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