blob: c4d83d2e9a8349a63157187adb051b8ff2f57f39 [file] [log] [blame]
Jonathan Hartaa380972014-04-03 10:24:46 -07001package net.onrc.onos.core.intent.runtime;
Brian O'Connor12861f72014-02-19 20:40:32 -08002
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.List;
6import java.util.Map;
7import java.util.Set;
8import java.util.concurrent.BlockingQueue;
TeruU9e530662014-05-18 11:49:37 -07009import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.ConcurrentMap;
Brian O'Connor12861f72014-02-19 20:40:32 -080011import java.util.concurrent.LinkedBlockingQueue;
12
TeruU9e530662014-05-18 11:49:37 -070013import net.floodlightcontroller.core.FloodlightContext;
Brian O'Connor12861f72014-02-19 20:40:32 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
TeruU9e530662014-05-18 11:49:37 -070015import net.floodlightcontroller.core.IOFMessageListener;
16import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connor12861f72014-02-19 20:40:32 -080017import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart6df90172014-04-03 10:13:11 -070021import net.onrc.onos.core.datagrid.IDatagridService;
22import net.onrc.onos.core.datagrid.IEventChannel;
23import net.onrc.onos.core.datagrid.IEventChannelListener;
Jonathan Hart23701d12014-04-03 10:45:48 -070024import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Jonathan Hartaa380972014-04-03 10:24:46 -070025import net.onrc.onos.core.intent.FlowEntry;
TeruU9e530662014-05-18 11:49:37 -070026import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070027import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070028import net.onrc.onos.core.intent.IntentOperation;
29import net.onrc.onos.core.intent.IntentOperationList;
TeruU9e530662014-05-18 11:49:37 -070030import net.onrc.onos.core.intent.PathIntent;
31import net.onrc.onos.core.intent.ShortestPathIntent;
Jonathan Harte37e4e22014-05-13 19:12:02 -070032import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart472062d2014-04-03 10:56:48 -070033
TeruU9e530662014-05-18 11:49:37 -070034import org.openflow.protocol.OFFlowRemoved;
35import org.openflow.protocol.OFMessage;
36import org.openflow.protocol.OFType;
Brian O'Connor5e73c012014-02-20 14:54:34 -080037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
TeruU9e530662014-05-18 11:49:37 -070040public class PlanInstallModule implements IFloodlightModule, IOFMessageListener {
Brian O'Connor12861f72014-02-19 20:40:32 -080041 protected volatile IFloodlightProviderService floodlightProvider;
Jonathan Harte37e4e22014-05-13 19:12:02 -070042 protected volatile ITopologyService topologyService;
Brian O'Connor12861f72014-02-19 20:40:32 -080043 protected volatile IDatagridService datagridService;
44 protected volatile IFlowPusherService flowPusher;
45 private PlanCalcRuntime planCalc;
46 private PlanInstallRuntime planInstall;
47 private EventListener eventListener;
Brian O'Connor488e5ed2014-02-20 19:50:01 -080048 private IEventChannel<Long, IntentStateList> intentStateChannel;
Ray Milkeyec838942014-04-09 11:28:43 -070049 private static final Logger log = LoggerFactory.getLogger(PlanInstallModule.class);
Brian O'Connor9b712f62014-02-20 14:22:20 -080050
Brian O'Connor12861f72014-02-19 20:40:32 -080051 private static final String PATH_INTENT_CHANNEL_NAME = "onos.pathintent";
Brian O'Connor488e5ed2014-02-20 19:50:01 -080052 private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
TeruU9e530662014-05-18 11:49:37 -070053 private ConcurrentMap<String, Intent> parentIntentMap = new ConcurrentHashMap<String, Intent>();
Brian O'Connor12861f72014-02-19 20:40:32 -080054
55 class EventListener extends Thread
Ray Milkey269ffb92014-04-03 14:43:30 -070056 implements IEventChannelListener<Long, IntentOperationList> {
Toshio Koide3a52ef32014-02-28 12:10:26 -080057
Ray Milkey269ffb92014-04-03 14:43:30 -070058 private BlockingQueue<IntentOperationList> intentQueue = new LinkedBlockingQueue<>();
59 private Long key = Long.valueOf(0);
Toshio Koide3a52ef32014-02-28 12:10:26 -080060
Ray Milkey269ffb92014-04-03 14:43:30 -070061 @Override
62 public void run() {
63 while (true) {
64 try {
65 IntentOperationList intents = intentQueue.take();
66 //TODO: consider draining the remaining intent lists
67 // and processing in one big batch
68// List<IntentOperationList> remaining = new LinkedList<>();
69// intentQueue.drainTo(remaining);
Toshio Koide3a52ef32014-02-28 12:10:26 -080070
Ray Milkey269ffb92014-04-03 14:43:30 -070071 processIntents(intents);
72 } catch (InterruptedException e) {
73 log.warn("Error taking from intent queue: {}", e.getMessage());
74 }
75 }
76 }
Toshio Koide3a52ef32014-02-28 12:10:26 -080077
Ray Milkey269ffb92014-04-03 14:43:30 -070078 private void processIntents(IntentOperationList intents) {
79 log("start_processIntents");
80 log.debug("Processing OperationList {}", intents);
81 log("begin_computePlan");
82 List<Set<FlowEntry>> plan = planCalc.computePlan(intents);
83 log("end_computePlan");
84 log.debug("Plan: {}", plan);
85 log("begin_installPlan");
86 boolean success = planInstall.installPlan(plan);
87 log("end_installPlan");
TeruUf9111652014-05-14 23:10:35 -070088 Set<Long> domainSwitchDpids = floodlightProvider.getSwitches().keySet();
Ray Milkey269ffb92014-04-03 14:43:30 -070089 log("begin_sendInstallNotif");
TeruUf9111652014-05-14 23:10:35 -070090 sendNotifications(intents, true, success, domainSwitchDpids);
Ray Milkey269ffb92014-04-03 14:43:30 -070091 log("end_sendInstallNotif");
92 log("finish");
93 }
Toshio Koide3a52ef32014-02-28 12:10:26 -080094
TeruUf9111652014-05-14 23:10:35 -070095 /***
96 * This function is for sending intent state notification to other ONOS instances.
97 * The argument of "domainSwitchDpids" is required for dispatching this ONOS's managed switches.
98 * @param intents
99 * @param installed
100 * @param success
101 * @param domainSwitchDpids
102 */
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700103 private void sendNotifications(IntentOperationList intents,
104 boolean installed, boolean success, Set<Long> domainSwitchDpids) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 IntentStateList states = new IntentStateList();
106 for (IntentOperation i : intents) {
107 IntentState newState;
108 switch (i.operator) {
109 case REMOVE:
110 if (installed) {
111 newState = success ? IntentState.DEL_ACK : IntentState.DEL_PENDING;
112 } else {
113 newState = IntentState.DEL_REQ;
114 }
115 break;
116 case ADD:
117 default:
118 if (installed) {
TeruUf9111652014-05-14 23:10:35 -0700119 if (domainSwitchDpids != null) {
120 states.domainSwitchDpids.addAll(domainSwitchDpids);
121 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700122 newState = success ? IntentState.INST_ACK : IntentState.INST_NACK;
123 } else {
124 newState = IntentState.INST_REQ;
125 }
126 break;
127 }
128 states.put(i.intent.getId(), newState);
129 }
TeruUf9111652014-05-14 23:10:35 -0700130
131 if (log.isTraceEnabled()) {
TeruU9e530662014-05-18 11:49:37 -0700132 log.trace("sendNotifications, states {}, domainSwitchDpids {}",
133 states, states.domainSwitchDpids);
TeruUf9111652014-05-14 23:10:35 -0700134 }
135
136 intentStateChannel.addTransientEntry(key, states);
Ray Milkey269ffb92014-04-03 14:43:30 -0700137 // XXX: Send notifications using the same key every time
138 // and receive them by entryAdded() and entryUpdated()
139 // key += 1;
140 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800141
Ray Milkey269ffb92014-04-03 14:43:30 -0700142 @Override
143 public void entryAdded(IntentOperationList value) {
144 entryUpdated(value);
145 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800146
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 @Override
148 public void entryRemoved(IntentOperationList value) {
149 // This channel is a queue, so this method is not needed
150 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800151
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 @Override
153 public void entryUpdated(IntentOperationList value) {
TeruU9e530662014-05-18 11:49:37 -0700154 putIntentOpsInfoInParentMap(value);
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 log("start_intentNotifRecv");
156 log("begin_sendReceivedNotif");
TeruUf9111652014-05-14 23:10:35 -0700157 sendNotifications(value, false, false, null);
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 log("end_sendReceivedNotif");
159 log("finish");
Brian O'Connor85dd8f22014-02-25 11:43:07 -0800160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 log.debug("Added OperationList {}", value);
162 try {
163 intentQueue.put(value);
164 } catch (InterruptedException e) {
165 log.warn("Error putting to intent queue: {}", e.getMessage());
166 }
167 }
TeruU9e530662014-05-18 11:49:37 -0700168
169 private void putIntentOpsInfoInParentMap(IntentOperationList intentOps) {
170 for (IntentOperation i : intentOps) {
171 if (!(i.intent instanceof PathIntent)) {
172 log.warn("Not a path intent: {}", i);
173 continue;
174 }
175 PathIntent intent = (PathIntent) i.intent;
176 Intent parent = intent.getParentIntent();
177 if (parent instanceof ShortestPathIntent) {
178 parentIntentMap.put(parent.getId(), parent);
179 } else {
180 log.warn("Unsupported Intent: {}", parent);
181 continue;
182 }
183 }
184 }
Brian O'Connor12861f72014-02-19 20:40:32 -0800185 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800186
Brian O'Connor85dd8f22014-02-25 11:43:07 -0800187 public static void log(String step) {
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700188 log.debug("Time:{}, Step:{}", System.nanoTime(), step);
Brian O'Connor85dd8f22014-02-25 11:43:07 -0800189 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800190
Brian O'Connor12861f72014-02-19 20:40:32 -0800191 @Override
TeruU9e530662014-05-18 11:49:37 -0700192 public void init(FloodlightModuleContext context)
193 throws FloodlightModuleException {
194 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
195 topologyService = context.getServiceImpl(ITopologyService.class);
196 datagridService = context.getServiceImpl(IDatagridService.class);
197 flowPusher = context.getServiceImpl(IFlowPusherService.class);
198 planCalc = new PlanCalcRuntime();
199 planInstall = new PlanInstallRuntime(floodlightProvider, flowPusher);
200 eventListener = new EventListener();
201 }
202
203 @Override
Brian O'Connor12861f72014-02-19 20:40:32 -0800204 public void startUp(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 // start subscriber
206 datagridService.addListener(PATH_INTENT_CHANNEL_NAME,
207 eventListener,
208 Long.class,
209 IntentOperationList.class);
210 eventListener.start();
211 // start publisher
212 intentStateChannel = datagridService.createChannel(INTENT_STATE_EVENT_CHANNEL_NAME,
213 Long.class,
214 IntentStateList.class);
TeruU9e530662014-05-18 11:49:37 -0700215 floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
Brian O'Connor12861f72014-02-19 20:40:32 -0800216 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800217
Brian O'Connor12861f72014-02-19 20:40:32 -0800218 @Override
219 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 Collection<Class<? extends IFloodlightService>> l =
221 new ArrayList<Class<? extends IFloodlightService>>();
222 l.add(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700223 l.add(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 l.add(IDatagridService.class);
225 l.add(IFlowPusherService.class);
226 return l;
Brian O'Connor12861f72014-02-19 20:40:32 -0800227 }
Toshio Koide3a52ef32014-02-28 12:10:26 -0800228
Brian O'Connor12861f72014-02-19 20:40:32 -0800229 @Override
230 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700231 // no services, for now
232 return null;
Brian O'Connor12861f72014-02-19 20:40:32 -0800233 }
234
235 @Override
236 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 // no services, for now
238 return null;
Brian O'Connor12861f72014-02-19 20:40:32 -0800239 }
TeruU9e530662014-05-18 11:49:37 -0700240
241 @Override
242 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
243 if (msg.getType().equals(OFType.FLOW_REMOVED) &&
244 (msg instanceof OFFlowRemoved)) {
245 OFFlowRemoved flowRemovedMsg = (OFFlowRemoved) msg;
246
247 if (log.isTraceEnabled()) {
248 log.trace("Receive flowRemoved from sw {} : Cookie {}",
249 sw.getId(), flowRemovedMsg.getCookie());
250 }
251
252 String intentParentId = Long.toString(flowRemovedMsg.getCookie());
253 Intent intent = parentIntentMap.get(intentParentId);
254
255 //We assume if the path src sw flow entry is expired,
256 //the path is expired.
257 if (!isFlowSrcRemoved(sw.getId(), intentParentId)) {
258 return Command.CONTINUE;
259 }
260
261 ShortestPathIntent spfIntent = null;
262 if (!(intent instanceof ShortestPathIntent)) {
263 return Command.CONTINUE;
264 }
265 spfIntent = (ShortestPathIntent) intent;
266 String pathIntentId = spfIntent.getPathIntentId();
267
268 IntentStateList states = new IntentStateList();
269 IntentState newState = IntentState.DEL_ACK;
270 states.put(pathIntentId, newState);
271 Set<Long> domainSwitchDpids = floodlightProvider.getSwitches().keySet();
272 if (domainSwitchDpids != null) {
273 states.domainSwitchDpids.addAll(domainSwitchDpids);
274 }
275 parentIntentMap.remove(intentParentId);
276 log.debug("addEntry to intentStateChannel intentId {}, states {}", flowRemovedMsg.getCookie(), states);
277
278 intentStateChannel.addTransientEntry(flowRemovedMsg.getCookie(), states);
279 }
280
281 return Command.CONTINUE;
282 }
283
284 private boolean isFlowSrcRemoved(long dpid, String shortestPathIntentId) {
285 Intent intent = parentIntentMap.get(shortestPathIntentId);
286 ShortestPathIntent spfIntent = null;
287 if (intent instanceof ShortestPathIntent) {
288 spfIntent = (ShortestPathIntent) intent;
289 }
290
291 if (spfIntent == null) {
292 return false;
293 }
294
295 long srcSwDpid = spfIntent.getSrcSwitchDpid();
296 if (srcSwDpid == dpid) {
297 return true;
298 }
299
300 return false;
301 }
302
303 @Override
304 public String getName() {
305 // TODO Auto-generated method stub
306 return null;
307 }
308
309 @Override
310 public boolean isCallbackOrderingPrereq(OFType type, String name) {
311 // TODO Auto-generated method stub
312 return false;
313 }
314
315 @Override
316 public boolean isCallbackOrderingPostreq(OFType type, String name) {
317 // TODO Auto-generated method stub
318 return false;
319 }
Brian O'Connor12861f72014-02-19 20:40:32 -0800320}