blob: a7b7fbc5f21925dcad1b9a629d0c8b277704ec95 [file] [log] [blame]
Jonathan Hart0961fe82014-04-03 09:56:25 -07001package net.onrc.onos.apps.forwarding;
Jonathan Hart1caaa932013-11-04 15:28:28 -08002
Jonathan Hart41d1e912013-11-24 16:50:25 -08003import java.util.ArrayList;
Jonathan Harte93aed42013-12-05 18:39:50 -08004import java.util.Collection;
Jonathan Hartd33a6cf2013-12-10 14:29:08 -08005import java.util.HashMap;
Jonathan Hart1caaa932013-11-04 15:28:28 -08006import java.util.Iterator;
Jonathan Hart41d1e912013-11-24 16:50:25 -08007import java.util.List;
Jonathan Harte93aed42013-12-05 18:39:50 -08008import java.util.Map;
TeruU7feef8a2014-04-03 00:15:49 -07009import java.util.Map.Entry;
TeruU417fe022014-02-04 12:59:30 -080010import java.util.concurrent.Executors;
11import java.util.concurrent.ScheduledExecutorService;
12import java.util.concurrent.TimeUnit;
Jonathan Hart1caaa932013-11-04 15:28:28 -080013
Jonathan Harte93aed42013-12-05 18:39:50 -080014import net.floodlightcontroller.core.module.FloodlightModuleContext;
15import net.floodlightcontroller.core.module.IFloodlightModule;
16import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080017import net.floodlightcontroller.util.MACAddress;
Jonathan Hartf5bd2582014-04-09 17:43:41 -070018import net.onrc.onos.api.packet.IPacketListener;
19import net.onrc.onos.api.packet.IPacketService;
Jonathan Hart0961fe82014-04-03 09:56:25 -070020import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart6df90172014-04-03 10:13:11 -070021import net.onrc.onos.core.datagrid.IDatagridService;
Jonathan Hart6df90172014-04-03 10:13:11 -070022import net.onrc.onos.core.datagrid.IEventChannelListener;
Jonathan Hart23701d12014-04-03 10:45:48 -070023import net.onrc.onos.core.devicemanager.IOnosDeviceService;
Jonathan Hartaa380972014-04-03 10:24:46 -070024import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070025import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070026import net.onrc.onos.core.intent.IntentMap;
27import net.onrc.onos.core.intent.IntentOperation;
28import net.onrc.onos.core.intent.IntentOperationList;
29import net.onrc.onos.core.intent.PathIntent;
30import net.onrc.onos.core.intent.ShortestPathIntent;
Jonathan Hartaa380972014-04-03 10:24:46 -070031import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
32import net.onrc.onos.core.intent.runtime.IntentStateList;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070033import net.onrc.onos.core.packet.Ethernet;
34import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070035import net.onrc.onos.core.topology.Device;
36import net.onrc.onos.core.topology.INetworkGraphService;
37import net.onrc.onos.core.topology.LinkEvent;
38import net.onrc.onos.core.topology.NetworkGraph;
Jonathan Hartf5bd2582014-04-09 17:43:41 -070039import net.onrc.onos.core.topology.Port;
Jonathan Hart472062d2014-04-03 10:56:48 -070040import net.onrc.onos.core.topology.Switch;
Jonathan Hart23701d12014-04-03 10:45:48 -070041import net.onrc.onos.core.util.Dpid;
42import net.onrc.onos.core.util.FlowPath;
Jonathan Hart23701d12014-04-03 10:45:48 -070043import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080044
Jonathan Hart1caaa932013-11-04 15:28:28 -080045import org.openflow.util.HexString;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
Jonathan Hartd857ad62013-12-14 18:08:17 -080049import com.google.common.collect.LinkedListMultimap;
50import com.google.common.collect.ListMultimap;
Jonathan Hart5e448782013-12-10 12:36:35 -080051
Jonathan Hartf5bd2582014-04-09 17:43:41 -070052public class Forwarding implements /*IOFMessageListener,*/ IFloodlightModule,
53 IForwardingService, IEventChannelListener<Long, IntentStateList>,
54 IPacketListener {
Ray Milkeyec838942014-04-09 11:28:43 -070055 private static final Logger log = LoggerFactory.getLogger(Forwarding.class);
TeruU7feef8a2014-04-03 00:15:49 -070056
Ray Milkey2476cac2014-04-08 11:03:21 -070057 private static final int SLEEP_TIME_FOR_DB_DEVICE_INSTALLED = 100; // milliseconds
Ray Milkeyec838942014-04-09 11:28:43 -070058 private static final int NUMBER_OF_THREAD_FOR_EXECUTOR = 1;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070059
Ray Milkeyec838942014-04-09 11:28:43 -070060 private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(NUMBER_OF_THREAD_FOR_EXECUTOR);
Jonathan Harte93aed42013-12-05 18:39:50 -080061
Ray Milkey269ffb92014-04-03 14:43:30 -070062 private final String callerId = "Forwarding";
Jonathan Harte93aed42013-12-05 18:39:50 -080063
Ray Milkey269ffb92014-04-03 14:43:30 -070064 private IDatagridService datagrid;
Jonathan Hartf5bd2582014-04-09 17:43:41 -070065 private IPacketService packetService;
Ray Milkey269ffb92014-04-03 14:43:30 -070066 private IControllerRegistryService controllerRegistryService;
67
68 private INetworkGraphService networkGraphService;
69 private NetworkGraph networkGraph;
70 private IPathCalcRuntimeService pathRuntime;
71 private IntentMap intentMap;
72
73 // TODO it seems there is a Guava collection that will time out entries.
74 // We should see if this will work here.
75 private Map<Path, PushedFlow> pendingFlows;
76 private ListMultimap<String, PacketToPush> waitingPackets;
77
78 private final Object lock = new Object();
79
Jonathan Hart8ed69c52014-04-09 13:29:16 -070080 private static class PacketToPush {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070081 public final Ethernet eth;
Ray Milkey269ffb92014-04-03 14:43:30 -070082 public final long dpid;
83
Jonathan Hartf5bd2582014-04-09 17:43:41 -070084 public PacketToPush(Ethernet eth, long dpid) {
85 this.eth = eth;
Ray Milkey269ffb92014-04-03 14:43:30 -070086 this.dpid = dpid;
87 }
88 }
89
Jonathan Hart8ed69c52014-04-09 13:29:16 -070090 private static class PushedFlow {
Ray Milkey269ffb92014-04-03 14:43:30 -070091 public final String intentId;
92 public boolean installed = false;
93 public short firstOutPort;
94
95 public PushedFlow(String flowId) {
96 this.intentId = flowId;
97 }
98 }
99
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700100 private static final class Path {
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 public final MACAddress srcMac;
102 public final MACAddress dstMac;
103
104 public Path(MACAddress srcMac, MACAddress dstMac) {
105 this.srcMac = srcMac;
106 this.dstMac = dstMac;
107 }
108
109 @Override
110 public boolean equals(Object other) {
111 if (!(other instanceof Path)) {
112 return false;
113 }
114
115 Path otherPath = (Path) other;
116 return srcMac.equals(otherPath.srcMac) &&
117 dstMac.equals(otherPath.dstMac);
118 }
119
120 @Override
121 public int hashCode() {
122 int hash = 17;
123 hash = 31 * hash + srcMac.hashCode();
124 hash = 31 * hash + dstMac.hashCode();
125 return hash;
126 }
127
128 @Override
129 public String toString() {
130 return "(" + srcMac + ") => (" + dstMac + ")";
131 }
132 }
133
134 @Override
135 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
136 List<Class<? extends IFloodlightService>> services =
137 new ArrayList<Class<? extends IFloodlightService>>(1);
138 services.add(IForwardingService.class);
139 return services;
140 }
141
142 @Override
143 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
144 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
145 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
146 impls.put(IForwardingService.class, this);
147 return impls;
148 }
149
150 @Override
151 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
152 List<Class<? extends IFloodlightService>> dependencies =
153 new ArrayList<Class<? extends IFloodlightService>>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 dependencies.add(IControllerRegistryService.class);
155 dependencies.add(IOnosDeviceService.class);
156 dependencies.add(IDatagridService.class);
157 dependencies.add(INetworkGraphService.class);
158 dependencies.add(IPathCalcRuntimeService.class);
159 // We don't use the IProxyArpService directly, but reactive forwarding
160 // requires it to be loaded and answering ARP requests
161 dependencies.add(IProxyArpService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700162 dependencies.add(IPacketService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 return dependencies;
164 }
165
166 @Override
167 public void init(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 datagrid = context.getServiceImpl(IDatagridService.class);
169 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
170 networkGraphService = context.getServiceImpl(INetworkGraphService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700171 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700172 packetService = context.getServiceImpl(IPacketService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700173
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 pendingFlows = new HashMap<Path, PushedFlow>();
175 waitingPackets = LinkedListMultimap.create();
176 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800177
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 @Override
179 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700180 packetService.registerPacketListener(this);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800181
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 networkGraph = networkGraphService.getNetworkGraph();
183 intentMap = pathRuntime.getPathIntents();
184 datagrid.addListener("onos.pathintent_state", this, Long.class, IntentStateList.class);
185 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800186
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 @Override
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700188 public void receive(Switch sw, Port inPort, Ethernet eth) {
189 log.debug("Receive PACKET_IN swId {}, portId {}", sw.getDpid(), inPort.getNumber());
TeruU417fe022014-02-04 12:59:30 -0800190
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700191 if (eth.getEtherType() != Ethernet.TYPE_IPV4) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700192 // Only handle IPv4 packets right now
193 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 }
TeruU417fe022014-02-04 12:59:30 -0800195
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 if (eth.isBroadcast() || eth.isMulticast()) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700197 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 } else {
199 // Unicast
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700200 handlePacketIn(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700201 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 }
TeruU417fe022014-02-04 12:59:30 -0800203
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700204 private void handleBroadcast(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 if (log.isTraceEnabled()) {
206 log.trace("Sending broadcast packet to other ONOS instances");
207 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800208
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700209 packetService.broadcastPacket(eth,
210 new SwitchPort(sw.getDpid(), inPort.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 }
Pavlin Radoslavova3818db2014-03-20 19:26:08 -0700212
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700213 private void handlePacketIn(Switch sw, Port inPort, Ethernet eth) {
214 log.debug("Start handlePacketIn swId {}, portId {}", sw.getDpid(), inPort.getNumber());
TeruU7feef8a2014-04-03 00:15:49 -0700215
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 String destinationMac =
217 HexString.toHexString(eth.getDestinationMACAddress());
Jonathan Hart0444d932014-01-22 15:06:17 -0800218
Ray Milkey269ffb92014-04-03 14:43:30 -0700219 //FIXME getDeviceByMac() is a blocking call, so it may be better way to handle it to avoid the condition.
220 Device deviceObject = networkGraph.getDeviceByMac(MACAddress.valueOf(destinationMac));
TeruU6464af02014-02-06 21:38:45 -0800221
Ray Milkey269ffb92014-04-03 14:43:30 -0700222 if (deviceObject == null) {
223 log.debug("No device entry found for {}",
224 destinationMac);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800225
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 //Device is not in the DB, so wait it until the device is added.
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700227 EXECUTOR_SERVICE.schedule(new WaitDeviceArp(sw, inPort, eth), SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, TimeUnit.MILLISECONDS);
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 return;
229 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800230
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700231 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 }
TeruU417fe022014-02-04 12:59:30 -0800233
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 private class WaitDeviceArp implements Runnable {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700235 Switch sw;
236 Port inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 Ethernet eth;
TeruU417fe022014-02-04 12:59:30 -0800238
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700239 public WaitDeviceArp(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 super();
241 this.sw = sw;
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700242 this.inPort = inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 this.eth = eth;
244 }
TeruU417fe022014-02-04 12:59:30 -0800245
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 @Override
247 public void run() {
248 Device deviceObject = networkGraph.getDeviceByMac(MACAddress.valueOf(eth.getDestinationMACAddress()));
249 if (deviceObject == null) {
250 log.debug("wait {}ms and device was not found. Send broadcast packet and the thread finish.", SLEEP_TIME_FOR_DB_DEVICE_INSTALLED);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700251 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700252 return;
253 }
254 log.debug("wait {}ms and device {} was found, continue", SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700255 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 }
257 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800258
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700259 private void continueHandlePacketIn(Switch sw, Port inPort, Ethernet eth, Device deviceObject) {
TeruU7feef8a2014-04-03 00:15:49 -0700260
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 log.debug("Start continuehandlePacketIn");
TeruU7feef8a2014-04-03 00:15:49 -0700262
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 //Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
264 Iterator<net.onrc.onos.core.topology.Port> ports = deviceObject.getAttachmentPoints().iterator();
265 if (!ports.hasNext()) {
266 log.debug("No attachment point found for device {} - broadcasting packet",
267 deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700268 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700269 return;
270 }
TeruU7feef8a2014-04-03 00:15:49 -0700271
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 //This code assumes the device has only one port. It should be problem.
273 net.onrc.onos.core.topology.Port portObject = ports.next();
274 short destinationPort = portObject.getNumber().shortValue();
275 Switch switchObject = portObject.getSwitch();
276 long destinationDpid = switchObject.getDpid();
277
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700278 // TODO eliminate cast
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 SwitchPort srcSwitchPort = new SwitchPort(
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700280 new Dpid(sw.getDpid()),
281 new net.onrc.onos.core.util.Port((short) inPort.getNumber().longValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 SwitchPort dstSwitchPort = new SwitchPort(
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700283 new Dpid(destinationDpid),
284 new net.onrc.onos.core.util.Port(destinationPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700285
286 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
287 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
288
289 synchronized (lock) {
290 //TODO check concurrency
291 Path pathspec = new Path(srcMacAddress, dstMacAddress);
292 PushedFlow existingFlow = pendingFlows.get(pathspec);
293
294 //A path is installed side by side to reduce a path timeout and a wrong state.
295 if (existingFlow != null) {
296 // We've already start to install a flow for this pair of MAC addresses
297 if (log.isDebugEnabled()) {
298 log.debug("Found existing the same pathspec {}, intent ID is {}",
299 pathspec,
300 existingFlow.intentId);
301 }
302
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 // Find the correct port here. We just assume the PI is from
304 // the first hop switch, but this is definitely not always
305 // the case. We'll have to retrieve the flow from HZ every time
306 // because it could change (be rerouted) sometimes.
307 if (existingFlow.installed) {
308 // Flow has been sent to the switches so it is safe to
309 // send a packet out now
310
311 Intent intent = intentMap.getIntent(existingFlow.intentId);
312 PathIntent pathIntent = null;
313 if (intent instanceof PathIntent) {
314 pathIntent = (PathIntent) intent;
315 } else {
316 log.debug("Intent {} is not PathIntent. Return.", intent.getId());
317 return;
318 }
319
320 Boolean isflowEntryForThisSwitch = false;
321 net.onrc.onos.core.topology.Path path = pathIntent.getPath();
322
Ray Milkey7f1567c2014-04-08 13:53:32 -0700323 for (Iterator<LinkEvent> i = path.iterator(); i.hasNext();) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700324 LinkEvent le = (LinkEvent) i.next();
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700325 if (le.getSrc().dpid.equals(sw.getDpid())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 log.debug("src {} dst {}", le.getSrc(), le.getDst());
327 isflowEntryForThisSwitch = true;
328 break;
329 }
330 }
331
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700332 if (!isflowEntryForThisSwitch) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700333 // If we don't find a flow entry for that switch, then we're
334 // in the middle of a rerouting (or something's gone wrong).
335 // This packet will be dropped as a victim of the rerouting.
336 log.debug("Dropping packet on flow {} between {}-{}",
337 existingFlow.intentId,
338 srcMacAddress, dstMacAddress);
339 } else {
340 log.debug("Sending packet out from sw {}, outport{}", sw, existingFlow.firstOutPort);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700341
342 packetService.sendPacket(new SwitchPort(
343 sw.getDpid(), existingFlow.firstOutPort), eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 }
345 } else {
346 // Flow path has not yet been installed to switches so save the
347 // packet out for later
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700348 log.debug("Put a packet into the waiting list. flowId {}", existingFlow.intentId);
349 waitingPackets.put(existingFlow.intentId, new PacketToPush(eth, sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700350 }
351 return;
352 }
353
354 log.debug("Adding new flow between {} at {} and {} at {}",
355 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
356
357 String intentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
358 IntentOperationList operations = new IntentOperationList();
359 ShortestPathIntent intent = new ShortestPathIntent(intentId,
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700360 sw.getDpid(), inPort.getNumber(), srcMacAddress.toLong(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700361 destinationDpid, destinationPort, dstMacAddress.toLong());
362 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
363 operations.add(operator, intent);
364 pathRuntime.executeIntentOperations(operations);
365
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 // Add to waiting lists
367 pendingFlows.put(pathspec, new PushedFlow(intentId));
368 log.debug("Put a Path {} in the pending flow, intent ID {}", pathspec, intentId);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700369 waitingPackets.put(intentId, new PacketToPush(eth, sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700370 log.debug("Put a Packet in the wating list. related pathspec {}", pathspec);
371
372 }
373 }
374
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 @Override
376 public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
377 }
378
379 @Override
380 public void flowRemoved(FlowPath removedFlowPath) {
381 }
382
383 public void flowRemoved(PathIntent removedIntent) {
384 if (log.isTraceEnabled()) {
385 log.trace("Path {} was removed", removedIntent.getParentIntent().getId());
386 }
387
388 ShortestPathIntent spfIntent = (ShortestPathIntent) removedIntent.getParentIntent();
389 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
390 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
391 Path removedPath = new Path(srcMacAddress, dstMacAddress);
392
393 synchronized (lock) {
394 // There *shouldn't* be any packets queued if the flow has
395 // just been removed.
396 List<PacketToPush> packets = waitingPackets.removeAll(spfIntent.getId());
397 if (!packets.isEmpty()) {
398 log.warn("Removed flow {} has packets queued.", spfIntent.getId());
399 }
400 pendingFlows.remove(removedPath);
401 log.debug("Removed from the pendingFlow: Path {}, Flow ID {}", removedPath, spfIntent.getId());
402 }
403 }
404
405 private void flowInstalled(PathIntent installedPath) {
406 if (log.isTraceEnabled()) {
407 log.trace("Path {} was installed", installedPath.getParentIntent().getId());
408 }
409
410 ShortestPathIntent spfIntent = (ShortestPathIntent) installedPath.getParentIntent();
411 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
412 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
413 Path path = new Path(srcMacAddress, dstMacAddress);
414 log.debug("Path spec {}", path);
415
416 // TODO waiting packets should time out. We could request a path that
417 // can't be installed right now because of a network partition. The path
418 // may eventually be installed, but we may have received thousands of
419 // packets in the meantime and probably don't want to send very old packets.
420
421 List<PacketToPush> packets = null;
422 net.onrc.onos.core.topology.Path graphPath = installedPath.getPath();
423
TeruU220c45e2014-04-10 18:56:26 -0700424 short outPort;
425 if (graphPath.isEmpty()) {
426 outPort = (short) spfIntent.getDstPortNumber();
427 log.debug("Path is empty. Maybe devices on the same switch. outPort {}", outPort);
428 } else {
429 outPort = graphPath.get(0).getSrc().getNumber().shortValue();
430 log.debug("path{}, outPort {}", graphPath, outPort);
431 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700432
433 PushedFlow existingFlow = null;
434
435 synchronized (lock) {
436 existingFlow = pendingFlows.get(path);
437
438 if (existingFlow != null) {
439 existingFlow.installed = true;
440 existingFlow.firstOutPort = outPort;
441 } else {
442 log.debug("ExistingFlow {} is null", path);
443 return;
444 }
445
446 //Check both existing flow are installed status.
447 if (existingFlow.installed) {
448 packets = waitingPackets.removeAll(existingFlow.intentId);
449 if (log.isDebugEnabled()) {
450 log.debug("removed my packets {} to push from waitingPackets. outPort {} size {}",
451 existingFlow.intentId, existingFlow.firstOutPort, packets.size());
452 }
453 } else {
454 log.debug("Forward or reverse flows hasn't been pushed yet. return");
455 return;
456 }
457 }
458
459 for (PacketToPush packet : packets) {
460 log.debug("Start packetToPush to sw {}, outPort {}, path {}", packet.dpid, existingFlow.firstOutPort, path);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700461 packetService.sendPacket(new SwitchPort(
462 packet.dpid, existingFlow.firstOutPort), packet.eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700463 }
464 }
465
Ray Milkey269ffb92014-04-03 14:43:30 -0700466 @Override
467 public void entryAdded(IntentStateList value) {
468 entryUpdated(value);
Ray Milkey269ffb92014-04-03 14:43:30 -0700469 }
470
471 @Override
472 public void entryRemoved(IntentStateList value) {
473 //no-op
474 }
475
476 @Override
477 public void entryUpdated(IntentStateList value) {
478 for (Entry<String, IntentState> entry : value.entrySet()) {
479 log.debug("path intent key {}, value {}", entry.getKey(), entry.getValue());
480 PathIntent pathIntent = (PathIntent) intentMap.getIntent(entry.getKey());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700481 if (pathIntent == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700483 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700484
Ray Milkeyb29e6262014-04-09 16:02:14 -0700485 if (!(pathIntent.getParentIntent() instanceof ShortestPathIntent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700486 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700487 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700488
489 IntentState state = entry.getValue();
490 switch (state) {
491 case INST_REQ:
492 break;
493 case INST_ACK:
494 flowInstalled(pathIntent);
495 break;
496 case INST_NACK:
497 break;
498 case DEL_REQ:
499 break;
500 case DEL_ACK:
501 flowRemoved(pathIntent);
502 break;
503 case DEL_PENDING:
504 break;
505 default:
506 break;
507 }
508 }
509 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800510}