blob: fcdbcf0f45ae1624fdc9794e47a34c51b881ad7b [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* Copyright 2011, Big Switch Networks, Inc.
3* Originally created by David Erickson, Stanford University
4*
5* Licensed under the Apache License, Version 2.0 (the "License"); you may
6* not use this file except in compliance with the License. You may obtain
7* a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14* License for the specific language governing permissions and limitations
15* under the License.
16**/
17
18package net.floodlightcontroller.core.internal;
19
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070020import static org.easymock.EasyMock.anyObject;
21import static org.easymock.EasyMock.capture;
22import static org.easymock.EasyMock.createMock;
23import static org.easymock.EasyMock.createNiceMock;
24import static org.easymock.EasyMock.eq;
25import static org.easymock.EasyMock.expect;
26import static org.easymock.EasyMock.expectLastCall;
27import static org.easymock.EasyMock.isA;
28import static org.easymock.EasyMock.replay;
29import static org.easymock.EasyMock.reset;
30import static org.easymock.EasyMock.same;
31import static org.easymock.EasyMock.verify;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080032
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Date;
36import java.util.HashMap;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080037import java.util.List;
38import java.util.Map;
39import java.util.concurrent.ConcurrentHashMap;
40import java.util.concurrent.Future;
41import java.util.concurrent.TimeUnit;
42
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080043import net.floodlightcontroller.core.FloodlightContext;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070044import net.floodlightcontroller.core.FloodlightProvider;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080045import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080046import net.floodlightcontroller.core.IFloodlightProviderService.Role;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070047import net.floodlightcontroller.core.IHAListener;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080048import net.floodlightcontroller.core.IListener.Command;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070049import net.floodlightcontroller.core.IOFMessageListener;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080050import net.floodlightcontroller.core.IOFSwitch;
51import net.floodlightcontroller.core.IOFSwitchListener;
Pankaj Berde6e421732013-08-14 15:17:52 -070052import net.floodlightcontroller.core.IUpdate;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080053import net.floodlightcontroller.core.internal.Controller.SwitchUpdate;
54import net.floodlightcontroller.core.internal.Controller.SwitchUpdateType;
55import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
56import net.floodlightcontroller.core.module.FloodlightModuleContext;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080057import net.floodlightcontroller.core.test.MockThreadPoolService;
58import net.floodlightcontroller.counter.CounterStore;
59import net.floodlightcontroller.counter.ICounterStoreService;
60import net.floodlightcontroller.packet.ARP;
61import net.floodlightcontroller.packet.Ethernet;
62import net.floodlightcontroller.packet.IPacket;
63import net.floodlightcontroller.packet.IPv4;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080064import net.floodlightcontroller.restserver.IRestApiService;
65import net.floodlightcontroller.restserver.RestApiServer;
66import net.floodlightcontroller.storage.IStorageSourceService;
67import net.floodlightcontroller.storage.memory.MemoryStorageSource;
68import net.floodlightcontroller.test.FloodlightTestCase;
69import net.floodlightcontroller.threadpool.IThreadPoolService;
HIGUCHI Yuta36cf0762013-06-14 14:25:38 -070070import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -070071import net.onrc.onos.ofcontroller.flowmanager.FlowManager;
72import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
Jonathan Hart220b8292013-12-07 19:25:11 -080073import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
74import net.onrc.onos.ofcontroller.linkdiscovery.internal.LinkDiscoveryManager;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070075import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070076import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -070077import net.onrc.onos.registry.controller.IControllerRegistryService;
78import net.onrc.onos.registry.controller.StandaloneRegistry;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080079
80import org.easymock.Capture;
81import org.easymock.EasyMock;
82import org.jboss.netty.channel.Channel;
83import org.junit.Test;
84import org.openflow.protocol.OFError;
85import org.openflow.protocol.OFError.OFBadRequestCode;
86import org.openflow.protocol.OFError.OFErrorType;
87import org.openflow.protocol.OFFeaturesReply;
88import org.openflow.protocol.OFPacketIn;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070089import org.openflow.protocol.OFPacketIn.OFPacketInReason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080090import org.openflow.protocol.OFPhysicalPort;
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -070091import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
92import org.openflow.protocol.OFPhysicalPort.OFPortState;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080093import org.openflow.protocol.OFPortStatus;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070094import org.openflow.protocol.OFPortStatus.OFPortReason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080095import org.openflow.protocol.OFStatisticsReply;
96import org.openflow.protocol.OFType;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080097import org.openflow.protocol.OFVendor;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080098import org.openflow.protocol.factory.BasicFactory;
99import org.openflow.protocol.statistics.OFFlowStatisticsReply;
100import org.openflow.protocol.statistics.OFStatistics;
101import org.openflow.protocol.statistics.OFStatisticsType;
102import org.openflow.util.HexString;
103import org.openflow.vendor.nicira.OFNiciraVendorData;
104import org.openflow.vendor.nicira.OFRoleReplyVendorData;
105
106/**
107 *
108 * @author David Erickson (daviderickson@cs.stanford.edu)
109 */
110public class ControllerTest extends FloodlightTestCase {
111
112 private Controller controller;
113 private MockThreadPoolService tp;
114
115 @Override
116 public void setUp() throws Exception {
117 super.setUp();
118 FloodlightModuleContext fmc = new FloodlightModuleContext();
119
120 FloodlightProvider cm = new FloodlightProvider();
121 controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class);
122 fmc.addService(IFloodlightProviderService.class, controller);
123
124 MemoryStorageSource memstorage = new MemoryStorageSource();
125 fmc.addService(IStorageSourceService.class, memstorage);
126
127 RestApiServer restApi = new RestApiServer();
128 fmc.addService(IRestApiService.class, restApi);
129
130 CounterStore cs = new CounterStore();
131 fmc.addService(ICounterStoreService.class, cs);
132
mininet73e7fb72013-12-03 14:25:53 -0800133
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800134 tp = new MockThreadPoolService();
135 fmc.addService(IThreadPoolService.class, tp);
136
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700137 // Following added by ONOS
138 // TODO replace with mock if further testing is needed.
139 fmc.addService(IFlowService.class, new FlowManager() );
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700140 fmc.addService(ITopologyNetService.class, new TopologyManager() );
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700141 StandaloneRegistry sr = new StandaloneRegistry();
142 fmc.addService(IControllerRegistryService.class, sr );
Jonathan Hart220b8292013-12-07 19:25:11 -0800143 LinkDiscoveryManager linkDiscovery = new LinkDiscoveryManager();
144 fmc.addService(ILinkDiscoveryService.class, linkDiscovery);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700145
146
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800147 restApi.init(fmc);
148 memstorage.init(fmc);
149 cm.init(fmc);
150 tp.init(fmc);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700151 sr.init(fmc);
Jonathan Hart220b8292013-12-07 19:25:11 -0800152 linkDiscovery.init(fmc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800153 restApi.startUp(fmc);
154 memstorage.startUp(fmc);
155 cm.startUp(fmc);
156 tp.startUp(fmc);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700157 sr.startUp(fmc);
Jonathan Hart220b8292013-12-07 19:25:11 -0800158 linkDiscovery.startUp(fmc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800159 }
160
161 public Controller getController() {
162 return controller;
163 }
164
165 protected OFStatisticsReply getStatisticsReply(int transactionId,
166 int count, boolean moreReplies) {
167 OFStatisticsReply sr = new OFStatisticsReply();
168 sr.setXid(transactionId);
169 sr.setStatisticType(OFStatisticsType.FLOW);
170 List<OFStatistics> statistics = new ArrayList<OFStatistics>();
171 for (int i = 0; i < count; ++i) {
172 statistics.add(new OFFlowStatisticsReply());
173 }
174 sr.setStatistics(statistics);
175 if (moreReplies)
176 sr.setFlags((short) 1);
177 return sr;
178 }
179
180 /* Set the mock expectations for sw when sw is passed to addSwitch */
181 protected void setupSwitchForAddSwitch(IOFSwitch sw, long dpid) {
182 String dpidString = HexString.toHexString(dpid);
183
184 expect(sw.getId()).andReturn(dpid).anyTimes();
185 expect(sw.getStringId()).andReturn(dpidString).anyTimes();
186 expect(sw.getConnectedSince()).andReturn(new Date());
187 Channel channel = createMock(Channel.class);
188 expect(sw.getChannel()).andReturn(channel);
189 expect(channel.getRemoteAddress()).andReturn(null);
190
191 expect(sw.getCapabilities()).andReturn(0).anyTimes();
192 expect(sw.getBuffers()).andReturn(0).anyTimes();
193 expect(sw.getTables()).andReturn((byte)0).anyTimes();
194 expect(sw.getActions()).andReturn(0).anyTimes();
195 expect(sw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>()).anyTimes();
196 }
197
198 /**
199 * Run the controller's main loop so that updates are processed
200 */
201 protected class ControllerRunThread extends Thread {
202 public void run() {
203 controller.openFlowPort = 0; // Don't listen
204 controller.run();
205 }
206 }
207
208 /**
209 * Verify that a listener that throws an exception halts further
210 * execution, and verify that the Commands STOP and CONTINUE are honored.
211 * @throws Exception
212 */
213 @Test
214 public void testHandleMessages() throws Exception {
215 Controller controller = getController();
216 controller.removeOFMessageListeners(OFType.PACKET_IN);
217
218 IOFSwitch sw = createMock(IOFSwitch.class);
219 expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
220
221 // Build our test packet
222 IPacket testPacket = new Ethernet()
223 .setSourceMACAddress("00:44:33:22:11:00")
224 .setDestinationMACAddress("00:11:22:33:44:55")
225 .setEtherType(Ethernet.TYPE_ARP)
226 .setPayload(
227 new ARP()
228 .setHardwareType(ARP.HW_TYPE_ETHERNET)
229 .setProtocolType(ARP.PROTO_TYPE_IP)
230 .setHardwareAddressLength((byte) 6)
231 .setProtocolAddressLength((byte) 4)
232 .setOpCode(ARP.OP_REPLY)
233 .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
234 .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
235 .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
236 .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
237 byte[] testPacketSerialized = testPacket.serialize();
238
239 // Build the PacketIn
240 OFPacketIn pi = ((OFPacketIn) new BasicFactory().getMessage(OFType.PACKET_IN))
241 .setBufferId(-1)
242 .setInPort((short) 1)
243 .setPacketData(testPacketSerialized)
244 .setReason(OFPacketInReason.NO_MATCH)
245 .setTotalLength((short) testPacketSerialized.length);
246
247 IOFMessageListener test1 = createMock(IOFMessageListener.class);
248 expect(test1.getName()).andReturn("test1").anyTimes();
249 expect(test1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
250 expect(test1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
251 expect(test1.receive(eq(sw), eq(pi), isA(FloodlightContext.class))).andThrow(new RuntimeException("This is NOT an error! We are testing exception catching."));
252 IOFMessageListener test2 = createMock(IOFMessageListener.class);
253 expect(test2.getName()).andReturn("test2").anyTimes();
254 expect(test2.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
255 expect(test2.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
256 // expect no calls to test2.receive() since test1.receive() threw an exception
257
258 replay(test1, test2, sw);
259 controller.addOFMessageListener(OFType.PACKET_IN, test1);
260 controller.addOFMessageListener(OFType.PACKET_IN, test2);
261 try {
262 controller.handleMessage(sw, pi, null);
263 } catch (RuntimeException e) {
264 assertEquals(e.getMessage().startsWith("This is NOT an error!"), true);
265 }
266 verify(test1, test2, sw);
267
268 // verify STOP works
269 reset(test1, test2, sw);
270 expect(test1.receive(eq(sw), eq(pi), isA(FloodlightContext.class))).andReturn(Command.STOP);
271 //expect(test1.getId()).andReturn(0).anyTimes();
272 expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
273 replay(test1, test2, sw);
274 controller.handleMessage(sw, pi, null);
275 verify(test1, test2, sw);
276 }
277
278 public class FutureFetcher<E> implements Runnable {
279 public E value;
280 public Future<E> future;
281
282 public FutureFetcher(Future<E> future) {
283 this.future = future;
284 }
285
286 @Override
287 public void run() {
288 try {
289 value = future.get();
290 } catch (Exception e) {
291 throw new RuntimeException(e);
292 }
293 }
294
295 /**
296 * @return the value
297 */
298 public E getValue() {
299 return value;
300 }
301
302 /**
303 * @return the future
304 */
305 public Future<E> getFuture() {
306 return future;
307 }
308 }
309
310 /**
311 *
312 * @throws Exception
313 */
314 @Test
315 public void testOFStatisticsFuture() throws Exception {
316 // Test for a single stats reply
317 IOFSwitch sw = createMock(IOFSwitch.class);
318 sw.cancelStatisticsReply(1);
319 OFStatisticsFuture sf = new OFStatisticsFuture(tp, sw, 1);
320
321 replay(sw);
322 List<OFStatistics> stats;
323 FutureFetcher<List<OFStatistics>> ff = new FutureFetcher<List<OFStatistics>>(sf);
324 Thread t = new Thread(ff);
325 t.start();
326 sf.deliverFuture(sw, getStatisticsReply(1, 10, false));
327
328 t.join();
329 stats = ff.getValue();
330 verify(sw);
331 assertEquals(10, stats.size());
332
333 // Test multiple stats replies
334 reset(sw);
335 sw.cancelStatisticsReply(1);
336
337 sf = new OFStatisticsFuture(tp, sw, 1);
338
339 replay(sw);
340 ff = new FutureFetcher<List<OFStatistics>>(sf);
341 t = new Thread(ff);
342 t.start();
343 sf.deliverFuture(sw, getStatisticsReply(1, 10, true));
344 sf.deliverFuture(sw, getStatisticsReply(1, 5, false));
345 t.join();
346
347 stats = sf.get();
348 verify(sw);
349 assertEquals(15, stats.size());
350
351 // Test cancellation
352 reset(sw);
353 sw.cancelStatisticsReply(1);
354 sf = new OFStatisticsFuture(tp, sw, 1);
355
356 replay(sw);
357 ff = new FutureFetcher<List<OFStatistics>>(sf);
358 t = new Thread(ff);
359 t.start();
360 sf.cancel(true);
361 t.join();
362
363 stats = sf.get();
364 verify(sw);
365 assertEquals(0, stats.size());
366
367 // Test self timeout
368 reset(sw);
369 sw.cancelStatisticsReply(1);
370 sf = new OFStatisticsFuture(tp, sw, 1, 75, TimeUnit.MILLISECONDS);
371
372 replay(sw);
373 ff = new FutureFetcher<List<OFStatistics>>(sf);
374 t = new Thread(ff);
375 t.start();
376 t.join(2000);
377
378 stats = sf.get();
379 verify(sw);
380 assertEquals(0, stats.size());
381 }
382
383 @Test
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800384 public void testAddSwitch() throws Exception {
385 controller.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
386
387 //OFSwitchImpl oldsw = createMock(OFSwitchImpl.class);
388 OFSwitchImpl oldsw = new OFSwitchImpl();
389 OFFeaturesReply featuresReply = new OFFeaturesReply();
390 featuresReply.setDatapathId(0L);
391 featuresReply.setPorts(new ArrayList<OFPhysicalPort>());
392 oldsw.setFeaturesReply(featuresReply);
393 //expect(oldsw.getId()).andReturn(0L).anyTimes();
394 //expect(oldsw.asyncRemoveSwitchLock()).andReturn(rwlock.writeLock()).anyTimes();
395 //oldsw.setConnected(false);
396 //expect(oldsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
397
398 Channel channel = createNiceMock(Channel.class);
399 //expect(oldsw.getChannel()).andReturn(channel);
400 oldsw.setChannel(channel);
401 expect(channel.close()).andReturn(null);
402
403 IOFSwitch newsw = createMock(IOFSwitch.class);
404 expect(newsw.getId()).andReturn(0L).anyTimes();
405 expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
406 expect(newsw.getConnectedSince()).andReturn(new Date());
407 Channel channel2 = createMock(Channel.class);
408 expect(newsw.getChannel()).andReturn(channel2);
409 expect(channel2.getRemoteAddress()).andReturn(null);
Jonathan Hart220b8292013-12-07 19:25:11 -0800410 expect(newsw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>()).times(2);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800411 expect(newsw.getCapabilities()).andReturn(0).anyTimes();
412 expect(newsw.getBuffers()).andReturn(0).anyTimes();
413 expect(newsw.getTables()).andReturn((byte)0).anyTimes();
414 expect(newsw.getActions()).andReturn(0).anyTimes();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800415 controller.activeSwitches.put(0L, oldsw);
416 replay(newsw, channel, channel2);
417
418 controller.addSwitch(newsw);
419
420 verify(newsw, channel, channel2);
421 }
422
423 @Test
424 public void testUpdateQueue() throws Exception {
HIGUCHI Yuta36cf0762013-06-14 14:25:38 -0700425 class DummySwitchListener implements IOFSwitchListener, IOFSwitchPortListener {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800426 public int nAdded;
427 public int nRemoved;
428 public int nPortChanged;
429 public DummySwitchListener() {
430 nAdded = 0;
431 nRemoved = 0;
432 nPortChanged = 0;
433 }
434 public synchronized void addedSwitch(IOFSwitch sw) {
435 nAdded++;
436 notifyAll();
437 }
438 public synchronized void removedSwitch(IOFSwitch sw) {
439 nRemoved++;
440 notifyAll();
441 }
442 public String getName() {
443 return "dummy";
444 }
445 @Override
446 public void switchPortChanged(Long switchId) {
447 nPortChanged++;
448 notifyAll();
449 }
Pankaj Berde3ee2bfe2013-06-10 21:30:14 -0700450 @Override
451 public void switchPortAdded(Long switchId, OFPhysicalPort port) {
452 // TODO Auto-generated method stub
453
454 }
455 @Override
456 public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
457 // TODO Auto-generated method stub
458
459 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800460 }
461 DummySwitchListener switchListener = new DummySwitchListener();
462 IOFSwitch sw = createMock(IOFSwitch.class);
Jonathan Hart220b8292013-12-07 19:25:11 -0800463 expect(sw.getId()).andReturn(1L).anyTimes();
464 expect(sw.getEnabledPorts()).andReturn(null);
465 expect(sw.getChannel()).andReturn(null).anyTimes();
466 replay(sw);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800467 ControllerRunThread t = new ControllerRunThread();
468 t.start();
469
470 controller.addOFSwitchListener(switchListener);
471 synchronized(switchListener) {
472 controller.updates.put(controller.new SwitchUpdate(sw,
473 Controller.SwitchUpdateType.ADDED));
474 switchListener.wait(500);
475 assertTrue("IOFSwitchListener.addedSwitch() was not called",
476 switchListener.nAdded == 1);
477 controller.updates.put(controller.new SwitchUpdate(sw,
478 Controller.SwitchUpdateType.REMOVED));
479 switchListener.wait(500);
480 assertTrue("IOFSwitchListener.removedSwitch() was not called",
481 switchListener.nRemoved == 1);
482 controller.updates.put(controller.new SwitchUpdate(sw,
483 Controller.SwitchUpdateType.PORTCHANGED));
484 switchListener.wait(500);
485 assertTrue("IOFSwitchListener.switchPortChanged() was not called",
486 switchListener.nPortChanged == 1);
487 }
488 }
489
490
491 private Map<String,Object> getFakeControllerIPRow(String id, String controllerId,
492 String type, int number, String discoveredIP ) {
493 HashMap<String, Object> row = new HashMap<String,Object>();
494 row.put(Controller.CONTROLLER_INTERFACE_ID, id);
495 row.put(Controller.CONTROLLER_INTERFACE_CONTROLLER_ID, controllerId);
496 row.put(Controller.CONTROLLER_INTERFACE_TYPE, type);
497 row.put(Controller.CONTROLLER_INTERFACE_NUMBER, number);
498 row.put(Controller.CONTROLLER_INTERFACE_DISCOVERED_IP, discoveredIP);
499 return row;
500 }
501
502 /**
503 * Test notifications for controller node IP changes. This requires
504 * synchronization between the main test thread and another thread
505 * that runs Controller's main loop and takes / handles updates. We
506 * synchronize with wait(timeout) / notifyAll(). We check for the
507 * expected condition after the wait returns. However, if wait returns
508 * due to the timeout (or due to spurious awaking) and the check fails we
509 * might just not have waited long enough. Using a long enough timeout
510 * mitigates this but we cannot get rid of the fundamental "issue".
511 *
512 * @throws Exception
513 */
514 @Test
515 public void testControllerNodeIPChanges() throws Exception {
516 class DummyHAListener implements IHAListener {
517 public Map<String, String> curControllerNodeIPs;
518 public Map<String, String> addedControllerNodeIPs;
519 public Map<String, String> removedControllerNodeIPs;
520 public int nCalled;
521
522 public DummyHAListener() {
523 this.nCalled = 0;
524 }
525
526 @Override
527 public void roleChanged(Role oldRole, Role newRole) {
528 // ignore
529 }
530
531 @Override
532 public synchronized void controllerNodeIPsChanged(
533 Map<String, String> curControllerNodeIPs,
534 Map<String, String> addedControllerNodeIPs,
535 Map<String, String> removedControllerNodeIPs) {
536 this.curControllerNodeIPs = curControllerNodeIPs;
537 this.addedControllerNodeIPs = addedControllerNodeIPs;
538 this.removedControllerNodeIPs = removedControllerNodeIPs;
539 this.nCalled++;
540 notifyAll();
541 }
542
543 public void do_assert(int nCalled,
544 Map<String, String> curControllerNodeIPs,
545 Map<String, String> addedControllerNodeIPs,
546 Map<String, String> removedControllerNodeIPs) {
547 assertEquals("nCalled is not as expected", nCalled, this.nCalled);
548 assertEquals("curControllerNodeIPs is not as expected",
549 curControllerNodeIPs, this.curControllerNodeIPs);
550 assertEquals("addedControllerNodeIPs is not as expected",
551 addedControllerNodeIPs, this.addedControllerNodeIPs);
552 assertEquals("removedControllerNodeIPs is not as expected",
553 removedControllerNodeIPs, this.removedControllerNodeIPs);
554
555 }
556 }
557 long waitTimeout = 250; // ms
558 DummyHAListener listener = new DummyHAListener();
559 HashMap<String,String> expectedCurMap = new HashMap<String, String>();
560 HashMap<String,String> expectedAddedMap = new HashMap<String, String>();
561 HashMap<String,String> expectedRemovedMap = new HashMap<String, String>();
562
563 controller.addHAListener(listener);
564 ControllerRunThread t = new ControllerRunThread();
565 t.start();
566
567 synchronized(listener) {
568 // Insert a first entry
569 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
570 getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
571 expectedCurMap.clear();
572 expectedAddedMap.clear();
573 expectedRemovedMap.clear();
574 expectedCurMap.put("c1", "1.1.1.1");
575 expectedAddedMap.put("c1", "1.1.1.1");
576 listener.wait(waitTimeout);
577 listener.do_assert(1, expectedCurMap, expectedAddedMap, expectedRemovedMap);
578
579 // Add an interface that we want to ignore.
580 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
581 getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
582 listener.wait(waitTimeout); // TODO: do a different check. This call will have to wait for the timeout
583 assertTrue("controllerNodeIPsChanged() should not have been called here",
584 listener.nCalled == 1);
585
586 // Add another entry
587 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
588 getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
589 expectedCurMap.clear();
590 expectedAddedMap.clear();
591 expectedRemovedMap.clear();
592 expectedCurMap.put("c1", "1.1.1.1");
593 expectedCurMap.put("c2", "2.2.2.2");
594 expectedAddedMap.put("c2", "2.2.2.2");
595 listener.wait(waitTimeout);
596 listener.do_assert(2, expectedCurMap, expectedAddedMap, expectedRemovedMap);
597
598
599 // Update an entry
600 controller.storageSource.updateRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
601 "row3", getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.3"));
602 expectedCurMap.clear();
603 expectedAddedMap.clear();
604 expectedRemovedMap.clear();
605 expectedCurMap.put("c1", "1.1.1.1");
606 expectedCurMap.put("c2", "2.2.2.3");
607 expectedAddedMap.put("c2", "2.2.2.3");
608 expectedRemovedMap.put("c2", "2.2.2.2");
609 listener.wait(waitTimeout);
610 listener.do_assert(3, expectedCurMap, expectedAddedMap, expectedRemovedMap);
611
612 // Delete an entry
613 controller.storageSource.deleteRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
614 "row3");
615 expectedCurMap.clear();
616 expectedAddedMap.clear();
617 expectedRemovedMap.clear();
618 expectedCurMap.put("c1", "1.1.1.1");
619 expectedRemovedMap.put("c2", "2.2.2.3");
620 listener.wait(waitTimeout);
621 listener.do_assert(4, expectedCurMap, expectedAddedMap, expectedRemovedMap);
622 }
623 }
624
625 @Test
626 public void testGetControllerNodeIPs() {
627 HashMap<String,String> expectedCurMap = new HashMap<String, String>();
628
629 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
630 getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
631 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
632 getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
633 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
634 getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
635 expectedCurMap.put("c1", "1.1.1.1");
636 expectedCurMap.put("c2", "2.2.2.2");
637 assertEquals("expectedControllerNodeIPs is not as expected",
638 expectedCurMap, controller.getControllerNodeIPs());
639 }
640
641 @Test
642 public void testSetRoleNull() {
643 try {
644 controller.setRole(null);
645 fail("Should have thrown an Exception");
646 }
647 catch (NullPointerException e) {
648 //exptected
649 }
650 }
651
652 @Test
653 public void testSetRole() {
654 controller.connectedSwitches.add(new OFSwitchImpl());
655 RoleChanger roleChanger = createMock(RoleChanger.class);
656 roleChanger.submitRequest(controller.connectedSwitches, Role.SLAVE);
657 controller.roleChanger = roleChanger;
658
659 assertEquals("Check that update queue is empty", 0,
660 controller.updates.size());
661
662 replay(roleChanger);
663 controller.setRole(Role.SLAVE);
664 verify(roleChanger);
665
Pankaj Berde6e421732013-08-14 15:17:52 -0700666 IUpdate upd = controller.updates.poll();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800667 assertNotNull("Check that update queue has an update", upd);
668 assertTrue("Check that update is HARoleUpdate",
669 upd instanceof Controller.HARoleUpdate);
670 Controller.HARoleUpdate roleUpd = (Controller.HARoleUpdate)upd;
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700671 assertSame(Role.MASTER, roleUpd.oldRole);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800672 assertSame(Role.SLAVE, roleUpd.newRole);
673 }
674
675 @Test
676 public void testCheckSwitchReady() {
677 OFChannelState state = new OFChannelState();
678 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
679 chdlr.sw = createMock(OFSwitchImpl.class);
680
681 // Wrong current state
682 // Should not go to READY
683 state.hsState = OFChannelState.HandshakeState.HELLO;
684 state.hasDescription = true;
685 state.hasGetConfigReply = true;
686 replay(chdlr.sw); // nothing called on sw
687 chdlr.checkSwitchReady();
688 verify(chdlr.sw);
689 assertSame(OFChannelState.HandshakeState.HELLO, state.hsState);
690 reset(chdlr.sw);
691
692 // Have only config reply
693 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
694 state.hasDescription = false;
695 state.hasGetConfigReply = true;
696 replay(chdlr.sw);
697 chdlr.checkSwitchReady();
698 verify(chdlr.sw);
699 assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState);
700 assertTrue(controller.connectedSwitches.isEmpty());
701 assertTrue(controller.activeSwitches.isEmpty());
702 reset(chdlr.sw);
703
704 // Have only desc reply
705 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
706 state.hasDescription = true;
707 state.hasGetConfigReply = false;
708 replay(chdlr.sw);
709 chdlr.checkSwitchReady();
710 verify(chdlr.sw);
711 assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState);
712 assertTrue(controller.connectedSwitches.isEmpty());
713 assertTrue(controller.activeSwitches.isEmpty());
714 reset(chdlr.sw);
715
716 //////////////////////////////////////////
717 // Finally, everything is right. Should advance to READY
718 //////////////////////////////////////////
719 controller.roleChanger = createMock(RoleChanger.class);
720 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
721 state.hasDescription = true;
722 state.hasGetConfigReply = true;
723 // Role support disabled. Switch should be promoted to active switch
724 // list.
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700725// FIXME: ONOS modified the behavior to always submit Role Request to trigger OFS error.
726// setupSwitchForAddSwitch(chdlr.sw, 0L);
727// chdlr.sw.clearAllFlowMods();
728// replay(controller.roleChanger, chdlr.sw);
729// chdlr.checkSwitchReady();
730// verify(controller.roleChanger, chdlr.sw);
731// assertSame(OFChannelState.HandshakeState.READY, state.hsState);
732// assertSame(chdlr.sw, controller.activeSwitches.get(0L));
733// assertTrue(controller.connectedSwitches.contains(chdlr.sw));
734// assertTrue(state.firstRoleReplyReceived);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800735 reset(chdlr.sw);
736 reset(controller.roleChanger);
737 controller.connectedSwitches.clear();
738 controller.activeSwitches.clear();
739
740
741 // Role support enabled.
742 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
743 controller.role = Role.MASTER;
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700744 expect(chdlr.sw.getStringId()).andReturn("SomeID").anyTimes();
745 expect(chdlr.sw.getId()).andReturn(42L).anyTimes();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800746 Capture<Collection<OFSwitchImpl>> swListCapture =
747 new Capture<Collection<OFSwitchImpl>>();
748 controller.roleChanger.submitRequest(capture(swListCapture),
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700749 same(Role.SLAVE));
750 Capture<Collection<OFSwitchImpl>> swListCapture2 =
751 new Capture<Collection<OFSwitchImpl>>();
752 controller.roleChanger.submitRequest(capture(swListCapture2),
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800753 same(Role.MASTER));
754 replay(controller.roleChanger, chdlr.sw);
755 chdlr.checkSwitchReady();
756 verify(controller.roleChanger, chdlr.sw);
757 assertSame(OFChannelState.HandshakeState.READY, state.hsState);
758 assertTrue(controller.activeSwitches.isEmpty());
759 assertTrue(controller.connectedSwitches.contains(chdlr.sw));
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700760// assertTrue(state.firstRoleReplyReceived);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800761 Collection<OFSwitchImpl> swList = swListCapture.getValue();
762 assertEquals(1, swList.size());
763 assertTrue("swList must contain this switch", swList.contains(chdlr.sw));
764 }
765
766
767 @Test
768 public void testChannelDisconnected() throws Exception {
769 OFChannelState state = new OFChannelState();
770 state.hsState = OFChannelState.HandshakeState.READY;
771 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
772 chdlr.sw = createMock(OFSwitchImpl.class);
773
774 // Switch is active
775 expect(chdlr.sw.getId()).andReturn(0L).anyTimes();
776 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:00")
777 .anyTimes();
778 chdlr.sw.cancelAllStatisticsReplies();
779 chdlr.sw.setConnected(false);
780 expect(chdlr.sw.isConnected()).andReturn(true);
781
782 controller.connectedSwitches.add(chdlr.sw);
783 controller.activeSwitches.put(0L, chdlr.sw);
784
785 replay(chdlr.sw);
786 chdlr.channelDisconnected(null, null);
787 verify(chdlr.sw);
788
789 // Switch is connected but not active
790 reset(chdlr.sw);
791 expect(chdlr.sw.getId()).andReturn(0L).anyTimes();
792 chdlr.sw.setConnected(false);
793 replay(chdlr.sw);
794 chdlr.channelDisconnected(null, null);
795 verify(chdlr.sw);
796
797 // Not in ready state
798 state.hsState = HandshakeState.START;
799 reset(chdlr.sw);
800 replay(chdlr.sw);
801 chdlr.channelDisconnected(null, null);
802 verify(chdlr.sw);
803
804 // Switch is null
805 state.hsState = HandshakeState.READY;
806 chdlr.sw = null;
807 chdlr.channelDisconnected(null, null);
808 }
809
810 /*
811 @Test
812 public void testRoleChangeForSerialFailoverSwitch() throws Exception {
813 OFSwitchImpl newsw = createMock(OFSwitchImpl.class);
814 expect(newsw.getId()).andReturn(0L).anyTimes();
815 expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
816 Channel channel2 = createMock(Channel.class);
817 expect(newsw.getChannel()).andReturn(channel2);
818
819 // newsw.role is null because the switch does not support
820 // role request messages
821 expect(newsw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
822 .andReturn(false);
823 // switch is connected
824 controller.connectedSwitches.add(newsw);
825
826 // the switch should get disconnected when role is changed to SLAVE
827 expect(channel2.close()).andReturn(null);
828
829 replay(newsw, channel2);
830 controller.setRole(Role.SLAVE);
831 verify(newsw, channel2);
832 }
833 */
834
835 @Test
836 public void testRoleNotSupportedError() throws Exception {
837 int xid = 424242;
838 OFChannelState state = new OFChannelState();
839 state.hsState = HandshakeState.READY;
840 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
841 chdlr.sw = createMock(OFSwitchImpl.class);
842 Channel ch = createMock(Channel.class);
843
844 // the error returned when role request message is not supported by sw
845 OFError msg = new OFError();
846 msg.setType(OFType.ERROR);
847 msg.setXid(xid);
848 msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
849 msg.setErrorCode(OFBadRequestCode.OFPBRC_BAD_VENDOR);
850
851 // the switch connection should get disconnected when the controller is
852 // in SLAVE mode and the switch does not support role-request messages
853 state.firstRoleReplyReceived = false;
854 controller.role = Role.SLAVE;
855 expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700856 expect(chdlr.sw.deliverRoleRequestNotSupportedEx(xid)).andReturn(Role.SLAVE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800857 expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
858 expect(ch.close()).andReturn(null);
859
860 replay(ch, chdlr.sw);
861 chdlr.processOFMessage(msg);
862 verify(ch, chdlr.sw);
863 assertTrue("state.firstRoleReplyReceived must be true",
864 state.firstRoleReplyReceived);
865 assertTrue("activeSwitches must be empty",
866 controller.activeSwitches.isEmpty());
867 reset(ch, chdlr.sw);
868
869
870 // a different error message - should also reject role request
871 msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
872 msg.setErrorCode(OFBadRequestCode.OFPBRC_EPERM);
873 state.firstRoleReplyReceived = false;
874 controller.role = Role.SLAVE;
875 expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700876 expect(chdlr.sw.deliverRoleRequestNotSupportedEx(xid)).andReturn(Role.SLAVE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800877 expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
878 expect(ch.close()).andReturn(null);
879 replay(ch, chdlr.sw);
880
881 chdlr.processOFMessage(msg);
882 verify(ch, chdlr.sw);
883 assertTrue("state.firstRoleReplyReceived must be True even with EPERM",
884 state.firstRoleReplyReceived);
885 assertTrue("activeSwitches must be empty",
886 controller.activeSwitches.isEmpty());
887 reset(ch, chdlr.sw);
888
889
890 // We are MASTER, the switch should be added to the list of active
891 // switches.
892 state.firstRoleReplyReceived = false;
893 controller.role = Role.MASTER;
894 expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -0700895 expect(chdlr.sw.deliverRoleRequestNotSupportedEx(xid)).andReturn(Role.MASTER);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800896 setupSwitchForAddSwitch(chdlr.sw, 0L);
897 chdlr.sw.clearAllFlowMods();
898 replay(ch, chdlr.sw);
899
900 chdlr.processOFMessage(msg);
901 verify(ch, chdlr.sw);
902 assertTrue("state.firstRoleReplyReceived must be true",
903 state.firstRoleReplyReceived);
904 assertSame("activeSwitches must contain this switch",
905 chdlr.sw, controller.activeSwitches.get(0L));
906 reset(ch, chdlr.sw);
907
908 }
909
910
911 @Test
912 public void testVendorMessageUnknown() throws Exception {
913 // Check behavior with an unknown vendor id
914 OFChannelState state = new OFChannelState();
915 state.hsState = HandshakeState.READY;
916 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
917 OFVendor msg = new OFVendor();
918 msg.setVendor(0);
919 chdlr.processOFMessage(msg);
920 }
921
922
923 // Helper function.
924 protected Controller.OFChannelHandler getChannelHandlerForRoleReplyTest() {
925 OFChannelState state = new OFChannelState();
926 state.hsState = HandshakeState.READY;
927 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
928 chdlr.sw = createMock(OFSwitchImpl.class);
929 return chdlr;
930 }
931
932 // Helper function
933 protected OFVendor getRoleReplyMsgForRoleReplyTest(int xid, int nicira_role) {
934 OFVendor msg = new OFVendor();
935 msg.setXid(xid);
936 msg.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
937 OFRoleReplyVendorData roleReplyVendorData =
938 new OFRoleReplyVendorData(OFRoleReplyVendorData.NXT_ROLE_REPLY);
939 msg.setVendorData(roleReplyVendorData);
940 roleReplyVendorData.setRole(nicira_role);
941 return msg;
942 }
943
944 /** invalid role in role reply */
945 @Test
946 public void testNiciraRoleReplyInvalidRole()
947 throws Exception {
948 int xid = 424242;
949 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
950 Channel ch = createMock(Channel.class);
951 expect(chdlr.sw.getChannel()).andReturn(ch);
952 expect(ch.close()).andReturn(null);
953 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 232323);
954 replay(chdlr.sw, ch);
955 chdlr.processOFMessage(msg);
956 verify(chdlr.sw, ch);
957 }
958
959 /** First role reply message received: transition from slave to master */
960 @Test
961 public void testNiciraRoleReplySlave2MasterFristTime()
962 throws Exception {
963 int xid = 424242;
964 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
965 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
966 OFRoleReplyVendorData.NX_ROLE_MASTER);
967
968 chdlr.sw.deliverRoleReply(xid, Role.MASTER);
969 expect(chdlr.sw.isActive()).andReturn(true);
970 setupSwitchForAddSwitch(chdlr.sw, 1L);
971 chdlr.sw.clearAllFlowMods();
972 chdlr.state.firstRoleReplyReceived = false;
973 replay(chdlr.sw);
974 chdlr.processOFMessage(msg);
975 verify(chdlr.sw);
976 assertTrue("state.firstRoleReplyReceived must be true",
977 chdlr.state.firstRoleReplyReceived);
978 assertSame("activeSwitches must contain this switch",
979 chdlr.sw, controller.activeSwitches.get(1L));
980 }
981
982
983 /** Not first role reply message received: transition from slave to master */
984 @Test
985 public void testNiciraRoleReplySlave2MasterNotFristTime()
986 throws Exception {
987 int xid = 424242;
988 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
989 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
990 OFRoleReplyVendorData.NX_ROLE_MASTER);
991
992 chdlr.sw.deliverRoleReply(xid, Role.MASTER);
993 expect(chdlr.sw.isActive()).andReturn(true);
994 setupSwitchForAddSwitch(chdlr.sw, 1L);
995 chdlr.state.firstRoleReplyReceived = true;
996 // Flow table shouldn't be wipe
997 replay(chdlr.sw);
998 chdlr.processOFMessage(msg);
999 verify(chdlr.sw);
1000 assertTrue("state.firstRoleReplyReceived must be true",
1001 chdlr.state.firstRoleReplyReceived);
1002 assertSame("activeSwitches must contain this switch",
1003 chdlr.sw, controller.activeSwitches.get(1L));
1004 }
1005
1006 /** transition from slave to equal */
1007 @Test
1008 public void testNiciraRoleReplySlave2Equal()
1009 throws Exception {
1010 int xid = 424242;
1011 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1012 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1013 OFRoleReplyVendorData.NX_ROLE_OTHER);
1014
1015 chdlr.sw.deliverRoleReply(xid, Role.EQUAL);
1016 expect(chdlr.sw.isActive()).andReturn(true);
1017 setupSwitchForAddSwitch(chdlr.sw, 1L);
1018 chdlr.sw.clearAllFlowMods();
1019 chdlr.state.firstRoleReplyReceived = false;
1020 replay(chdlr.sw);
1021 chdlr.processOFMessage(msg);
1022 verify(chdlr.sw);
1023 assertTrue("state.firstRoleReplyReceived must be true",
1024 chdlr.state.firstRoleReplyReceived);
1025 assertSame("activeSwitches must contain this switch",
1026 chdlr.sw, controller.activeSwitches.get(1L));
1027 };
1028
1029 @Test
1030 /** Slave2Slave transition ==> no change */
1031 public void testNiciraRoleReplySlave2Slave() throws Exception{
1032 int xid = 424242;
1033 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1034 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1035 OFRoleReplyVendorData.NX_ROLE_SLAVE);
1036
1037 chdlr.sw.deliverRoleReply(xid, Role.SLAVE);
1038 expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
1039 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
1040 .anyTimes();
1041 expect(chdlr.sw.isActive()).andReturn(false);
1042 // don't add switch to activeSwitches ==> slave2slave
1043 chdlr.state.firstRoleReplyReceived = false;
1044 replay(chdlr.sw);
1045 chdlr.processOFMessage(msg);
1046 verify(chdlr.sw);
1047 assertTrue("state.firstRoleReplyReceived must be true",
1048 chdlr.state.firstRoleReplyReceived);
1049 assertTrue("activeSwitches must be empty",
1050 controller.activeSwitches.isEmpty());
1051 }
1052
1053 @Test
1054 /** Equal2Master transition ==> no change */
1055 public void testNiciraRoleReplyEqual2Master() throws Exception{
1056 int xid = 424242;
1057 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1058 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1059 OFRoleReplyVendorData.NX_ROLE_MASTER);
1060
1061 chdlr.sw.deliverRoleReply(xid, Role.MASTER);
1062 expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
1063 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
1064 .anyTimes();
1065 expect(chdlr.sw.isActive()).andReturn(true);
1066 controller.activeSwitches.put(1L, chdlr.sw);
1067 chdlr.state.firstRoleReplyReceived = false;
1068 replay(chdlr.sw);
1069 chdlr.processOFMessage(msg);
1070 verify(chdlr.sw);
1071 assertTrue("state.firstRoleReplyReceived must be true",
1072 chdlr.state.firstRoleReplyReceived);
1073 assertSame("activeSwitches must contain this switch",
1074 chdlr.sw, controller.activeSwitches.get(1L));
1075 }
1076
1077 @Test
1078 public void testNiciraRoleReplyMaster2Slave()
1079 throws Exception {
1080 int xid = 424242;
1081 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1082 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1083 OFRoleReplyVendorData.NX_ROLE_SLAVE);
1084
1085 chdlr.sw.deliverRoleReply(xid, Role.SLAVE);
1086 expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
1087 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
1088 .anyTimes();
1089 controller.activeSwitches.put(1L, chdlr.sw);
1090 expect(chdlr.sw.isActive()).andReturn(false);
1091 expect(chdlr.sw.isConnected()).andReturn(true);
1092 chdlr.sw.cancelAllStatisticsReplies();
1093 chdlr.state.firstRoleReplyReceived = false;
1094 replay(chdlr.sw);
1095 chdlr.processOFMessage(msg);
1096 verify(chdlr.sw);
1097 assertTrue("state.firstRoleReplyReceived must be true",
1098 chdlr.state.firstRoleReplyReceived);
1099 assertTrue("activeSwitches must be empty",
1100 controller.activeSwitches.isEmpty());
1101 }
1102
1103 /**
1104 * Tests that you can't remove a switch from the active
1105 * switch list.
1106 * @throws Exception
1107 */
1108 @Test
1109 public void testRemoveActiveSwitch() {
1110 IOFSwitch sw = EasyMock.createNiceMock(IOFSwitch.class);
1111 boolean exceptionThrown = false;
1112 expect(sw.getId()).andReturn(1L).anyTimes();
1113 replay(sw);
1114 getController().activeSwitches.put(sw.getId(), sw);
1115 try {
1116 getController().getSwitches().remove(1L);
1117 } catch (UnsupportedOperationException e) {
1118 exceptionThrown = true;
1119 }
1120 assertTrue(exceptionThrown);
1121 verify(sw);
1122 }
1123
1124 public void verifyPortChangedUpdateInQueue(IOFSwitch sw) throws Exception {
1125 assertEquals(1, controller.updates.size());
1126 IUpdate update = controller.updates.take();
1127 assertEquals(true, update instanceof SwitchUpdate);
1128 SwitchUpdate swUpdate = (SwitchUpdate)update;
1129 assertEquals(sw, swUpdate.sw);
1130 assertEquals(SwitchUpdateType.PORTCHANGED, swUpdate.switchUpdateType);
1131 }
1132
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -07001133 public void verifyPortAddedUpdateInQueue(IOFSwitch sw) throws Exception {
1134 assertEquals(2, controller.updates.size());
1135 IUpdate update = controller.updates.take();
1136 assertEquals(true, update instanceof SwitchUpdate);
1137 SwitchUpdate swUpdate = (SwitchUpdate)update;
1138 assertEquals(sw, swUpdate.sw);
1139 assertEquals(SwitchUpdateType.PORTADDED, swUpdate.switchUpdateType);
1140 verifyPortChangedUpdateInQueue(sw);
1141 }
1142
1143 public void verifyPortRemovedUpdateInQueue(IOFSwitch sw) throws Exception {
1144 assertEquals(2, controller.updates.size());
1145 IUpdate update = controller.updates.take();
1146 assertEquals(true, update instanceof SwitchUpdate);
1147 SwitchUpdate swUpdate = (SwitchUpdate)update;
1148 assertEquals(sw, swUpdate.sw);
1149 assertEquals(SwitchUpdateType.PORTREMOVED, swUpdate.switchUpdateType);
1150 verifyPortChangedUpdateInQueue(sw);
1151 }
1152
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001153 /*
1154 * Test handlePortStatus()
1155 * TODO: test correct updateStorage behavior!
1156 */
1157 @Test
1158 public void testHandlePortStatus() throws Exception {
1159 IOFSwitch sw = createMock(IOFSwitch.class);
Jonathan Hart220b8292013-12-07 19:25:11 -08001160 expect(sw.getId()).andReturn(1L).anyTimes();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001161 OFPhysicalPort port = new OFPhysicalPort();
1162 port.setName("myPortName1");
1163 port.setPortNumber((short)42);
1164
1165 OFPortStatus ofps = new OFPortStatus();
1166 ofps.setDesc(port);
1167
1168 ofps.setReason((byte)OFPortReason.OFPPR_ADD.ordinal());
1169 sw.setPort(port);
1170 expectLastCall().once();
1171 replay(sw);
1172 controller.handlePortStatusMessage(sw, ofps, false);
1173 verify(sw);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -07001174 verifyPortAddedUpdateInQueue(sw);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001175 reset(sw);
1176
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -07001177 // ONOS:Port is considered added if Link state is not down and not configured to be down
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001178 ofps.setReason((byte)OFPortReason.OFPPR_MODIFY.ordinal());
1179 sw.setPort(port);
1180 expectLastCall().once();
1181 replay(sw);
1182 controller.handlePortStatusMessage(sw, ofps, false);
1183 verify(sw);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -07001184 verifyPortAddedUpdateInQueue(sw);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001185 reset(sw);
1186
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -07001187 // ONOS:Port is considered removed if Link state is down
1188 ofps.setReason((byte)OFPortReason.OFPPR_MODIFY.ordinal());
1189 port.setState(OFPortState.OFPPS_LINK_DOWN.getValue());
1190 sw.setPort(port);
1191 expectLastCall().once();
1192 replay(sw);
1193 controller.handlePortStatusMessage(sw, ofps, false);
1194 verify(sw);
1195 verifyPortRemovedUpdateInQueue(sw);
1196 reset(sw);
1197 port.setState(0);// reset
1198
1199 // ONOS: .. or is configured to be down
1200 ofps.setReason((byte)OFPortReason.OFPPR_MODIFY.ordinal());
1201 port.setConfig(OFPortConfig.OFPPC_PORT_DOWN.getValue());
1202 sw.setPort(port);
1203 expectLastCall().once();
1204 replay(sw);
1205 controller.handlePortStatusMessage(sw, ofps, false);
1206 verify(sw);
1207 verifyPortRemovedUpdateInQueue(sw);
1208 reset(sw);
1209 port.setConfig(0);// reset
1210
1211
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001212 ofps.setReason((byte)OFPortReason.OFPPR_DELETE.ordinal());
1213 sw.deletePort(port.getPortNumber());
1214 expectLastCall().once();
1215 replay(sw);
1216 controller.handlePortStatusMessage(sw, ofps, false);
1217 verify(sw);
HIGUCHI Yuta21fd07f2013-06-28 11:24:14 -07001218 verifyPortRemovedUpdateInQueue(sw);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001219 reset(sw);
1220 }
1221}