X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=openflowplugin%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fopenflow%2Fmd%2Fcore%2FConnectionConductorImplTest.java;h=5d586ca12ac27e50eba47d574ab537dc0b54f5af;hb=611180ac770b6038b526c54994701db16d1a8567;hp=84fc8bb82ee59af48053dad9f82e9898fb3ab012;hpb=8746e4ce01810c546635bf98b106ad092ba593c0;p=openflowplugin.git diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/ConnectionConductorImplTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/ConnectionConductorImplTest.java index 84fc8bb82e..5d586ca12a 100644 --- a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/ConnectionConductorImplTest.java +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/ConnectionConductorImplTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -8,6 +8,9 @@ package org.opendaylight.openflowplugin.openflow.md.core; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; @@ -16,56 +19,61 @@ import java.util.List; import java.util.Map; import java.util.Stack; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.openflowplugin.api.OFConstants; +import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; +import org.opendaylight.openflowplugin.api.openflow.md.core.IMDMessageTranslator; +import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; +import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey; import org.opendaylight.openflowplugin.openflow.md.core.plan.ConnectionAdapterStackImpl; import org.opendaylight.openflowplugin.openflow.md.core.plan.EventFactory; import org.opendaylight.openflowplugin.openflow.md.core.plan.SwitchTestEvent; -import org.opendaylight.openflowplugin.openflow.md.core.session.SessionContext; -import org.opendaylight.openflowplugin.openflow.md.queue.PopListener; -import org.opendaylight.openflowplugin.openflow.md.queue.QueueKeeperLightImpl; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener; +import org.opendaylight.openflowplugin.openflow.md.queue.QueueProcessorLightImpl; +import org.opendaylight.openflowplugin.api.statistics.MessageSpy; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.Capabilities; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ErrorType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.HelloElementType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortFeaturesV10; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortReason; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessageBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessageBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.Elements; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.ElementsBuilder; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.Lists; - -/** - * @author mirehak - */ +@RunWith(MockitoJUnitRunner.class) public class ConnectionConductorImplTest { protected static final Logger LOG = LoggerFactory .getLogger(ConnectionConductorImplTest.class); - /** in [ms] */ + /** + * in [ms] + */ private final int maxProcessingTimeout = 500; - + protected ConnectionAdapterStackImpl adapter; private ConnectionConductorImpl connectionConductor; private MDController controller; @@ -75,9 +83,9 @@ public class ConnectionConductorImplTest { private ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor( 8); - private QueueKeeperLightImpl queueKeeper; + protected QueueProcessorLightImpl queueProcessor; - private PopListener popListener; + private PopListener popListener; private int experimenterMessageCounter; private int packetinMessageCounter; @@ -86,7 +94,14 @@ public class ConnectionConductorImplTest { private int portstatusDeleteMessageCounter; private int portstatusModifyMessageCounter; private int errorMessageCounter; - + + @Mock + private ErrorHandlerSimpleImpl errorHandler; + + private int expectedErrors = 0; + @Mock + private MessageSpy messageSpy; + public void incrExperimenterMessageCounter() { this.experimenterMessageCounter++; } @@ -115,6 +130,14 @@ public class ConnectionConductorImplTest { this.errorMessageCounter++; } + @Test + /** + * Test for ConnectionConductorFactory#createConductor + */ + public void testCreateConductor() { + ConnectionConductor connectionConductor = ConnectionConductorFactory.createConductor(adapter, queueProcessor); + assertNotNull(connectionConductor); + } /** * @throws java.lang.Exception @@ -122,25 +145,39 @@ public class ConnectionConductorImplTest { @Before public void setUp() throws Exception { adapter = new ConnectionAdapterStackImpl(); - + popListener = new PopListenerCountingImpl<>(); - - queueKeeper = new QueueKeeperLightImpl<>(); - queueKeeper.init(); - queueKeeper.addPopListener(popListener); - - connectionConductor = new ConnectionConductorImpl(adapter); - connectionConductor.setQueueKeeper(queueKeeper); - connectionConductor.init(); + controller = new MDController(); controller.init(); - queueKeeper.setListenerMapping(controller.getMessageListeners()); + controller.getMessageTranslators().putAll(assembleTranslatorMapping()); + + queueProcessor = new QueueProcessorLightImpl(); + queueProcessor.setMessageSpy(messageSpy); + queueProcessor.setPopListenersMapping(assemblePopListenerMapping()); + queueProcessor.setTranslatorMapping(controller.getMessageTranslators()); + queueProcessor.init(); + + connectionConductor = new ConnectionConductorImpl(adapter); + connectionConductor.setQueueProcessor(queueProcessor); + connectionConductor.setErrorHandler(errorHandler); + connectionConductor.init(); eventPlan = new Stack<>(); adapter.setEventPlan(eventPlan); adapter.setProceedTimeout(5000L); adapter.checkListeners(); - - controller.getMessageListeners().putAll(assembleListenerMapping()); + } + + /** + * @return + */ + private Map, Collection>> assemblePopListenerMapping() { + Map, Collection>> mapping = new HashMap<>(); + Collection> popListenerBag = new ArrayList<>(); + popListenerBag.add(popListener); + //TODO: add testing registered types + mapping.put(DataObject.class, popListenerBag); + return mapping; } /** @@ -151,8 +188,9 @@ public class ConnectionConductorImplTest { if (libSimulation != null) { libSimulation.join(); } - queueKeeper.shutdown(); - + queueProcessor.shutdown(); + connectionConductor.shutdownPool(); + for (Exception problem : adapter.getOccuredExceptions()) { LOG.error("during simulation on adapter side: " + problem.getMessage()); @@ -170,16 +208,30 @@ public class ConnectionConductorImplTest { Assert.assertTrue("plan is not finished", eventPlan.isEmpty()); eventPlan = null; controller = null; + + // logging errors if occurred + ArgumentCaptor errorCaptor = ArgumentCaptor.forClass(Throwable.class); + Mockito.verify(errorHandler, Mockito.atMost(1)).handleException( + errorCaptor.capture(), Matchers.any(SessionContext.class)); + for (Throwable problem : errorCaptor.getAllValues()) { + LOG.warn(problem.getMessage(), problem); + } + + Mockito.verify(errorHandler, Mockito.times(expectedErrors)).handleException( + Matchers.any(Throwable.class), Matchers.any(SessionContext.class)); } /** * Test method for * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onEchoRequestMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessage)} * . + * * @throws Exception */ @Test public void testOnEchoRequestMessage() throws Exception { + simulateV13PostHandshakeState(connectionConductor); + eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, EventFactory.DEFAULT_VERSION, new EchoRequestMessageBuilder())); eventPlan.add(0, @@ -188,29 +240,28 @@ public class ConnectionConductorImplTest { } /** - * Test of handshake, covering version negotiation and features . + * Test of handshake, covering version negotiation and features. + * Switch delivers first helloMessage with default version. + * * @throws Exception */ @Test public void testHandshake1() throws Exception { eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, EventFactory.DEFAULT_VERSION, new HelloMessageBuilder())); - eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder(); - getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060")); - getFeaturesOutputBuilder.setAuxiliaryId((short) 0); - getFeaturesOutputBuilder.setBuffers(4L); - getFeaturesOutputBuilder.setReserved(0L); - getFeaturesOutputBuilder.setTables((short) 2); - getFeaturesOutputBuilder.setCapabilities(createCapabilities(84)); - + eventPlan.add(0, EventFactory.createDefaultWaitForAllEvent( + EventFactory.createDefaultWaitForRpcEvent(43, "helloReply"), + EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures"))); eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(44, - EventFactory.DEFAULT_VERSION, getFeaturesOutputBuilder)); + EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); + + int i = 1; + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + executeNow(); - execute(true); Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING, connectionConductor.getConductorState()); Assert.assertEquals((short) 0x04, connectionConductor.getVersion() @@ -218,39 +269,66 @@ public class ConnectionConductorImplTest { } /** - * Test of handshake, covering version negotiation and features . + * Test of handshake, covering version negotiation and features. + * Controller sends first helloMessage with default version + * + * @throws Exception + */ + @Test + public void testHandshake1SwitchStarts() throws Exception { + eventPlan.add(0, EventFactory.createConnectionReadyCallback(connectionConductor)); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(21, "helloReply")); + eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, + EventFactory.DEFAULT_VERSION, new HelloMessageBuilder())); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "getFeatures")); + eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(43, + EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); + + int i = 1; + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); + + executeNow(); + + Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING, + connectionConductor.getConductorState()); + Assert.assertEquals((short) 0x04, connectionConductor.getVersion() + .shortValue()); + } + + /** + * Test of handshake, covering version negotiation and features. + * Switch delivers first helloMessage with version 0x05 + * and negotiates following versions: 0x03, 0x01 + * * @throws Exception */ @Test public void testHandshake2() throws Exception { + connectionConductor.setBitmapNegotiationEnable(false); eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, (short) 0x05, new HelloMessageBuilder())); eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); eventPlan.add(0, EventFactory.createDefaultNotificationEvent(43L, - (short) 0x01, new HelloMessageBuilder())); + (short) 0x03, new HelloMessageBuilder())); eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(44, "helloReply")); - // Commented : connection will terminate if hello message is sent again - // with not supported version -// eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L, -// (short) 0x01, new HelloMessageBuilder())); -// eventPlan.add(0, -// EventFactory.createDefaultWaitForRpcEvent(45, "helloReply")); + eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L, + (short) 0x01, new HelloMessageBuilder())); eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(45, "getFeatures")); - GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder(); - getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060")); - getFeaturesOutputBuilder.setAuxiliaryId((short) 0); - getFeaturesOutputBuilder.setBuffers(4L); - getFeaturesOutputBuilder.setReserved(0L); - getFeaturesOutputBuilder.setTables((short) 2); - getFeaturesOutputBuilder.setCapabilities(createCapabilities(84)); eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(45, - EventFactory.DEFAULT_VERSION, getFeaturesOutputBuilder)); + EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); + + int i = 1; + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); executeNow(); + Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING, connectionConductor.getConductorState()); Assert.assertEquals((short) 0x01, connectionConductor.getVersion() @@ -258,117 +336,64 @@ public class ConnectionConductorImplTest { } /** - * Test of handshake, covering version negotiation and features . + * Test of handshake, covering version negotiation and features. + * Controller sends first helloMessage with default version + * and switch negotiates following versions: 0x05, 0x03, 0x01 + * * @throws Exception */ @Test - public void testHandshake3() throws Exception { - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, - (short) 0x00, new HelloMessageBuilder())); - - executeNow(); - Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.HANDSHAKING, - connectionConductor.getConductorState()); - Assert.assertNull(connectionConductor.getVersion()); - } - - /** - * Test method for - * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onExperimenterMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage)} - * . - * @throws InterruptedException - */ - @Test - public void testOnExperimenterMessage1() throws InterruptedException { + public void testHandshake2SwitchStarts() throws Exception { + connectionConductor.setBitmapNegotiationEnable(false); + eventPlan.add(0, EventFactory.createConnectionReadyCallback(connectionConductor)); eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(42, "experimenter")); - ExperimenterMessageBuilder builder1 = new ExperimenterMessageBuilder(); - builder1.setExperimenter(84L).setExpType(4L); + EventFactory.createDefaultWaitForRpcEvent(21, "helloReply")); eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, - EventFactory.DEFAULT_VERSION, builder1)); - - executeLater(); - - Runnable sendExperimenterCmd = new Runnable() { - - @Override - public void run() { - ExperimenterInputBuilder builder2 = new ExperimenterInputBuilder(); - builder2.setExperimenter(84L).setExpType(4L); - EventFactory.setupHeader(42L, builder2); - adapter.experimenter(builder2.build()); - } - }; - pool.schedule(sendExperimenterCmd, - ConnectionAdapterStackImpl.JOB_DELAY, TimeUnit.MILLISECONDS); - } - - /** - * Test method for - * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onExperimenterMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage)} - * . - * @throws InterruptedException - */ - @Test - public void testOnExperimenterMessage2() throws InterruptedException { + (short) 0x05, new HelloMessageBuilder())); + eventPlan.add(0, EventFactory.createDefaultNotificationEvent(43L, + (short) 0x03, new HelloMessageBuilder())); eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(42, "experimenter")); - ErrorMessageBuilder builder1 = new ErrorMessageBuilder(); - builder1.setType(ErrorType.BADREQUEST).setCode(3) - .setData(new byte[] { 1, 2, 3 }); + EventFactory.createDefaultWaitForRpcEvent(44, "helloReply")); + eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L, + (short) 0x01, new HelloMessageBuilder())); + eventPlan.add(0, + EventFactory.createDefaultWaitForRpcEvent(45, "getFeatures")); - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, - EventFactory.DEFAULT_VERSION, builder1)); + eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(45, + EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - executeLater(); + int i = 1; + eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput")); - Runnable sendExperimenterCmd = new Runnable() { + executeNow(); - @Override - public void run() { - ExperimenterInputBuilder builder2 = new ExperimenterInputBuilder(); - builder2.setExperimenter(84L).setExpType(4L); - EventFactory.setupHeader(42L, builder2); - adapter.experimenter(builder2.build()); - } - }; - pool.schedule(sendExperimenterCmd, - ConnectionAdapterStackImpl.JOB_DELAY, TimeUnit.MILLISECONDS); + Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING, + connectionConductor.getConductorState()); + Assert.assertEquals((short) 0x01, connectionConductor.getVersion() + .shortValue()); } /** * Test method for * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onFlowRemovedMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage)} * . - * @throws InterruptedException + * + * @throws InterruptedException */ @Test public void testOnFlowRemovedMessage() throws InterruptedException { - IMDMessageListener objFms = new FlowRemovedMessageService() ; - controller.addMessageListener(FlowRemovedMessage.class, objFms); - - // Complete HandShake - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, - EventFactory.DEFAULT_VERSION, new HelloMessageBuilder())); - eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0,EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder(); - getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060")); - getFeaturesOutputBuilder.setAuxiliaryId((short) 0); - getFeaturesOutputBuilder.setBuffers(4L); - getFeaturesOutputBuilder.setReserved(0L); - getFeaturesOutputBuilder.setTables((short) 2); - getFeaturesOutputBuilder.setCapabilities(createCapabilities(84)); - eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(44, - EventFactory.DEFAULT_VERSION, getFeaturesOutputBuilder)); - execute(true); - + IMDMessageTranslator> objFms = new FlowRemovedMessageService(); + controller.addMessageTranslator(FlowRemovedMessage.class, 4, objFms); + + simulateV13PostHandshakeState(connectionConductor); + // Now send Flow Removed messages FlowRemovedMessageBuilder builder1 = new FlowRemovedMessageBuilder(); + builder1.setVersion((short) 4); builder1.setXid(1L); connectionConductor.onFlowRemovedMessage(builder1.build()); synchronized (popListener) { + LOG.debug("about to wait for popListener"); popListener.wait(maxProcessingTimeout); } Assert.assertEquals(1, flowremovedMessageCounter); @@ -391,54 +416,30 @@ public class ConnectionConductorImplTest { // TODO:: add test } - /** - * Test method for - * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onMultipartRequestMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestMessage)} - * . - */ - @Test - public void testOnMultipartRequestMessage() { - // fail("Not yet implemented"); - // TODO:: add test - } - /** * Test method for * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onPacketInMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage)} * . - * @throws InterruptedException + * + * @throws InterruptedException */ @Test public void testOnPacketInMessage() throws InterruptedException { - IMDMessageListener objPms = new PacketInMessageService() ; - controller.addMessageListener(PacketInMessage.class, objPms); - - // Complete HandShake - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, - EventFactory.DEFAULT_VERSION, new HelloMessageBuilder())); - eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0,EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder(); - getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060")); - getFeaturesOutputBuilder.setAuxiliaryId((short) 0); - getFeaturesOutputBuilder.setBuffers(4L); - getFeaturesOutputBuilder.setReserved(0L); - getFeaturesOutputBuilder.setTables((short) 2); - getFeaturesOutputBuilder.setCapabilities(createCapabilities(84)); - eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(44, - EventFactory.DEFAULT_VERSION, getFeaturesOutputBuilder)); - execute(true); - + IMDMessageTranslator> objPms = new PacketInMessageService(); + controller.addMessageTranslator(PacketInMessage.class, 4, objPms); + + simulateV13PostHandshakeState(connectionConductor); + // Now send PacketIn PacketInMessageBuilder builder1 = new PacketInMessageBuilder(); - builder1.setBufferId((long)1); + builder1.setVersion((short) 4); + builder1.setBufferId((long) 1); connectionConductor.onPacketInMessage(builder1.build()); synchronized (popListener) { popListener.wait(maxProcessingTimeout); } Assert.assertEquals(1, packetinMessageCounter); - builder1.setBufferId((long)2); + builder1.setBufferId((long) 2); connectionConductor.onPacketInMessage(builder1.build()); synchronized (popListener) { popListener.wait(maxProcessingTimeout); @@ -450,34 +451,20 @@ public class ConnectionConductorImplTest { * Test method for * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onPortStatusMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage)} * . - * @throws InterruptedException + * + * @throws InterruptedException */ @Test public void testOnPortStatusMessage() throws InterruptedException { - - IMDMessageListener objPSms = new PortStatusMessageService() ; - controller.addMessageListener(PortStatusMessage.class, objPSms); - - // Complete HandShake - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, - EventFactory.DEFAULT_VERSION, new HelloMessageBuilder())); - eventPlan.add(0, - EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0,EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder(); - getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060")); - getFeaturesOutputBuilder.setAuxiliaryId((short) 0); - getFeaturesOutputBuilder.setBuffers(4L); - getFeaturesOutputBuilder.setReserved(0L); - getFeaturesOutputBuilder.setTables((short) 2); - getFeaturesOutputBuilder.setCapabilities(createCapabilities(84)); - eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(44, - EventFactory.DEFAULT_VERSION, getFeaturesOutputBuilder)); - execute(true); - + IMDMessageTranslator> objPSms = new PortStatusMessageService(); + controller.addMessageTranslator(PortStatusMessage.class, 4, objPSms); + + simulateV13PostHandshakeState(connectionConductor); + // Send Port Status messages PortStatusMessageBuilder builder1 = new PortStatusMessageBuilder(); - PortFeatures features = new PortFeatures(true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false); + builder1.setVersion((short) 4); + PortFeatures features = new PortFeatures(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); builder1.setPortNo(90L).setReason(PortReason.OFPPRADD).setCurrentFeatures(features); connectionConductor.onPortStatusMessage(builder1.build()); synchronized (popListener) { @@ -498,34 +485,6 @@ public class ConnectionConductorImplTest { Assert.assertEquals(1, portstatusDeleteMessageCounter); } - /** - * Test method for - * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#proposeVersion(short)} - * . - */ - @Test - public void testProposeVersion() { - short[] remoteVer = new short[] { 0x05, 0x04, 0x03, 0x02, 0x01, 0x8f, - 0xff }; - short[] expectedProposal = new short[] { 0x04, 0x04, 0x01, 0x01, 0x01, - 0x04, 0x04 }; - - for (int i = 0; i < remoteVer.length; i++) { - short actualProposal = connectionConductor - .proposeVersion(remoteVer[i]); - Assert.assertEquals( - String.format("proposing for version: %04x", remoteVer[i]), - expectedProposal[i], actualProposal); - } - - try { - connectionConductor.proposeVersion((short) 0); - Assert.fail("there should be no proposition for this version"); - } catch (Exception e) { - // expected - } - } - /** * @throws InterruptedException */ @@ -538,6 +497,7 @@ public class ConnectionConductorImplTest { */ private void executeNow() throws InterruptedException { execute(true); + connectionConductor.shutdownPool(); } /** @@ -551,206 +511,7 @@ public class ConnectionConductorImplTest { } } - //////// Start - Version Negotiation Test ////////////// - - /** - * Test of version negotiation Where switch version = 1.0 - * - * @throws Exception - */ - @Test - public void testVersionNegotiation10() throws Exception { - Short version = (short) 0x01; - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42, version, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - eventPlan.add(0, - EventFactory.createDefaultRpcResponseEvent(44, EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - - executeNow(); - Assert.assertEquals(version, connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where switch version < 1.0 - * - * @throws Exception - */ - @Test - public void testVersionNegotiation00() throws Exception { - Short version = (short) 0x00; - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, version, new HelloMessageBuilder())); - executeNow(); - Assert.assertNull(connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where 1.0 < switch version < 1.3 - * - * @throws Exception - */ - @Test - public void testVersionNegotiation11() throws Exception { - Short version = (short) 0x02; - Short expVersion = (short) 0x01; - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, version, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - Assert.assertNull(connectionConductor.getVersion()); - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44, expVersion, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(45, "helloReply")); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(46, "getFeatures")); - eventPlan.add(0, - EventFactory.createDefaultRpcResponseEvent(46, EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - executeNow(); - Assert.assertEquals(expVersion, connectionConductor.getVersion()); - - } - - /** - * Test of version negotiation Where switch version = 1.3 - * - * @throws Exception - */ - @Test - public void testVersionNegotiation13() throws Exception { - Short version = (short) 0x04; - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, version, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - eventPlan.add(0, - EventFactory.createDefaultRpcResponseEvent(44, EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - - executeNow(); - Assert.assertEquals(version, connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where switch version >= 1.3 - * - * @throws Exception - */ - @Test - public void testVersionNegotiation15() throws Exception { - Short version = (short) 0x06; - Short expVersion = (short) 0x04; - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, version, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - Assert.assertNull(connectionConductor.getVersion()); - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44, expVersion, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(45, "helloReply")); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(46, "getFeatures")); - eventPlan.add(0, - EventFactory.createDefaultRpcResponseEvent(46, EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - executeNow(); - Assert.assertEquals(expVersion, connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where switch version > 1.3 - * - * @throws Exception - */ - @Test - public void testVersionNegotiation15_MultipleCall() throws Exception { - Short version = (short) 0x06; - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L, version, new HelloMessageBuilder())); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - Assert.assertNull(connectionConductor.getVersion()); - eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44, version, new HelloMessageBuilder())); - executeNow(); - // TODO : check for connection termination - Assert.assertNull(connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where bitmap version {0x05,0x01} - * - * @throws Exception - */ - @Test - public void testVersionNegotiation10InBitmap() throws Exception { - Short version = (short) 0x01; - eventPlan.add( - 0, - EventFactory.createDefaultNotificationEvent(42L, (short) 0x05, - getHelloBitmapMessage(Lists.newArrayList((short) 0x05, (short) 0x01)))); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - eventPlan.add(0, - EventFactory.createDefaultRpcResponseEvent(44, EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - - executeNow(); - Assert.assertEquals(version, connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where bitmap version {0x05,0x04} - * - * @throws Exception - */ - @Test - public void testVersionNegotiation13InBitmap() throws Exception { - Short version = (short) 0x04; - eventPlan.add( - 0, - EventFactory.createDefaultNotificationEvent(42L, (short) 0x05, - getHelloBitmapMessage(Lists.newArrayList((short) 0x05, (short) 0x04)))); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "helloReply")); - eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")); - eventPlan.add(0, - EventFactory.createDefaultRpcResponseEvent(44, EventFactory.DEFAULT_VERSION, getFeatureResponseMsg())); - - executeNow(); - Assert.assertEquals(version, connectionConductor.getVersion()); - } - - /** - * Test of version negotiation Where bitmap version {0x05,0x02} - * - * @throws Exception - */ - @Test - public void testVersionNegotiationNoCommonVersionInBitmap() throws Exception { - eventPlan.add( - 0, - EventFactory.createDefaultNotificationEvent(42L, (short) 0x05, - getHelloBitmapMessage(Lists.newArrayList((short) 0x05, (short) 0x02)))); - executeNow(); - Assert.assertNull(connectionConductor.getVersion()); - } - - private HelloMessageBuilder getHelloBitmapMessage(List versionOrder) { - short highestVersion = versionOrder.get(0); - int elementsCount = highestVersion / Integer.SIZE; - ElementsBuilder elementsBuilder = new ElementsBuilder(); - - List elementList = new ArrayList<>(); - int orderIndex = versionOrder.size(); - int value = versionOrder.get(--orderIndex); - for (int index = 0; index <= elementsCount; index++) { - List booleanList = new ArrayList<>(); - for (int i = 0; i < Integer.SIZE; i++) { - if (value == ((index * Integer.SIZE) + i)) { - booleanList.add(true); - value = (orderIndex == 0) ? highestVersion : versionOrder.get(--orderIndex); - } else { - booleanList.add(false); - } - } - elementsBuilder.setType(HelloElementType.forValue(1)); - elementsBuilder.setVersionBitmap(booleanList); - elementList.add(elementsBuilder.build()); - } - - HelloMessageBuilder builder = new HelloMessageBuilder(); - builder.setXid(10L); - builder.setVersion(highestVersion); - builder.setElements(elementList); - return builder; - - } - - private GetFeaturesOutputBuilder getFeatureResponseMsg() { + private static GetFeaturesOutputBuilder getFeatureResponseMsg() { GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder(); getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060")); getFeaturesOutputBuilder.setAuxiliaryId((short) 0); @@ -777,87 +538,71 @@ public class ConnectionConductorImplTest { PORT_BLOCKED, PORT_STATS, QUEUE_STATS, TABLE_STATS); return capabilities; } - - public class ExperimenterMessageService implements IMDMessageListener { + + public class ExperimenterMessageService implements IMDMessageTranslator> { @Override - public void receive(SwitchConnectionDistinguisher cookie, SessionContext sw, DataObject msg) { + public List translate(SwitchConnectionDistinguisher cookie, SessionContext sw, OfHeader msg) { LOG.debug("Received a packet in Experimenter Service"); ConnectionConductorImplTest.this.incrExperimenterMessageCounter(); - + return null; } } - public class PacketInMessageService implements IMDMessageListener { + public class PacketInMessageService implements IMDMessageTranslator> { @Override - public void receive(SwitchConnectionDistinguisher cookie, SessionContext sw, DataObject msg) { + public List translate(SwitchConnectionDistinguisher cookie, SessionContext sw, OfHeader msg) { LOG.debug("Received a packet in PacketIn Service"); ConnectionConductorImplTest.this.incrPacketinMessageCounter(); + return null; } } - public class FlowRemovedMessageService implements IMDMessageListener { + public class FlowRemovedMessageService implements IMDMessageTranslator> { @Override - public void receive(SwitchConnectionDistinguisher cookie, SessionContext sw, DataObject msg) { + public List translate(SwitchConnectionDistinguisher cookie, SessionContext sw, OfHeader msg) { LOG.debug("Received a packet in FlowRemoved Service"); ConnectionConductorImplTest.this.incrFlowremovedMessageCounter(); + return null; } } - public class PortStatusMessageService implements IMDMessageListener { + public class PortStatusMessageService implements IMDMessageTranslator> { @Override - public void receive(SwitchConnectionDistinguisher cookie, SessionContext sw, DataObject msg) { + public List translate(SwitchConnectionDistinguisher cookie, SessionContext sw, OfHeader msg) { LOG.debug("Received a packet in PortStatus Service"); - if ( (((PortStatusMessage)msg).getReason().equals(PortReason.OFPPRADD)) ) { + if ((((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRADD))) { ConnectionConductorImplTest.this.incrPortstatusAddMessageCounter(); - } else if (((PortStatusMessage)msg).getReason().equals(PortReason.OFPPRDELETE)){ + } else if (((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRDELETE)) { ConnectionConductorImplTest.this.incrPortstatusDeleteMessageCounter(); - } else if (((PortStatusMessage)msg).getReason().equals(PortReason.OFPPRMODIFY)) { + } else if (((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRMODIFY)) { ConnectionConductorImplTest.this.incrPortstatusModifyMessageCounter(); } + return null; } } - - public class ErrorMessageService implements IMDMessageListener { + + public class ErrorMessageService implements IMDMessageTranslator> { @Override - public void receive(SwitchConnectionDistinguisher cookie, SessionContext sw, DataObject msg) { + public List translate(SwitchConnectionDistinguisher cookie, SessionContext sw, OfHeader msg) { LOG.debug("Received a packet in Experimenter Service"); ConnectionConductorImplTest.this.incrErrorMessageCounter(); + return null; } } - /** - * Test method for - * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onExperimenterMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage)} - * . - * @throws InterruptedException - */ - @Test - public void testOnExperimenterMessage() throws InterruptedException { - ExperimenterMessageBuilder builder1 = new ExperimenterMessageBuilder(); - builder1.setExperimenter(84L).setExpType(4L); - connectionConductor.onExperimenterMessage(builder1.build()); - synchronized (popListener) { - popListener.wait(maxProcessingTimeout); - } - Assert.assertEquals(1, experimenterMessageCounter); - - builder1.setExperimenter(85L).setExpType(4L); - connectionConductor.onExperimenterMessage(builder1.build()); - synchronized (popListener) { - popListener.wait(maxProcessingTimeout); - } - Assert.assertEquals(2, experimenterMessageCounter); - } - /** * Test method for * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onExperimenterMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage)} * . + * * @throws InterruptedException */ @Test public void testOnErrorMessage() throws InterruptedException { + simulateV13PostHandshakeState(connectionConductor); + ErrorMessageBuilder builder1 = new ErrorMessageBuilder(); + builder1.setVersion((short) 4); builder1.setCode(100); connectionConductor.onErrorMessage(builder1.build()); synchronized (popListener) { @@ -873,22 +618,96 @@ public class ConnectionConductorImplTest { } /** - * @return listener mapping for : + * @return listener mapping for: *
    *
  • experimenter
  • *
  • error
  • *
*/ - private Map, Collection> assembleListenerMapping() { - IMDMessageListener objEms = new ExperimenterMessageService() ; - Map, Collection> listenerMapping = new HashMap<>(); - Collection existingValues = new ArrayList<>(); + private Map>>> assembleTranslatorMapping() { + Map>>> translatorMapping = new HashMap<>(); + TranslatorKey tKey; + + IMDMessageTranslator> objEms = new ExperimenterMessageService(); + Collection>> existingValues = new ArrayList<>(); existingValues.add(objEms); - listenerMapping.put(ExperimenterMessage.class, existingValues); - IMDMessageListener objErms = new ErrorMessageService() ; + tKey = new TranslatorKey(4, ExperimenterMessage.class.getName()); + translatorMapping.put(tKey, existingValues); + IMDMessageTranslator> objErms = new ErrorMessageService(); existingValues.add(objErms); - listenerMapping.put(ErrorMessage.class, existingValues); - return listenerMapping; + tKey = new TranslatorKey(4, ErrorMessage.class.getName()); + translatorMapping.put(tKey, existingValues); + return translatorMapping; + } + + /** + * Test method for + * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#processPortStatusMsg(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage)} + *

+ * Tests for getting features from port status message by port version + *
    + *
  • features are malformed - one of them is null
  • + *
  • mismatch between port version and port features
  • + *
  • mismatch between port version and port features
  • + *
  • non-existing port version
  • + *
  • port version OF 1.0
  • + *
  • port version OF 1.3
  • + *
+ */ + @Test + public void testProcessPortStatusMsg() { + simulateV13PostHandshakeState(connectionConductor); + + long portNumber = 90L; + long portNumberV10 = 91L; + PortStatusMessage msg; + + PortStatusMessageBuilder builder = new PortStatusMessageBuilder(); + PortFeatures features = new PortFeatures(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); + PortFeatures featuresMal = new PortFeatures(true, false, false, false, null, false, false, false, false, false, false, false, false, false, false, false); + PortFeaturesV10 featuresV10 = new PortFeaturesV10(true, false, false, false, false, false, false, false, false, false, false, false); + + //Malformed features + builder.setVersion((short) 1).setPortNo(portNumber).setReason(PortReason.OFPPRADD).setCurrentFeatures(featuresMal); + connectionConductor.processPortStatusMsg(builder.build()); + Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty()); + Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty()); + + //Version-features mismatch + builder.setCurrentFeatures(features); + connectionConductor.processPortStatusMsg(builder.build()); + Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty()); + Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty()); + + //Non existing version + builder.setVersion((short) 0); + connectionConductor.processPortStatusMsg(builder.build()); + Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty()); + Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty()); + + //Version OF 1.3 + builder.setVersion((short) 4); + msg = builder.build(); + connectionConductor.processPortStatusMsg(builder.build()); + Assert.assertTrue(connectionConductor.getSessionContext().getPortBandwidth(portNumber)); + Assert.assertEquals(connectionConductor.getSessionContext().getPhysicalPort(portNumber), msg); + + //Version OF 1.0 + builder.setVersion((short) 1).setPortNo(portNumberV10).setCurrentFeatures(null).setCurrentFeaturesV10(featuresV10); + msg = builder.build(); + connectionConductor.processPortStatusMsg(builder.build()); + Assert.assertTrue(connectionConductor.getSessionContext().getPortBandwidth(portNumberV10)); + Assert.assertEquals(connectionConductor.getSessionContext().getPhysicalPort(portNumberV10), msg); } + + @Test + public void testHandshakeFailOperations(){ + connectionConductor.onHandshakeFailure(); + connectionConductor.checkState(ConnectionConductor.CONDUCTOR_STATE.RIP); + } + private void simulateV13PostHandshakeState(ConnectionConductorImpl conductor) { + GetFeaturesOutputBuilder featureOutput = getFeatureResponseMsg(); + conductor.postHandshakeBasic(featureOutput.build(), OFConstants.OFP_VERSION_1_3); + } }