blob: 8d376116dd91cd791017686ecb77607c19a0f586 [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;
TeruUf9111652014-05-14 23:10:35 -07007import java.util.LinkedList;
Jonathan Hart41d1e912013-11-24 16:50:25 -08008import java.util.List;
Jonathan Harte93aed42013-12-05 18:39:50 -08009import java.util.Map;
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 Hart23701d12014-04-03 10:45:48 -070021import net.onrc.onos.core.devicemanager.IOnosDeviceService;
Jonathan Hartaa380972014-04-03 10:24:46 -070022import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070023import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070024import net.onrc.onos.core.intent.IntentMap;
TeruUf9111652014-05-14 23:10:35 -070025import net.onrc.onos.core.intent.IntentMap.ChangedEvent;
26import net.onrc.onos.core.intent.IntentMap.ChangedListener;
Jonathan Hartaa380972014-04-03 10:24:46 -070027import 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;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070032import net.onrc.onos.core.packet.Ethernet;
33import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070034import net.onrc.onos.core.topology.Device;
Jonathan Harte37e4e22014-05-13 19:12:02 -070035import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart472062d2014-04-03 10:56:48 -070036import net.onrc.onos.core.topology.LinkEvent;
Jonathan Hartf5bd2582014-04-09 17:43:41 -070037import net.onrc.onos.core.topology.Port;
Jonathan Hart472062d2014-04-03 10:56:48 -070038import net.onrc.onos.core.topology.Switch;
TeruUf9111652014-05-14 23:10:35 -070039import net.onrc.onos.core.topology.Topology;
Jonathan Hart23701d12014-04-03 10:45:48 -070040import net.onrc.onos.core.util.Dpid;
41import net.onrc.onos.core.util.FlowPath;
Jonathan Hart23701d12014-04-03 10:45:48 -070042import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080043
Jonathan Hart1caaa932013-11-04 15:28:28 -080044import org.openflow.util.HexString;
45import org.slf4j.Logger;
46import org.slf4j.LoggerFactory;
47
Jonathan Hartd857ad62013-12-14 18:08:17 -080048import com.google.common.collect.LinkedListMultimap;
49import com.google.common.collect.ListMultimap;
Jonathan Hart5e448782013-12-10 12:36:35 -080050
Jonathan Hartf5bd2582014-04-09 17:43:41 -070051public class Forwarding implements /*IOFMessageListener,*/ IFloodlightModule,
TeruUf9111652014-05-14 23:10:35 -070052 IForwardingService, IPacketListener, ChangedListener {
Ray Milkeyec838942014-04-09 11:28:43 -070053 private static final Logger log = LoggerFactory.getLogger(Forwarding.class);
TeruU7feef8a2014-04-03 00:15:49 -070054
Ray Milkey2476cac2014-04-08 11:03:21 -070055 private static final int SLEEP_TIME_FOR_DB_DEVICE_INSTALLED = 100; // milliseconds
Ray Milkeyec838942014-04-09 11:28:43 -070056 private static final int NUMBER_OF_THREAD_FOR_EXECUTOR = 1;
TeruU30c0c932014-05-15 16:47:41 -070057 private static final int SRC_SWITCH_TIMEOUT_ADJUST_SECOND = 2;
58 private static final int DEFAULT_IDLE_TIMEOUT = 5;
59 private int idleTimeout = DEFAULT_IDLE_TIMEOUT;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070060
Jonathan Hartc00f5c22014-06-10 15:14:40 -070061 private static final ScheduledExecutorService EXECUTOR_SERVICE =
62 Executors.newScheduledThreadPool(NUMBER_OF_THREAD_FOR_EXECUTOR);
Jonathan Harte93aed42013-12-05 18:39:50 -080063
Ray Milkey269ffb92014-04-03 14:43:30 -070064 private final String callerId = "Forwarding";
Jonathan Harte93aed42013-12-05 18:39:50 -080065
Jonathan Hartf5bd2582014-04-09 17:43:41 -070066 private IPacketService packetService;
Ray Milkey269ffb92014-04-03 14:43:30 -070067 private IControllerRegistryService controllerRegistryService;
68
Jonathan Harte37e4e22014-05-13 19:12:02 -070069 private ITopologyService topologyService;
70 private Topology topology;
Ray Milkey269ffb92014-04-03 14:43:30 -070071 private IPathCalcRuntimeService pathRuntime;
TeruU9e530662014-05-18 11:49:37 -070072 private IntentMap pathIntentMap;
73 private IntentMap highLevelIntentMap;
Ray Milkey269ffb92014-04-03 14:43:30 -070074
75 // TODO it seems there is a Guava collection that will time out entries.
76 // We should see if this will work here.
77 private Map<Path, PushedFlow> pendingFlows;
78 private ListMultimap<String, PacketToPush> waitingPackets;
79
80 private final Object lock = new Object();
81
Jonathan Hart8ed69c52014-04-09 13:29:16 -070082 private static class PacketToPush {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070083 public final Ethernet eth;
Ray Milkey269ffb92014-04-03 14:43:30 -070084 public final long dpid;
85
Jonathan Hartf5bd2582014-04-09 17:43:41 -070086 public PacketToPush(Ethernet eth, long dpid) {
87 this.eth = eth;
Ray Milkey269ffb92014-04-03 14:43:30 -070088 this.dpid = dpid;
89 }
90 }
91
Jonathan Hart8ed69c52014-04-09 13:29:16 -070092 private static class PushedFlow {
Ray Milkey269ffb92014-04-03 14:43:30 -070093 public final String intentId;
94 public boolean installed = false;
95 public short firstOutPort;
96
97 public PushedFlow(String flowId) {
98 this.intentId = flowId;
99 }
100 }
101
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700102 private static final class Path {
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 public final MACAddress srcMac;
104 public final MACAddress dstMac;
105
106 public Path(MACAddress srcMac, MACAddress dstMac) {
107 this.srcMac = srcMac;
108 this.dstMac = dstMac;
109 }
110
111 @Override
112 public boolean equals(Object other) {
113 if (!(other instanceof Path)) {
114 return false;
115 }
116
117 Path otherPath = (Path) other;
118 return srcMac.equals(otherPath.srcMac) &&
119 dstMac.equals(otherPath.dstMac);
120 }
121
122 @Override
123 public int hashCode() {
124 int hash = 17;
125 hash = 31 * hash + srcMac.hashCode();
126 hash = 31 * hash + dstMac.hashCode();
127 return hash;
128 }
129
130 @Override
131 public String toString() {
132 return "(" + srcMac + ") => (" + dstMac + ")";
133 }
134 }
135
136 @Override
137 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
138 List<Class<? extends IFloodlightService>> services =
139 new ArrayList<Class<? extends IFloodlightService>>(1);
140 services.add(IForwardingService.class);
141 return services;
142 }
143
144 @Override
145 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
146 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
147 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
148 impls.put(IForwardingService.class, this);
149 return impls;
150 }
151
152 @Override
153 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
154 List<Class<? extends IFloodlightService>> dependencies =
155 new ArrayList<Class<? extends IFloodlightService>>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 dependencies.add(IControllerRegistryService.class);
157 dependencies.add(IOnosDeviceService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700158 dependencies.add(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 dependencies.add(IPathCalcRuntimeService.class);
160 // We don't use the IProxyArpService directly, but reactive forwarding
161 // requires it to be loaded and answering ARP requests
162 dependencies.add(IProxyArpService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700163 dependencies.add(IPacketService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 return dependencies;
165 }
166
167 @Override
168 public void init(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700170 topologyService = context.getServiceImpl(ITopologyService.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) {
TeruU30c0c932014-05-15 16:47:41 -0700180 Map<String, String> configOptions = context.getConfigParams(this);
181
182 try {
183 if (Integer.parseInt(configOptions.get("idletimeout")) > 0) {
184 idleTimeout = Integer.parseInt(configOptions.get("idletimeout"));
185 log.info("idle_timeout for Forwarding is set to {}.", idleTimeout);
186 } else {
187 log.info("idle_timeout for Forwarding is less than 0. Use default {}.", idleTimeout);
188 }
189 } catch (NumberFormatException e) {
190 log.info("idle_timeout related config options were not set. Use default.");
191 }
192
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700193 packetService.registerPacketListener(this);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800194
Jonathan Harte37e4e22014-05-13 19:12:02 -0700195 topology = topologyService.getTopology();
TeruU9e530662014-05-18 11:49:37 -0700196 highLevelIntentMap = pathRuntime.getHighLevelIntents();
197 pathIntentMap = pathRuntime.getPathIntents();
198 pathIntentMap.addChangeListener(this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800200
Ray Milkey269ffb92014-04-03 14:43:30 -0700201 @Override
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700202 public void receive(Switch sw, Port inPort, Ethernet eth) {
TeruUf9111652014-05-14 23:10:35 -0700203 if (log.isTraceEnabled()) {
204 log.trace("Receive PACKET_IN swId {}, portId {}", sw.getDpid(), inPort.getNumber());
205 }
TeruU417fe022014-02-04 12:59:30 -0800206
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700207 if (eth.getEtherType() != Ethernet.TYPE_IPV4) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700208 // Only handle IPv4 packets right now
209 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700210 }
TeruU417fe022014-02-04 12:59:30 -0800211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 if (eth.isBroadcast() || eth.isMulticast()) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700213 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700214 } else {
215 // Unicast
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700216 handlePacketIn(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700217 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 }
TeruU417fe022014-02-04 12:59:30 -0800219
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700220 private void handleBroadcast(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 if (log.isTraceEnabled()) {
222 log.trace("Sending broadcast packet to other ONOS instances");
223 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800224
Jonathan Harte3702f22014-04-29 02:56:56 -0700225 packetService.broadcastPacketOutEdge(eth,
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700226 new SwitchPort(sw.getDpid(), inPort.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 }
Pavlin Radoslavova3818db2014-03-20 19:26:08 -0700228
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700229 private void handlePacketIn(Switch sw, Port inPort, Ethernet eth) {
TeruUf9111652014-05-14 23:10:35 -0700230 if (log.isTraceEnabled()) {
231 log.trace("Start handlePacketIn swId {}, portId {}", sw.getDpid(), inPort.getNumber());
232 }
TeruU7feef8a2014-04-03 00:15:49 -0700233
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 String destinationMac =
235 HexString.toHexString(eth.getDestinationMACAddress());
Jonathan Hart0444d932014-01-22 15:06:17 -0800236
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700237 // FIXME getDeviceByMac() is a blocking call, so it may be better way
238 // to handle it to avoid the condition.
239 Device deviceObject = topology.getDeviceByMac(
240 MACAddress.valueOf(destinationMac));
TeruU6464af02014-02-06 21:38:45 -0800241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 if (deviceObject == null) {
243 log.debug("No device entry found for {}",
244 destinationMac);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800245
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 //Device is not in the DB, so wait it until the device is added.
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700247 EXECUTOR_SERVICE.schedule(new WaitDeviceArp(sw, inPort, eth),
248 SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, TimeUnit.MILLISECONDS);
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 return;
250 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800251
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700252 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 }
TeruU417fe022014-02-04 12:59:30 -0800254
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 private class WaitDeviceArp implements Runnable {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700256 Switch sw;
257 Port inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 Ethernet eth;
TeruU417fe022014-02-04 12:59:30 -0800259
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700260 public WaitDeviceArp(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 super();
262 this.sw = sw;
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700263 this.inPort = inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 this.eth = eth;
265 }
TeruU417fe022014-02-04 12:59:30 -0800266
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 @Override
268 public void run() {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700269 Device deviceObject = topology.getDeviceByMac(MACAddress.valueOf(eth.getDestinationMACAddress()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 if (deviceObject == null) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700271 log.debug("wait {}ms and device was not found. " +
272 "Send broadcast packet and the thread finish.",
273 SLEEP_TIME_FOR_DB_DEVICE_INSTALLED);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700274 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 return;
276 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700277 log.debug("wait {}ms and device {} was found, continue",
278 SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700279 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 }
281 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800282
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700283 private void continueHandlePacketIn(Switch sw, Port inPort, Ethernet eth, Device deviceObject) {
TeruU7feef8a2014-04-03 00:15:49 -0700284
TeruU9e530662014-05-18 11:49:37 -0700285 log.trace("Start continuehandlePacketIn");
TeruU7feef8a2014-04-03 00:15:49 -0700286
Ray Milkey269ffb92014-04-03 14:43:30 -0700287 //Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
288 Iterator<net.onrc.onos.core.topology.Port> ports = deviceObject.getAttachmentPoints().iterator();
289 if (!ports.hasNext()) {
290 log.debug("No attachment point found for device {} - broadcasting packet",
291 deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700292 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700293 return;
294 }
TeruU7feef8a2014-04-03 00:15:49 -0700295
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 //This code assumes the device has only one port. It should be problem.
297 net.onrc.onos.core.topology.Port portObject = ports.next();
298 short destinationPort = portObject.getNumber().shortValue();
299 Switch switchObject = portObject.getSwitch();
300 long destinationDpid = switchObject.getDpid();
301
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700302 // TODO eliminate cast
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 SwitchPort srcSwitchPort = new SwitchPort(
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700304 new Dpid(sw.getDpid()),
305 new net.onrc.onos.core.util.Port((short) inPort.getNumber().longValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 SwitchPort dstSwitchPort = new SwitchPort(
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700307 new Dpid(destinationDpid),
308 new net.onrc.onos.core.util.Port(destinationPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700309
310 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
311 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
TeruU9e530662014-05-18 11:49:37 -0700312 Path pathspec = new Path(srcMacAddress, dstMacAddress);
313 IntentOperationList operations = new IntentOperationList();
Ray Milkey269ffb92014-04-03 14:43:30 -0700314
315 synchronized (lock) {
316 //TODO check concurrency
TeruU9e530662014-05-18 11:49:37 -0700317
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 PushedFlow existingFlow = pendingFlows.get(pathspec);
319
320 //A path is installed side by side to reduce a path timeout and a wrong state.
321 if (existingFlow != null) {
322 // We've already start to install a flow for this pair of MAC addresses
323 if (log.isDebugEnabled()) {
324 log.debug("Found existing the same pathspec {}, intent ID is {}",
325 pathspec,
326 existingFlow.intentId);
327 }
328
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 // Find the correct port here. We just assume the PI is from
330 // the first hop switch, but this is definitely not always
331 // the case. We'll have to retrieve the flow from HZ every time
332 // because it could change (be rerouted) sometimes.
333 if (existingFlow.installed) {
334 // Flow has been sent to the switches so it is safe to
335 // send a packet out now
336
TeruU9e530662014-05-18 11:49:37 -0700337 // TODO Here highLevelIntentMap and pathIntentMap would be problem,
338 // because it doesn't have global information as of May 2014.
339 // However usually these lines here is used when we got packet-in and this class think
340 // the path for the packet is installed already, so it is pretty rare.
341 // I will leave it for now, and will work in the next step.
342 Intent highLevelIntent = highLevelIntentMap.getIntent(existingFlow.intentId);
343 if (highLevelIntent == null) {
344 log.debug("Intent ID {} is null in HighLevelIntentMap. return.", existingFlow.intentId);
345 return;
346 }
347
348 if (highLevelIntent.getState() != IntentState.INST_ACK) {
349 log.debug("Intent ID {}'s state is not INST_ACK. return.", existingFlow.intentId);
350 return;
351 }
352
353 ShortestPathIntent spfIntent = null;
354 if (highLevelIntent instanceof ShortestPathIntent) {
355 spfIntent = (ShortestPathIntent) highLevelIntent;
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 } else {
TeruUf9111652014-05-14 23:10:35 -0700357 log.debug("Intent ID {} is not PathIntent or null. return.", existingFlow.intentId);
Ray Milkey269ffb92014-04-03 14:43:30 -0700358 return;
359 }
360
TeruU9e530662014-05-18 11:49:37 -0700361 PathIntent pathIntent = (PathIntent) pathIntentMap.getIntent(spfIntent.getPathIntentId());
362 if (pathIntent == null) {
363 log.debug("PathIntent ID {} is null in PathIntentMap. return.", existingFlow.intentId);
364 return;
365 }
366
367 if (pathIntent.getState() != IntentState.INST_ACK) {
368 log.debug("Intent ID {}'s state is not INST_ACK. return.", existingFlow.intentId);
369 return;
370 }
371
372 boolean isflowEntryForThisSwitch = false;
Yuta HIGUCHI1fc395e2014-05-13 14:06:28 -0700373 net.onrc.onos.core.intent.Path path = pathIntent.getPath();
TeruU9e530662014-05-18 11:49:37 -0700374 long outPort = -1;
375
376 if (spfIntent.getDstSwitchDpid() == sw.getDpid()) {
377 log.trace("The packet-in sw dpid {} is on the path.", sw.getDpid());
378 isflowEntryForThisSwitch = true;
379 outPort = spfIntent.getDstPortNumber();
380 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700381
Ray Milkey7f1567c2014-04-08 13:53:32 -0700382 for (Iterator<LinkEvent> i = path.iterator(); i.hasNext();) {
Ray Milkey149693c2014-05-20 14:58:53 -0700383 LinkEvent le = i.next();
TeruU9e530662014-05-18 11:49:37 -0700384
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700385 if (le.getSrc().dpid.equals(sw.getDpid())) {
TeruU9e530662014-05-18 11:49:37 -0700386 log.trace("The packet-in sw dpid {} is on the path.", sw.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700387 isflowEntryForThisSwitch = true;
TeruU9e530662014-05-18 11:49:37 -0700388 outPort = le.getSrc().getNumber();
Ray Milkey269ffb92014-04-03 14:43:30 -0700389 break;
390 }
391 }
392
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700393 if (!isflowEntryForThisSwitch) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700394 // If we don't find a flow entry for that switch, then we're
395 // in the middle of a rerouting (or something's gone wrong).
396 // This packet will be dropped as a victim of the rerouting.
397 log.debug("Dropping packet on flow {} between {}-{}",
398 existingFlow.intentId,
399 srcMacAddress, dstMacAddress);
400 } else {
TeruU9e530662014-05-18 11:49:37 -0700401 if (outPort < 0) {
402 outPort = existingFlow.firstOutPort;
403 }
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700404
TeruU9e530662014-05-18 11:49:37 -0700405 log.debug("Sending packet out from sw {}, outport{}", sw.getDpid(), outPort);
Jonathan Harte3702f22014-04-29 02:56:56 -0700406 packetService.sendPacket(eth, new SwitchPort(
TeruU9e530662014-05-18 11:49:37 -0700407 sw.getDpid(), (short) outPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700408 }
409 } else {
410 // Flow path has not yet been installed to switches so save the
411 // packet out for later
TeruU9e530662014-05-18 11:49:37 -0700412 log.trace("Put a packet into the waiting list. flowId {}", existingFlow.intentId);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700413 waitingPackets.put(existingFlow.intentId, new PacketToPush(eth, sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700414 }
415 return;
416 }
417
TeruU9e530662014-05-18 11:49:37 -0700418 String intentId = Long.toString(controllerRegistryService.getNextUniqueId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700419 ShortestPathIntent intent = new ShortestPathIntent(intentId,
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700420 sw.getDpid(), inPort.getNumber(), srcMacAddress.toLong(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700421 destinationDpid, destinationPort, dstMacAddress.toLong());
Ray Milkeyff735142014-05-22 19:06:02 -0700422
TeruU30c0c932014-05-15 16:47:41 -0700423 intent.setIdleTimeout(idleTimeout + SRC_SWITCH_TIMEOUT_ADJUST_SECOND);
424 intent.setFirstSwitchIdleTimeout(idleTimeout);
Ray Milkey269ffb92014-04-03 14:43:30 -0700425 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
426 operations.add(operator, intent);
TeruU9e530662014-05-18 11:49:37 -0700427 log.debug("Adding new flow between {} at {} and {} at {}",
428 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
Ray Milkey269ffb92014-04-03 14:43:30 -0700429
TeruU9e530662014-05-18 11:49:37 -0700430 // Add to waiting lists
431 waitingPackets.put(intentId, new PacketToPush(eth, sw.getDpid()));
432 log.trace("Put a Packet in the wating list. intent ID {}, related pathspec {}", intentId, pathspec);
433 pendingFlows.put(pathspec, new PushedFlow(intentId));
434 log.trace("Put a Path {} in the pending flow, intent ID {}", pathspec, intentId);
Ray Milkey269ffb92014-04-03 14:43:30 -0700435 }
TeruU9e530662014-05-18 11:49:37 -0700436 pathRuntime.executeIntentOperations(operations);
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 }
438
Ray Milkey269ffb92014-04-03 14:43:30 -0700439 @Override
440 public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
441 }
442
443 @Override
444 public void flowRemoved(FlowPath removedFlowPath) {
445 }
446
447 public void flowRemoved(PathIntent removedIntent) {
448 if (log.isTraceEnabled()) {
449 log.trace("Path {} was removed", removedIntent.getParentIntent().getId());
450 }
451
452 ShortestPathIntent spfIntent = (ShortestPathIntent) removedIntent.getParentIntent();
453 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
454 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
455 Path removedPath = new Path(srcMacAddress, dstMacAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700456 synchronized (lock) {
457 // There *shouldn't* be any packets queued if the flow has
458 // just been removed.
459 List<PacketToPush> packets = waitingPackets.removeAll(spfIntent.getId());
460 if (!packets.isEmpty()) {
461 log.warn("Removed flow {} has packets queued.", spfIntent.getId());
462 }
TeruU9e530662014-05-18 11:49:37 -0700463
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 pendingFlows.remove(removedPath);
465 log.debug("Removed from the pendingFlow: Path {}, Flow ID {}", removedPath, spfIntent.getId());
466 }
467 }
468
469 private void flowInstalled(PathIntent installedPath) {
470 if (log.isTraceEnabled()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700471 log.trace("Installed intent ID {}, path {}",
472 installedPath.getParentIntent().getId(), installedPath.getPath());
Ray Milkey269ffb92014-04-03 14:43:30 -0700473 }
474
475 ShortestPathIntent spfIntent = (ShortestPathIntent) installedPath.getParentIntent();
476 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
477 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
478 Path path = new Path(srcMacAddress, dstMacAddress);
479 log.debug("Path spec {}", path);
480
481 // TODO waiting packets should time out. We could request a path that
482 // can't be installed right now because of a network partition. The path
483 // may eventually be installed, but we may have received thousands of
484 // packets in the meantime and probably don't want to send very old packets.
485
486 List<PacketToPush> packets = null;
Yuta HIGUCHI1fc395e2014-05-13 14:06:28 -0700487 net.onrc.onos.core.intent.Path graphPath = installedPath.getPath();
Ray Milkey269ffb92014-04-03 14:43:30 -0700488
TeruU220c45e2014-04-10 18:56:26 -0700489 short outPort;
490 if (graphPath.isEmpty()) {
491 outPort = (short) spfIntent.getDstPortNumber();
492 log.debug("Path is empty. Maybe devices on the same switch. outPort {}", outPort);
493 } else {
494 outPort = graphPath.get(0).getSrc().getNumber().shortValue();
495 log.debug("path{}, outPort {}", graphPath, outPort);
496 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700497
498 PushedFlow existingFlow = null;
499
500 synchronized (lock) {
501 existingFlow = pendingFlows.get(path);
502
503 if (existingFlow != null) {
504 existingFlow.installed = true;
505 existingFlow.firstOutPort = outPort;
506 } else {
507 log.debug("ExistingFlow {} is null", path);
508 return;
509 }
510
511 //Check both existing flow are installed status.
512 if (existingFlow.installed) {
513 packets = waitingPackets.removeAll(existingFlow.intentId);
514 if (log.isDebugEnabled()) {
515 log.debug("removed my packets {} to push from waitingPackets. outPort {} size {}",
516 existingFlow.intentId, existingFlow.firstOutPort, packets.size());
517 }
518 } else {
519 log.debug("Forward or reverse flows hasn't been pushed yet. return");
520 return;
521 }
522 }
523
524 for (PacketToPush packet : packets) {
525 log.debug("Start packetToPush to sw {}, outPort {}, path {}", packet.dpid, existingFlow.firstOutPort, path);
Jonathan Harte3702f22014-04-29 02:56:56 -0700526 packetService.sendPacket(packet.eth, new SwitchPort(
527 packet.dpid, existingFlow.firstOutPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 }
529 }
530
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 @Override
TeruUf9111652014-05-14 23:10:35 -0700532 public void intentsChange(LinkedList<ChangedEvent> events) {
533 for (ChangedEvent event : events) {
534 log.debug("path intent ID {}, eventType {}", event.intent.getId() , event.eventType);
TeruU9e530662014-05-18 11:49:37 -0700535 PathIntent pathIntent = (PathIntent) pathIntentMap.getIntent(event.intent.getId());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700536 if (pathIntent == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700537 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700538 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700539
Ray Milkeyb29e6262014-04-09 16:02:14 -0700540 if (!(pathIntent.getParentIntent() instanceof ShortestPathIntent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700542 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700543
TeruUf9111652014-05-14 23:10:35 -0700544 switch(event.eventType) {
545 case ADDED:
Ray Milkey269ffb92014-04-03 14:43:30 -0700546 break;
TeruUf9111652014-05-14 23:10:35 -0700547 case REMOVED:
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 break;
TeruUf9111652014-05-14 23:10:35 -0700549 case STATE_CHANGED:
550 IntentState state = pathIntent.getState();
551 switch (state) {
552 case INST_REQ:
553 break;
554 case INST_ACK:
555 flowInstalled(pathIntent);
556 break;
557 case INST_NACK:
558 break;
559 case DEL_REQ:
560 break;
561 case DEL_ACK:
562 flowRemoved(pathIntent);
563 break;
564 case DEL_PENDING:
565 break;
566 default:
567 break;
568 }
Ray Milkey149693c2014-05-20 14:58:53 -0700569 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700570 default:
571 break;
572 }
573 }
574 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800575}