2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.openflowplugin.impl.connection;
10 import static org.junit.Assert.assertThrows;
11 import static org.mockito.ArgumentMatchers.any;
13 import com.google.common.collect.Lists;
14 import com.google.common.util.concurrent.Futures;
15 import java.math.BigInteger;
16 import java.time.LocalDateTime;
17 import java.util.ArrayList;
18 import java.util.List;
19 import org.junit.After;
20 import org.junit.Assert;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.junit.runner.RunWith;
24 import org.mockito.ArgumentCaptor;
25 import org.mockito.Mock;
26 import org.mockito.Mockito;
27 import org.mockito.junit.MockitoJUnitRunner;
28 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
29 import org.opendaylight.openflowplugin.api.OFConstants;
30 import org.opendaylight.openflowplugin.api.openflow.connection.DeviceConnectionStatusProvider;
31 import org.opendaylight.openflowplugin.api.openflow.md.core.ErrorHandler;
32 import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener;
33 import org.opendaylight.openflowplugin.impl.common.DeviceConnectionRateLimiter;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.HelloElementType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.Elements;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.ElementsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfigBuilder;
44 import org.opendaylight.yangtools.yang.common.RpcResult;
45 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
46 import org.opendaylight.yangtools.yang.common.Uint16;
47 import org.opendaylight.yangtools.yang.common.Uint32;
48 import org.opendaylight.yangtools.yang.common.Uint64;
49 import org.opendaylight.yangtools.yang.common.Uint8;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
56 @RunWith(MockitoJUnitRunner.class)
57 public class HandshakeManagerImplTest {
59 private static final Logger LOG = LoggerFactory.getLogger(HandshakeManagerImplTest.class);
60 private static final Uint16 DEVICE_CONNECTION_RATE_LIMIT_PER_MIN = Uint16.ZERO;
61 private static final int DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS = 60;
63 private HandshakeManagerImpl handshakeManager;
65 private ConnectionAdapter adapter;
67 private ErrorHandler errorHandler;
69 private HandshakeListener handshakeListener;
71 private DeviceConnectionStatusProvider deviceConnectionStatusProvider;
73 private DeviceConnectionRateLimiter deviceConnectionRateLimiter;
75 private RpcResult<GetFeaturesOutput> resultFeatures;
77 private final long helloXid = 42L;
79 private int expectedErrors = 0;
82 * invoked before every test method.
86 deviceConnectionRateLimiter = new DeviceConnectionRateLimiter(new OpenflowProviderConfigBuilder()
87 .setDeviceConnectionRateLimitPerMin(DEVICE_CONNECTION_RATE_LIMIT_PER_MIN).build());
88 handshakeManager = new HandshakeManagerImpl(adapter, OFConstants.OFP_VERSION_1_3, OFConstants.VERSION_ORDER,
89 errorHandler, handshakeListener, false, deviceConnectionRateLimiter,
90 DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS, deviceConnectionStatusProvider);
92 resultFeatures = RpcResultBuilder.success(new GetFeaturesOutputBuilder().setDatapathId(Uint64.ONE).build())
95 Mockito.when(adapter.hello(any(HelloInput.class)))
96 .thenReturn(Futures.immediateFuture(RpcResultBuilder.success((HelloOutput) null).build()));
97 Mockito.when(deviceConnectionStatusProvider.getDeviceLastConnectionTime(BigInteger.ONE))
98 .thenReturn(LocalDateTime.now().minusSeconds(DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS));
102 * invoked after each test method.
105 public void teardown() {
106 // logging errors if occurred
107 ArgumentCaptor<Throwable> errorCaptor = ArgumentCaptor.forClass(Throwable.class);
108 Mockito.verify(errorHandler, Mockito.atMost(1)).handleException(errorCaptor.capture());
109 for (Throwable problem : errorCaptor.getAllValues()) {
110 LOG.warn(problem.getMessage(), problem);
113 Mockito.verify(errorHandler, Mockito.times(expectedErrors)).handleException(any(Throwable.class));
118 * {@link org.opendaylight.openflowplugin.openflow.md.core
119 * .HandshakeManagerImpl#proposeCommonBitmapVersion(java.util.List)}.
122 public void testProposeCommonBitmapVersion() {
124 = new Boolean[][]{{true, true, true, false, false, false}, {true, true, true, false, false}};
126 for (Boolean[] verasionList : versions) {
127 ElementsBuilder elementsBuilder = new ElementsBuilder();
128 elementsBuilder.setVersionBitmap(Lists.newArrayList(verasionList));
129 Elements element = elementsBuilder.build();
130 Assert.assertEquals(Uint8.ONE, handshakeManager.proposeCommonBitmapVersion(List.of(element)));
136 * {@link org.opendaylight.openflowplugin.openflow.md.core.HandshakeManagerImpl#proposeNextVersion(short)}.
139 public void testProposeNextVersion() {
140 short[] remoteVer = new short[]{0x05, 0x04, 0x03, 0x02, 0x01, 0x8f, 0xff};
141 short[] expectedProposal = new short[]{0x04, 0x04, 0x01, 0x01, 0x01, 0x04, 0x04};
143 for (int i = 0; i < remoteVer.length; i++) {
144 Uint8 actualProposal = handshakeManager.proposeNextVersion(Uint8.valueOf(remoteVer[i]));
145 Assert.assertEquals(String.format("proposing for version: %04x", remoteVer[i]), expectedProposal[i],
146 actualProposal.toJava());
149 assertThrows(IllegalArgumentException.class, () -> handshakeManager.proposeNextVersion(Uint8.ZERO));
152 //////// Version Negotiation Tests //////////////
155 * Test of version negotiation Where switch version = 1.0.
159 public void testVersionNegotiation10() {
160 LOG.debug("testVersionNegotiation10");
161 Uint8 version = OFConstants.OFP_VERSION_1_0;
163 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
164 .thenReturn(Futures.immediateFuture(resultFeatures));
166 handshakeManager.shake(null);
168 handshakeManager.shake(createHelloMessage(version, helloXid).build());
170 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
174 * Test of version negotiation Where switch version = 1.0.
178 public void testVersionNegotiation10SwitchStarts() {
179 LOG.debug("testVersionNegotiation10-ss");
180 Uint8 version = OFConstants.OFP_VERSION_1_0;
182 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
183 .thenReturn(Futures.immediateFuture(resultFeatures));
185 handshakeManager.shake(createHelloMessage(version, helloXid).build());
187 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
191 * Test of version negotiation Where switch version < 1.0.
192 * Switch delivers first helloMessage with version 0x00 = negotiation unsuccessful
195 public void testVersionNegotiation00() {
196 LOG.debug("testVersionNegotiation00");
199 handshakeManager.shake(createHelloMessage(Uint8.ZERO, helloXid).build());
201 Mockito.verify(handshakeListener, Mockito.never())
202 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
206 * Test of version negotiation Where switch version < 1.0.
207 * Switch delivers first helloMessage with version 0x00 = negotiation unsuccessful
210 public void testVersionNegotiation00SwitchStarts() {
211 LOG.debug("testVersionNegotiation00-ss");
213 Uint8 version = Uint8.ZERO;
215 handshakeManager.shake(null);
217 handshakeManager.shake(createHelloMessage(version, helloXid).build());
219 Mockito.verify(handshakeListener, Mockito.never())
220 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
224 * Test of version negotiation Where 1.0 < switch version < 1.3.
228 public void testVersionNegotiation11() {
229 LOG.debug("testVersionNegotiation11");
230 final Uint8 version = Uint8.TWO;
231 final Uint8 expVersion = Uint8.ONE;
233 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
234 .thenReturn(Futures.immediateFuture(resultFeatures));
236 handshakeManager.shake(createHelloMessage(version, helloXid).build());
238 handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
240 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
244 * Test of version negotiation Where 1.0 < switch version < 1.3.
247 public void testVersionNegotiation11SwitchStarts() {
248 LOG.debug("testVersionNegotiation11-ss");
249 final Uint8 version = Uint8.TWO;
250 final Uint8 expVersion = Uint8.ONE;
252 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
253 .thenReturn(Futures.immediateFuture(resultFeatures));
255 handshakeManager.shake(null);
257 handshakeManager.shake(createHelloMessage(version, helloXid).build());
259 handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
261 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
265 * Test of version negotiation Where switch version = 1.3.
269 public void testVersionNegotiation13() {
270 LOG.debug("testVersionNegotiation13");
271 Uint8 version = OFConstants.OFP_VERSION_1_3;
273 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
274 .thenReturn(Futures.immediateFuture(resultFeatures));
276 handshakeManager.shake(createHelloMessage(version, helloXid).build());
278 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
282 * Test of version negotiation Where switch version = 1.3.
286 public void testVersionNegotiation13SwitchStarts() {
287 LOG.debug("testVersionNegotiation13-ss");
288 Uint8 version = OFConstants.OFP_VERSION_1_3;
290 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
291 .thenReturn(Futures.immediateFuture(resultFeatures));
293 handshakeManager.shake(null);
295 handshakeManager.shake(createHelloMessage(version, helloXid).build());
297 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
301 * Test of version negotiation Where switch version >= 1.3.
305 public void testVersionNegotiation15() {
306 LOG.debug("testVersionNegotiation15");
307 Uint8 version = Uint8.valueOf(6);
308 Uint8 expVersion = OFConstants.OFP_VERSION_1_3;
310 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
311 .thenReturn(Futures.immediateFuture(resultFeatures));
313 handshakeManager.shake(createHelloMessage(version, helloXid).build());
315 handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
317 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
321 * Test of version negotiation Where switch version >= 1.3.
325 public void testVersionNegotiation15SwitchStart() {
326 LOG.debug("testVersionNegotiation15-ss");
327 Uint8 version = Uint8.valueOf(6);
328 Uint8 expVersion = OFConstants.OFP_VERSION_1_3;
330 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
331 .thenReturn(Futures.immediateFuture(resultFeatures));
333 handshakeManager.shake(createHelloMessage(version, helloXid).build());
335 handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
337 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
341 * Test of version negotiation Where switch version > 1.3.
345 public void testVersionNegotiation15_MultipleCall() {
346 LOG.debug("testVersionNegotiation15_MultipleCall");
347 Uint8 version = Uint8.valueOf(6);
350 handshakeManager.shake(createHelloMessage(version, helloXid).build());
352 handshakeManager.shake(createHelloMessage(version, helloXid).build());
354 Mockito.verify(handshakeListener, Mockito.never())
355 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
359 * Test of version negotiation Where switch version > 1.3.
363 public void testVersionNegotiation15_MultipleCallSwitchStarts() {
364 LOG.debug("testVersionNegotiation15_MultipleCall-ss");
365 Uint8 version = Uint8.valueOf(6);
368 handshakeManager.shake(null);
370 handshakeManager.shake(createHelloMessage(version, helloXid).build());
372 handshakeManager.shake(createHelloMessage(version, helloXid).build());
374 Mockito.verify(handshakeListener, Mockito.never())
375 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
379 * Test of version negotiation Where bitmap version {0x05,0x01}.
383 public void testVersionNegotiation10InBitmap() {
384 LOG.debug("testVersionNegotiation10InBitmap");
385 Uint8 version = OFConstants.OFP_VERSION_1_0;
386 handshakeManager.setUseVersionBitmap(true);
388 HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
389 addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_0), helloMessage);
391 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
392 .thenReturn(Futures.immediateFuture(resultFeatures));
394 handshakeManager.shake(helloMessage.build());
396 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
400 * Test of version negotiation Where bitmap version {0x05,0x01}.
404 public void testVersionNegotiation10InBitmapSwitchStarts() {
405 LOG.debug("testVersionNegotiation10InBitmap-ss");
406 Uint8 version = OFConstants.OFP_VERSION_1_0;
407 handshakeManager.setUseVersionBitmap(true);
409 HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
410 addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_0), helloMessage);
412 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
413 .thenReturn(Futures.immediateFuture(resultFeatures));
415 handshakeManager.shake(null);
417 handshakeManager.shake(helloMessage.build());
419 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
423 * Test of version negotiation Where bitmap version {0x05,0x04}.
427 public void testVersionNegotiation13InBitmap() {
428 LOG.debug("testVersionNegotiation13InBitmap");
429 Uint8 version = OFConstants.OFP_VERSION_1_3;
430 handshakeManager.setUseVersionBitmap(true);
432 HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
433 addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_3), helloMessage);
435 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
436 .thenReturn(Futures.immediateFuture(resultFeatures));
438 handshakeManager.shake(helloMessage.build());
440 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
444 * Test of version negotiation Where bitmap version {0x05,0x04}.
448 public void testVersionNegotiation13InBitmapSwitchFirst() {
449 LOG.debug("testVersionNegotiation13InBitmap-ss");
450 Uint8 version = OFConstants.OFP_VERSION_1_3;
451 handshakeManager.setUseVersionBitmap(true);
453 HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
454 addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_3), helloMessage);
456 Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
457 .thenReturn(Futures.immediateFuture(resultFeatures));
459 handshakeManager.shake(null);
461 handshakeManager.shake(helloMessage.build());
463 Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
467 * Test of version negotiation Where bitmap version {0x05,0x02}.
471 public void testVersionNegotiationNoCommonVersionInBitmap() {
472 LOG.debug("testVersionNegotiationNoCommonVersionInBitmap");
473 Uint8 version = Uint8.valueOf(5);
475 handshakeManager.setUseVersionBitmap(true);
477 HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
478 addVersionBitmap(List.of(Uint8.valueOf(5), Uint8.TWO), helloMessage);
480 handshakeManager.shake(helloMessage.build());
482 Mockito.verify(handshakeListener, Mockito.never())
483 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
487 * Test of version negotiation Where bitmap version {0x05,0x02}.
491 public void testVersionNegotiationNoCommonVersionInBitmapSwitchStarts() {
492 LOG.debug("testVersionNegotiationNoCommonVersionInBitmap-ss");
493 Uint8 version = Uint8.valueOf(5);
495 handshakeManager.setUseVersionBitmap(true);
497 HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
498 addVersionBitmap(List.of(Uint8.valueOf(5), Uint8.TWO), helloMessage);
500 handshakeManager.shake(null);
502 handshakeManager.shake(helloMessage.build());
504 Mockito.verify(handshakeListener, Mockito.never())
505 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
510 * Creates hello message.
512 * @param ofpVersion10 version
513 * @param helloXid hello xid
516 private static HelloMessageBuilder createHelloMessage(final Uint8 ofpVersion10, final long helloXid) {
517 return new HelloMessageBuilder().setVersion(ofpVersion10).setXid(Uint32.valueOf(helloXid));
521 * Adds version bitmap.
522 * @param versionOrder version order
523 * @param helloBuilder hello builder
526 private static HelloMessageBuilder addVersionBitmap(final List<Uint8> versionOrder,
527 final HelloMessageBuilder helloBuilder) {
528 final short highestVersion = versionOrder.get(0).toJava();
529 final int elementsCount = highestVersion / Integer.SIZE;
530 ElementsBuilder elementsBuilder = new ElementsBuilder();
532 List<Elements> elementList = new ArrayList<>();
533 int orderIndex = versionOrder.size();
534 int value = versionOrder.get(--orderIndex).toJava();
535 for (int index = 0; index <= elementsCount; index++) {
536 List<Boolean> booleanList = new ArrayList<>();
537 for (int i = 0; i < Integer.SIZE; i++) {
538 if (value == index * Integer.SIZE + i) {
539 booleanList.add(true);
540 value = orderIndex == 0 ? highestVersion : versionOrder.get(--orderIndex).toJava();
542 booleanList.add(false);
545 elementsBuilder.setType(HelloElementType.forValue(1));
546 elementsBuilder.setVersionBitmap(booleanList);
547 elementList.add(elementsBuilder.build());
550 helloBuilder.setElements(elementList);