blob: f942fa8842ff87d6297956a6cee472b2ff9ff526 [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'Connor6dc44e92014-02-24 21:23:46 -080019import org.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'Connora15fb862014-06-12 23:38:54 -070024 * This class is responsible for installing plans (lists of sets of FlowEntries) into local switches.
25 * In this context, a local switch is a switch for which this ONOS instance is the master.
26 * It also is responsible for sending barrier messages between sets.
Brian O'Connor67c6e662014-02-17 15:20:44 -080027 */
28
Brian O'Connor12861f72014-02-19 20:40:32 -080029public class PlanInstallRuntime {
Brian O'Connora15fb862014-06-12 23:38:54 -070030
Brian O'Connor67c6e662014-02-17 15:20:44 -080031 IFlowPusherService pusher;
32 IFloodlightProviderService provider;
Ray Milkeyec838942014-04-09 11:28:43 -070033 private static final Logger log = LoggerFactory.getLogger(PlanInstallRuntime.class);
Brian O'Connor67c6e662014-02-17 15:20:44 -080034
Brian O'Connora15fb862014-06-12 23:38:54 -070035 /**
36 * Constructor.
37 *
38 * @param provider the FloodlightProviderService for list of local switches
39 * @param pusher the FlowPusherService to use for FlowEntry installation
40 */
41 public PlanInstallRuntime(IFloodlightProviderService provider,
Ray Milkey269ffb92014-04-03 14:43:30 -070042 IFlowPusherService pusher) {
Ray Milkey269ffb92014-04-03 14:43:30 -070043 this.provider = provider;
44 this.pusher = pusher;
Brian O'Connor67c6e662014-02-17 15:20:44 -080045 }
Ray Milkey269ffb92014-04-03 14:43:30 -070046
Brian O'Connora15fb862014-06-12 23:38:54 -070047 /**
48 * This class is a temporary class for collecting FlowMod installation information. It is
49 * largely used for debugging purposes, and it should not be depended on for other purposes.
50 * <p>
51 * TODO: This class should be wrapped into a more generic debugging framework when available.
52 */
Brian O'Connor2fab2f62014-02-26 12:40:01 -080053 private static class FlowModCount {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070054 WeakReference<IOFSwitch> sw;
Ray Milkey269ffb92014-04-03 14:43:30 -070055 long modFlows = 0;
56 long delFlows = 0;
57 long errors = 0;
58
Brian O'Connora15fb862014-06-12 23:38:54 -070059 /**
60 * Constructor.
61 *
62 * @param sw the switch for FlowMod statistics collection
63 */
Ray Milkey269ffb92014-04-03 14:43:30 -070064 FlowModCount(IOFSwitch sw) {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070065 this.sw = new WeakReference<>(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -070066 }
67
Brian O'Connora15fb862014-06-12 23:38:54 -070068 /**
69 * Include the FlowEntry in this switch statistics object.
70 *
71 * @param entry the FlowEntry to count
72 */
Ray Milkey269ffb92014-04-03 14:43:30 -070073 void addFlowEntry(FlowEntry entry) {
74 switch (entry.getOperator()) {
75 case ADD:
76 modFlows++;
77 break;
78 case ERROR:
79 errors++;
80 break;
81 case REMOVE:
82 delFlows++;
83 break;
84 default:
85 break;
86 }
87 }
88
Brian O'Connora15fb862014-06-12 23:38:54 -070089 /**
90 * Returns a string representation of this object.
91 *
92 * @return string representation of this object
93 */
TeruUf9111652014-05-14 23:10:35 -070094 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -070095 public String toString() {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070096 final IOFSwitch swTemp = sw.get();
97 return "sw:" + ((swTemp == null) ? "disconnected" : swTemp.getStringId())
98 + ": modify " + modFlows + " delete " + delFlows + " error " + errors;
Ray Milkey269ffb92014-04-03 14:43:30 -070099 }
100
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -0700101 static Map<IOFSwitch, FlowModCount> map = new WeakHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700102
Brian O'Connora15fb862014-06-12 23:38:54 -0700103 /**
104 * This function is used for collecting statistics information. It should be called for
105 * every FlowEntry that is pushed to the switch for accurate statistics.
106 * <p>
107 * This class maintains a map of Switches and FlowModCount collection objects, which
108 * are used for collection.
109 * <p>
110 * TODO: This should be refactored to use a more generic mechanism when available.
111 *
112 * @param sw the switch that entry is being pushed to
113 * @param entry the FlowEntry being pushed
114 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700115 static void countFlowEntry(IOFSwitch sw, FlowEntry entry) {
116 FlowModCount count = map.get(sw);
117 if (count == null) {
118 count = new FlowModCount(sw);
119 map.put(sw, count);
120 }
121 count.addFlowEntry(entry);
122 }
123
Brian O'Connora15fb862014-06-12 23:38:54 -0700124 /**
125 * Reset the statistics collection. It should be called when required for debugging.
126 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700127 static void startCount() {
128 map.clear();
129 }
130
Brian O'Connora15fb862014-06-12 23:38:54 -0700131 /**
132 * Print out the statistics information when required for debugging.
133 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 static void printCount() {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700135 StringBuilder result = new StringBuilder();
136
137 result.append("FLOWMOD COUNT:\n");
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 for (FlowModCount count : map.values()) {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700139 result.append(count.toString() + '\n');
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 }
141 if (map.values().isEmpty()) {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700142 result.append("No flow mods installed\n");
Ray Milkey269ffb92014-04-03 14:43:30 -0700143 }
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700144 log.debug(result.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 }
Brian O'Connor2fab2f62014-02-26 12:40:01 -0800146 }
Brian O'Connor67c6e662014-02-17 15:20:44 -0800147
Brian O'Connora15fb862014-06-12 23:38:54 -0700148 /**
149 * This function should be called to install the FlowEntries in the plan.
150 * <p>
151 * Each set of FlowEntries can be installed together, but all entries should be installed
152 * proceeded to the next set.
153 * <p>
154 * TODO: This method lack coordination between the other ONOS instances before proceeded
155 * with the next set of entries
156 *
157 * @param plan list of set of FlowEntries for installation on local switches
158 * @return true (we assume installation is successful)
159 */
Brian O'Connor488e5ed2014-02-20 19:50:01 -0800160 public boolean installPlan(List<Set<FlowEntry>> plan) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 long start = System.nanoTime();
162 Map<Long, IOFSwitch> switches = provider.getSwitches();
Brian O'Connor2fab2f62014-02-26 12:40:01 -0800163
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 log.debug("IOFSwitches: {}", switches);
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 FlowModCount.startCount();
166 for (Set<FlowEntry> phase : plan) {
167 Set<Pair<IOFSwitch, net.onrc.onos.core.util.FlowEntry>> entries = new HashSet<>();
168 Set<IOFSwitch> modifiedSwitches = new HashSet<>();
169
170 long step1 = System.nanoTime();
171 // convert flow entries and create pairs
172 for (FlowEntry entry : phase) {
173 IOFSwitch sw = switches.get(entry.getSwitch());
174 if (sw == null) {
175 // no active switch, skip this flow entry
176 log.debug("Skipping flow entry: {}", entry);
177 continue;
178 }
179 entries.add(new Pair<>(sw, entry.getFlowEntry()));
180 modifiedSwitches.add(sw);
181 FlowModCount.countFlowEntry(sw, entry);
182 }
183 long step2 = System.nanoTime();
184
185 // push flow entries to switches
186 log.debug("Pushing flow entries: {}", entries);
187 pusher.pushFlowEntries(entries);
188 long step3 = System.nanoTime();
189
Brian O'Connora15fb862014-06-12 23:38:54 -0700190 // insert a barrier after each phase on each modifiedSwitch
191 // wait for confirmation messages before proceeding
Ray Milkey269ffb92014-04-03 14:43:30 -0700192 List<Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>>> barriers = new ArrayList<>();
193 for (IOFSwitch sw : modifiedSwitches) {
194 barriers.add(new Pair<>(sw, pusher.barrierAsync(sw)));
195 }
196 for (Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>> pair : barriers) {
Sho SHIMIZU26d77892014-06-10 11:07:06 -0700197 IOFSwitch sw = pair.getFirst();
198 OFMessageFuture<OFBarrierReply> future = pair.getSecond();
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 try {
200 future.get();
201 } catch (InterruptedException | ExecutionException e) {
202 log.error("Barrier message not received for sw: {}", sw);
203 }
204 }
205 long step4 = System.nanoTime();
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700206 log.debug("MEASUREMENT: convert: {} ns, push: {} ns, barrierWait: {} ns",
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 step2 - step1, step3 - step2, step4 - step3);
208
209 }
210 long end = System.nanoTime();
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700211 log.debug("MEASUREMENT: Install plan: {} ns", (end - start));
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 FlowModCount.printCount();
213
214 // TODO: we assume that the plan installation succeeds for now
215 return true;
Brian O'Connor67c6e662014-02-17 15:20:44 -0800216 }
Brian O'Connor67c6e662014-02-17 15:20:44 -0800217}