Async config message 22/59522/17
authormiroslav.macko <miroslav.macko@pantheon.tech>
Mon, 19 Jun 2017 14:29:27 +0000 (16:29 +0200)
committerTomas Slusny <tomas.slusny@pantheon.tech>
Mon, 25 Sep 2017 09:45:47 +0000 (11:45 +0200)
- Add support for async config message
  (Supported from version 1.3)

Resolves: bug 4082

Change-Id: Iae32e8a7433610d689c3d6b7a1c440032c3f2cc6
Signed-off-by: miroslav.macko <miroslav.macko@pantheon.tech>
15 files changed:
model/model-flow-service/src/main/yang/sal-async-config.yang [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MessageDeserializerInjector.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/AsyncConfigMessageDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/MessageSerializerInjector.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/AsyncConfigMessageSerializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/SalAsyncConfigServiceImpl.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/singlelayer/SingleLayerGetAsyncConfigService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/singlelayer/SingleLayerSetAsyncConfigService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/AsyncConfigMessageSerializerTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/FlowCapableTransactionServiceImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/PacketProcessingServiceImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/SalAsyncConfigServiceImplTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/convertor/ConvertorManagerFactory.java

diff --git a/model/model-flow-service/src/main/yang/sal-async-config.yang b/model/model-flow-service/src/main/yang/sal-async-config.yang
new file mode 100644 (file)
index 0000000..caf6ab8
--- /dev/null
@@ -0,0 +1,102 @@
+module sal-async-config {
+    namespace "urn:opendaylight:async-config:service";
+    prefix async-config;
+
+    import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+    import opendaylight-port-types {prefix port-type;revision-date "2013-09-25";}
+    import opendaylight-flow-types  { prefix flow-types;  revision-date "2013-10-26"; }
+    import openflow-protocol { prefix ofproto; revision-date "2013-07-31"; }
+    import packet-processing  { prefix packet-processing;  revision-date "2013-07-09"; }
+
+    description "Asynchronous configuration message.";
+
+    revision "2017-06-19" {
+        description "Initial revision of asynchronous configuration service.";
+    }
+
+    typedef packet-in-mask {
+        type bits {
+            bit NO_MATCH;
+            bit ACTION;
+            bit INVALID_TTL;
+        }
+    }
+
+    typedef port-status-mask {
+        description "Be careful when modifying this configuration, as this can impact lldp-speaker";
+        type bits {
+            bit ADD;
+            bit DELETE;
+            bit UPDATE;
+        }
+    }
+
+    typedef flow-removed-mask {
+        description "Be careful when modifying this configuration, as this can impact FRM.";
+        type bits {
+            bit IDLE_TIMEOUT;
+            bit HARD_TIMEOUT;
+            bit DELETE;
+            bit GROUP_DELETE;
+        }
+     }
+
+    grouping async-config {
+        container packet-in-mask {
+            leaf master-mask {
+                type packet-in-mask;
+            }
+
+            leaf slave-mask {
+                type packet-in-mask;
+            }
+        }
+
+        container port-status-mask {
+            leaf master-mask {
+                type port-status-mask;
+            }
+
+            leaf slave-mask {
+                type port-status-mask;
+            }
+        }
+
+        container flow-removed-mask {
+            leaf master-mask {
+                type flow-removed-mask;
+            }
+
+            leaf slave-mask {
+                type flow-removed-mask;
+            }
+        }
+    }
+
+    container async-config-message {
+        uses ofproto:ofHeader;
+        uses async-config;
+    }
+
+    rpc set-async {
+        description "Controller to switch message set configuration.";
+
+        input {
+            uses "inv:node-context-ref";
+            uses async-config;
+        }
+    }
+
+    rpc get-async {
+        description "Controller to switch message get configuration.";
+
+        input {
+            uses "inv:node-context-ref";
+        }
+
+        output {
+            uses async-config;
+        }
+    }
+
+}
\ No newline at end of file
index 3ad3e8e9e5a3e680d4fe62e692de62fee4b9685d..01cddf221888ac572a06658545dc9dd4a89a4fc6 100644 (file)
@@ -17,11 +17,14 @@ import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
 import org.opendaylight.openflowjava.protocol.api.keys.TypeToClassKey;
 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
 import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.FlowMessageDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.AsyncConfigMessageDeserializer;
 import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.GroupMessageDeserializer;
 import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.MeterMessageDeserializer;
 import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.PacketInMessageDeserializer;
 import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.PortMessageDeserializer;
 import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyMessageDeserializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupMessage;
@@ -51,6 +54,7 @@ class MessageDeserializerInjector {
         injector.apply(10).apply(org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709
                 .PacketInMessage.class).accept(new PacketInMessageDeserializer());
         injector.apply(19).apply(MultipartReply.class).accept(new MultipartReplyMessageDeserializer());
+        injector.apply(27).apply(AsyncConfigMessage.class).accept(new AsyncConfigMessageDeserializer());
     }
 
     /**
@@ -66,6 +70,9 @@ class MessageDeserializerInjector {
         provider.unregisterDeserializerMapping(new TypeToClassKey(EncodeConstants.OF13_VERSION_ID, 19));
         provider.registerDeserializerMapping(new TypeToClassKey(EncodeConstants.OF13_VERSION_ID, 19),
                 MultipartReplyMessage.class);
+        provider.unregisterDeserializerMapping(new TypeToClassKey(EncodeConstants.OF13_VERSION_ID, 27));
+        provider.registerDeserializerMapping(new TypeToClassKey(EncodeConstants.OF13_VERSION_ID, 27),
+                GetAsyncOutput.class);
     }
 
     /**
@@ -78,7 +85,7 @@ class MessageDeserializerInjector {
      */
     @VisibleForTesting
     static Function<Integer, Function<Class<? extends OfHeader>, Consumer<OFDeserializer<? extends OfHeader>>>>
-        createInjector(
+    createInjector(
             final DeserializerExtensionProvider provider,
             final short version) {
         return code -> retType -> deserializer -> {
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/AsyncConfigMessageDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/AsyncConfigMessageDeserializer.java
new file mode 100644 (file)
index 0000000..f79d9b6
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.messages;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.FlowRemovedMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.PacketInMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.PortStatusMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.async.config.FlowRemovedMaskBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.async.config.PacketInMaskBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.async.config.PortStatusMaskBuilder;
+
+public class AsyncConfigMessageDeserializer implements OFDeserializer<AsyncConfigMessage> {
+    @Override
+    public AsyncConfigMessage deserialize(ByteBuf message) {
+        return new AsyncConfigMessageBuilder()
+                .setVersion((short) EncodeConstants.OF13_VERSION_ID)
+                .setXid(message.readUnsignedInt())
+                .setPacketInMask(new PacketInMaskBuilder()
+                        .setMasterMask(deserializePacketInMask(message))
+                        .setSlaveMask(deserializePacketInMask(message))
+                        .build())
+                .setPortStatusMask(new PortStatusMaskBuilder()
+                        .setMasterMask(deserializePortStatusMask(message))
+                        .setSlaveMask(deserializePortStatusMask(message))
+                        .build())
+                .setFlowRemovedMask(new FlowRemovedMaskBuilder()
+                        .setMasterMask(deserializeFlowRemovedMask(message))
+                        .setSlaveMask(deserializeFlowRemovedMask(message))
+                        .build())
+                .build();
+    }
+
+    private static PacketInMask deserializePacketInMask(final ByteBuf byteBuf) {
+        final long mask = byteBuf.readUnsignedInt();
+        final boolean isNoMatch = (mask & (1)) != 0;
+        final boolean isAction = (mask & (1 << 1)) != 0;
+        final boolean isInvalidTtl = (mask & (1 << 2)) != 0;
+        return new PacketInMask(isAction, isInvalidTtl, isNoMatch);
+    }
+
+    private static PortStatusMask deserializePortStatusMask(final ByteBuf byteBuf) {
+        final long mask = byteBuf.readUnsignedInt();
+        final boolean isAdd = (mask & (1)) != 0;
+        final boolean isDelete = (mask & (1 << 1)) != 0;
+        final boolean isModify = (mask & (1 << 2)) != 0;
+        return new PortStatusMask(isAdd, isDelete, isModify);
+    }
+
+    private static FlowRemovedMask deserializeFlowRemovedMask(final ByteBuf byteBuf) {
+        final long mask = byteBuf.readUnsignedInt();
+        final boolean isIdleTimeout = (mask & (1)) != 0;
+        final boolean isHardTimeout = (mask & (1 << 1)) != 0;
+        final boolean isDelete = (mask & (1 << 2)) != 0;
+        final boolean isGroupDelete = (mask & (1 << 3)) != 0;
+        return new FlowRemovedMask(isDelete, isGroupDelete, isHardTimeout, isIdleTimeout);
+    }
+}
\ No newline at end of file
index 0b31b2b049179475d3009834372948a248f29072..ff1c57ad073b196e6c6aebd837c51f731c508ee2 100644 (file)
@@ -15,11 +15,13 @@ import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
 import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerExtensionProvider;
 import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.AsyncConfigMessageSerializer;
 import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.FlowMessageSerializer;
 import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.GroupMessageSerializer;
 import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.MeterMessageSerializer;
 import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.PortMessageSerializer;
 import org.opendaylight.openflowplugin.impl.protocol.serialization.multipart.MultipartRequestMessageSerializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupMessage;
@@ -48,6 +50,7 @@ class MessageSerializerInjector {
         injector.apply(PortMessage.class).accept(new PortMessageSerializer());
         injector.apply(GroupMessage.class).accept(new GroupMessageSerializer());
         injector.apply(MultipartRequest.class).accept(new MultipartRequestMessageSerializer());
+        injector.apply(AsyncConfigMessage.class).accept(new AsyncConfigMessageSerializer());
     }
 
     /**
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/AsyncConfigMessageSerializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/AsyncConfigMessageSerializer.java
new file mode 100644 (file)
index 0000000..46a8512
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.serialization.messages;
+
+import io.netty.buffer.ByteBuf;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.WeakHashMap;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.FlowRemovedMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.PacketInMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.PortStatusMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowRemovedReason;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PacketInReason;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortReason;
+
+public class AsyncConfigMessageSerializer extends AbstractMessageSerializer<AsyncConfigMessage> {
+    @Override
+    public void serialize(AsyncConfigMessage message, ByteBuf outBuffer) {
+        final int index = outBuffer.writerIndex();
+        super.serialize(message, outBuffer);
+
+        Optional.ofNullable(message.getPacketInMask())
+                .ifPresent(mask -> {
+                    serializePacketInMask(mask.getMasterMask(), outBuffer);
+                    serializePacketInMask(mask.getSlaveMask(), outBuffer);
+                });
+
+        Optional.ofNullable(message.getPortStatusMask())
+                .ifPresent(mask -> {
+                    serializePortStatusMask(mask.getMasterMask(), outBuffer);
+                    serializePortStatusMask(mask.getSlaveMask(), outBuffer);
+                });
+
+        Optional.ofNullable(message.getFlowRemovedMask())
+                .ifPresent(mask -> {
+                    serializeFlowRemovedMask(mask.getMasterMask(), outBuffer);
+                    serializeFlowRemovedMask(mask.getSlaveMask(), outBuffer);
+                });
+
+        outBuffer.setShort(index + 2, outBuffer.writerIndex() - index);
+    }
+
+    @Override
+    protected byte getMessageType() {
+        return 28;
+    }
+
+    private static void serializePacketInMask(final PacketInMask mask, final ByteBuf outBuffer) {
+        if (Objects.isNull(mask)) {
+            return;
+        }
+
+        final Map<Integer, Boolean> map = new WeakHashMap<>();
+
+        if (mask.isNOMATCH()) {
+            map.put(PacketInReason.OFPRNOMATCH.getIntValue(), true);
+        }
+
+        if (mask.isACTION()) {
+            map.put(PacketInReason.OFPRACTION.getIntValue(), true);
+        }
+
+        if (mask.isINVALIDTTL()) {
+            map.put(PacketInReason.OFPRINVALIDTTL.getIntValue(), true);
+        }
+
+        outBuffer.writeInt(ByteBufUtils.fillBitMaskFromMap(map));
+    }
+
+    private static void serializePortStatusMask(final PortStatusMask mask, final ByteBuf outBuffer) {
+        if (Objects.isNull(mask)) {
+            return;
+        }
+
+        final Map<Integer, Boolean> map = new WeakHashMap<>();
+
+        if (mask.isADD()) {
+            map.put(PortReason.OFPPRADD.getIntValue(), true);
+        }
+
+        if (mask.isDELETE()) {
+            map.put(PortReason.OFPPRDELETE.getIntValue(), true);
+        }
+
+        if (mask.isUPDATE()) {
+            map.put(PortReason.OFPPRMODIFY.getIntValue(), true);
+        }
+
+        outBuffer.writeInt(ByteBufUtils.fillBitMaskFromMap(map));
+    }
+
+    private static void serializeFlowRemovedMask(final FlowRemovedMask mask, final ByteBuf outBuffer) {
+        if (Objects.isNull(mask)) {
+            return;
+        }
+
+        final Map<Integer, Boolean> map = new WeakHashMap<>();
+
+        if (mask.isIDLETIMEOUT()) {
+            map.put(FlowRemovedReason.OFPRRIDLETIMEOUT.getIntValue(), true);
+        }
+
+        if (mask.isHARDTIMEOUT()) {
+            map.put(FlowRemovedReason.OFPRRHARDTIMEOUT.getIntValue(), true);
+        }
+
+        if (mask.isDELETE()) {
+            map.put(FlowRemovedReason.OFPRRDELETE.getIntValue(), true);
+        }
+
+        if (mask.isGROUPDELETE()) {
+            map.put(FlowRemovedReason.OFPRRGROUPDELETE.getIntValue(), true);
+        }
+
+        outBuffer.writeInt(ByteBufUtils.fillBitMaskFromMap(map));
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/SalAsyncConfigServiceImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/SalAsyncConfigServiceImpl.java
new file mode 100644 (file)
index 0000000..984aa32
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.services.sal;
+
+import com.google.common.util.concurrent.Futures;
+import java.util.Objects;
+import java.util.concurrent.Future;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.impl.services.singlelayer.SingleLayerGetAsyncConfigService;
+import org.opendaylight.openflowplugin.impl.services.singlelayer.SingleLayerSetAsyncConfigService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.SalAsyncConfigService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.SetAsyncInput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+public class SalAsyncConfigServiceImpl implements SalAsyncConfigService {
+
+    private final SingleLayerSetAsyncConfigService setAsyncConfigService;
+    private final SingleLayerGetAsyncConfigService getAsyncConfigService;
+
+    public SalAsyncConfigServiceImpl(final RequestContextStack requestContextStack, final DeviceContext deviceContext) {
+        setAsyncConfigService = new SingleLayerSetAsyncConfigService(requestContextStack, deviceContext);
+        getAsyncConfigService = new SingleLayerGetAsyncConfigService(requestContextStack, deviceContext);
+    }
+
+    @Override
+    public Future<RpcResult<Void>> setAsync(SetAsyncInput input) {
+        return setAsyncConfigService.handleServiceCall(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetAsyncOutput>> getAsync(GetAsyncInput input) {
+        return Futures.transform(getAsyncConfigService.handleServiceCall(input), result ->
+                Objects.nonNull(result) && result.isSuccessful()
+                        ? RpcResultBuilder.success(new GetAsyncOutputBuilder(result.getResult())).build()
+                        : RpcResultBuilder.<GetAsyncOutput>failed().build());
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/singlelayer/SingleLayerGetAsyncConfigService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/singlelayer/SingleLayerGetAsyncConfigService.java
new file mode 100644 (file)
index 0000000..2cc0a79
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.services.singlelayer;
+
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.impl.services.AbstractSimpleService;
+import org.opendaylight.openflowplugin.impl.services.util.ServiceException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+
+public class SingleLayerGetAsyncConfigService extends AbstractSimpleService<GetAsyncInput, AsyncConfigMessage> {
+
+    public SingleLayerGetAsyncConfigService(final RequestContextStack requestContextStack, final DeviceContext deviceContext) {
+        super(requestContextStack, deviceContext, AsyncConfigMessage.class);
+    }
+
+    @Override
+    protected OfHeader buildRequest(Xid xid, GetAsyncInput input) throws ServiceException {
+        return new GetAsyncInputBuilder()
+                .setVersion(getVersion())
+                .setXid(xid.getValue())
+                .build();
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/singlelayer/SingleLayerSetAsyncConfigService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/singlelayer/SingleLayerSetAsyncConfigService.java
new file mode 100644 (file)
index 0000000..b4ab33a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.services.singlelayer;
+
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.impl.services.AbstractVoidService;
+import org.opendaylight.openflowplugin.impl.services.util.ServiceException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.SetAsyncInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+
+public class SingleLayerSetAsyncConfigService extends AbstractVoidService<SetAsyncInput> {
+
+    public SingleLayerSetAsyncConfigService(final RequestContextStack requestContextStack,
+                                            final DeviceContext deviceContext) {
+        super(requestContextStack, deviceContext);
+    }
+
+    @Override
+    protected OfHeader buildRequest(Xid xid, SetAsyncInput input) throws ServiceException {
+        return new AsyncConfigMessageBuilder(input)
+                .setVersion(getVersion())
+                .setXid(xid.getValue())
+                .build();
+    }
+}
index 767997a89bf8c2514c48e1e30f49d84a1c2f85e2..ba282fa020940bcaa1c7c022a4eed9ece1922e76 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.openflowplugin.impl.datastore.MultipartWriterProviderFac
 import org.opendaylight.openflowplugin.impl.services.sal.FlowCapableTransactionServiceImpl;
 import org.opendaylight.openflowplugin.impl.services.sal.NodeConfigServiceImpl;
 import org.opendaylight.openflowplugin.impl.services.sal.PacketProcessingServiceImpl;
+import org.opendaylight.openflowplugin.impl.services.sal.SalAsyncConfigServiceImpl;
 import org.opendaylight.openflowplugin.impl.services.sal.SalBundleServiceImpl;
 import org.opendaylight.openflowplugin.impl.services.sal.SalEchoServiceImpl;
 import org.opendaylight.openflowplugin.impl.services.sal.SalExperimenterMessageServiceImpl;
@@ -44,6 +45,7 @@ import org.opendaylight.openflowplugin.impl.statistics.services.direct.Opendayli
 import org.opendaylight.openflowplugin.impl.statistics.services.direct.multilayer.MultiLayerDirectStatisticsProviderInitializer;
 import org.opendaylight.openflowplugin.impl.statistics.services.direct.singlelayer.SingleLayerDirectStatisticsProviderInitializer;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.SalAsyncConfigService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.echo.service.rev150305.SalEchoService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.message.service.rev151020.SalExperimenterMessageService;
@@ -96,6 +98,8 @@ public class MdSalRegistrationUtils {
         final SalFlowServiceImpl salFlowService = new SalFlowServiceImpl(rpcContext, deviceContext, convertorExecutor);
         final FlowCapableTransactionServiceImpl flowCapableTransactionService =
                 new FlowCapableTransactionServiceImpl(rpcContext, deviceContext);
+        final SalAsyncConfigServiceImpl salAsyncConfigService =
+                new SalAsyncConfigServiceImpl(rpcContext, deviceContext);
         final SalGroupServiceImpl salGroupService =
                 new SalGroupServiceImpl(rpcContext, deviceContext, convertorExecutor);
         final SalMeterServiceImpl salMeterService =
@@ -106,6 +110,7 @@ public class MdSalRegistrationUtils {
                 new SalEchoServiceImpl(rpcContext, deviceContext));
         rpcContext.registerRpcServiceImplementation(SalFlowService.class, salFlowService);
         rpcContext.registerRpcServiceImplementation(FlowCapableTransactionService.class, flowCapableTransactionService);
+        rpcContext.registerRpcServiceImplementation(SalAsyncConfigService.class, salAsyncConfigService);
         rpcContext.registerRpcServiceImplementation(SalMeterService.class, salMeterService);
         rpcContext.registerRpcServiceImplementation(SalGroupService.class, salGroupService);
         rpcContext.registerRpcServiceImplementation(SalTableService.class,
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/AsyncConfigMessageSerializerTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/AsyncConfigMessageSerializerTest.java
new file mode 100644 (file)
index 0000000..77bb13f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.serialization.messages;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableMap;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import org.junit.Test;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.AbstractSerializerTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.AsyncConfigMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.FlowRemovedMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.PacketInMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.PortStatusMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.async.config.FlowRemovedMaskBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.async.config.PacketInMaskBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.async.config.PortStatusMaskBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowRemovedReason;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PacketInReason;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortReason;
+
+public class AsyncConfigMessageSerializerTest extends AbstractSerializerTest {
+
+    private static final short LENGTH = 32;
+    private static final Long XID = 42L;
+    private static final short VERSION = EncodeConstants.OF13_VERSION_ID;
+
+    // Packet in mask
+    private static final Boolean MASTER_IS_NOMATCH = true;
+    private static final Boolean MASTER_IS_ACTION = false;
+    private static final Boolean MASTER_IS_INVALID_TTL= false;
+    private static final Boolean SLAVE_IS_NOMATCH = false;
+    private static final Boolean SLAVE_IS_ACTION = false;
+    private static final Boolean SLAVE_IS_INVALID_TTL= false;
+
+    // Port status mask
+    private static final Boolean MASTER_IS_ADD = false;
+    private static final Boolean MASTER_IS_DELETE = false;
+    private static final Boolean MASTER_IS_MODIFY = false;
+    private static final Boolean SLAVE_IS_ADD = false;
+    private static final Boolean SLAVE_IS_DELETE = false;
+    private static final Boolean SLAVE_IS_MODIFY = false;
+
+    // Flow removed mask
+    private static final Boolean MASTER_IS_IDLETIMEOUT = false;
+    private static final Boolean MASTER_IS_HARDTIMEOUT = false;
+    private static final Boolean MASTER_IS_FLOWDELETE = false;
+    private static final Boolean MASTER_IS_GROUPDELETE = false;
+    private static final Boolean SLAVE_IS_IDLETIMEOUT = false;
+    private static final Boolean SLAVE_IS_HARDTIMEOUT = false;
+    private static final Boolean SLAVE_IS_FLOWDELETE = false;
+    private static final Boolean SLAVE_IS_GROUPDELETE = false;
+
+    private static final AsyncConfigMessage MESSAGE = new AsyncConfigMessageBuilder()
+            .setXid(XID)
+            .setVersion(VERSION)
+            .setPacketInMask(new PacketInMaskBuilder()
+                    .setMasterMask(new PacketInMask(MASTER_IS_ACTION, MASTER_IS_INVALID_TTL, MASTER_IS_NOMATCH))
+                    .setSlaveMask(new PacketInMask(SLAVE_IS_ACTION, SLAVE_IS_INVALID_TTL, SLAVE_IS_NOMATCH))
+                    .build())
+            .setPortStatusMask(new PortStatusMaskBuilder()
+                    .setMasterMask(new PortStatusMask(MASTER_IS_ADD, MASTER_IS_DELETE, MASTER_IS_MODIFY))
+                    .setSlaveMask(new PortStatusMask(SLAVE_IS_ADD, SLAVE_IS_DELETE, SLAVE_IS_MODIFY))
+                    .build())
+            .setFlowRemovedMask(new FlowRemovedMaskBuilder()
+                    .setMasterMask(new FlowRemovedMask(MASTER_IS_FLOWDELETE, MASTER_IS_GROUPDELETE,
+                            MASTER_IS_HARDTIMEOUT, MASTER_IS_IDLETIMEOUT))
+                    .setSlaveMask(new FlowRemovedMask(SLAVE_IS_FLOWDELETE, SLAVE_IS_GROUPDELETE,
+                            SLAVE_IS_HARDTIMEOUT, SLAVE_IS_IDLETIMEOUT))
+                    .build())
+            .build();
+
+    private AsyncConfigMessageSerializer serializer;
+
+    @Override
+    protected void init() {
+        serializer = getRegistry()
+                .getSerializer(new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, AsyncConfigMessage.class));
+    }
+
+    @Test
+    public void testSerialize() throws Exception {
+        final ByteBuf out = UnpooledByteBufAllocator.DEFAULT.buffer();
+        serializer.serialize(MESSAGE, out);
+
+        // Header
+        assertEquals(out.readByte(), VERSION);
+        assertEquals(out.readByte(), serializer.getMessageType());
+        assertEquals(out.readShort(), LENGTH);
+        assertEquals(out.readInt(), XID.intValue());
+
+        // Packet in master
+        assertEquals(out.readInt(), ByteBufUtils.fillBitMaskFromMap(ImmutableMap
+                .<Integer, Boolean>builder()
+                .put(PacketInReason.OFPRNOMATCH.getIntValue(), MASTER_IS_NOMATCH)
+                .put(PacketInReason.OFPRACTION.getIntValue(), MASTER_IS_ACTION)
+                .put(PacketInReason.OFPRINVALIDTTL.getIntValue(), MASTER_IS_INVALID_TTL)
+                .build()));
+
+        // Packet in slave
+        assertEquals(out.readInt(), ByteBufUtils.fillBitMaskFromMap(ImmutableMap
+                .<Integer, Boolean>builder()
+                .put(PacketInReason.OFPRNOMATCH.getIntValue(), SLAVE_IS_NOMATCH)
+                .put(PacketInReason.OFPRACTION.getIntValue(), SLAVE_IS_ACTION)
+                .put(PacketInReason.OFPRINVALIDTTL.getIntValue(), SLAVE_IS_INVALID_TTL)
+                .build()));
+
+        // Port status master
+        assertEquals(out.readInt(), ByteBufUtils.fillBitMaskFromMap(ImmutableMap
+                .<Integer, Boolean>builder()
+                .put(PortReason.OFPPRADD.getIntValue(), MASTER_IS_ADD)
+                .put(PortReason.OFPPRDELETE.getIntValue(), MASTER_IS_DELETE)
+                .put(PortReason.OFPPRMODIFY.getIntValue(), MASTER_IS_MODIFY)
+                .build()));
+
+        // Port status slave
+        assertEquals(out.readInt(), ByteBufUtils.fillBitMaskFromMap(ImmutableMap
+                .<Integer, Boolean>builder()
+                .put(PortReason.OFPPRADD.getIntValue(), SLAVE_IS_ADD)
+                .put(PortReason.OFPPRDELETE.getIntValue(), SLAVE_IS_DELETE)
+                .put(PortReason.OFPPRMODIFY.getIntValue(), SLAVE_IS_MODIFY)
+                .build()));
+
+        // Flow removed master
+        assertEquals(out.readInt(), ByteBufUtils.fillBitMaskFromMap(ImmutableMap
+                .<Integer, Boolean>builder()
+                .put(FlowRemovedReason.OFPRRIDLETIMEOUT.getIntValue(), MASTER_IS_IDLETIMEOUT)
+                .put(FlowRemovedReason.OFPRRHARDTIMEOUT.getIntValue(), MASTER_IS_HARDTIMEOUT)
+                .put(FlowRemovedReason.OFPRRDELETE.getIntValue(), MASTER_IS_FLOWDELETE)
+                .put(FlowRemovedReason.OFPRRGROUPDELETE.getIntValue(), MASTER_IS_GROUPDELETE)
+                .build()));
+
+        // Flow removed slave
+        assertEquals(out.readInt(), ByteBufUtils.fillBitMaskFromMap(ImmutableMap
+                .<Integer, Boolean>builder()
+                .put(FlowRemovedReason.OFPRRIDLETIMEOUT.getIntValue(), SLAVE_IS_IDLETIMEOUT)
+                .put(FlowRemovedReason.OFPRRHARDTIMEOUT.getIntValue(), SLAVE_IS_HARDTIMEOUT)
+                .put(FlowRemovedReason.OFPRRDELETE.getIntValue(), SLAVE_IS_FLOWDELETE)
+                .put(FlowRemovedReason.OFPRRGROUPDELETE.getIntValue(), SLAVE_IS_GROUPDELETE)
+                .build()));
+
+        assertEquals(out.readableBytes(), 0);
+    }
+
+}
\ No newline at end of file
index d79d1d3bc2c68405979c705cf51d7a203186f905..682f4cdc361371e6987ac1a0914dc25675749f57 100644 (file)
@@ -22,7 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
 
 /**
- * Test for {@link org.opendaylight.openflowplugin.impl.services.sal.FlowCapableTransactionServiceImpl}.
+ * Test for {@link FlowCapableTransactionServiceImpl}.
  */
 public class FlowCapableTransactionServiceImplTest extends ServiceMocking {
 
index 74a19aee56bb809f39b2bb1c8d3fe9aed1ef7ec5..16d1ba38a1c1047419e4839dcf788baee6af2a1d 100644 (file)
@@ -35,7 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.Tr
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 
 /**
- * Test for {@link org.opendaylight.openflowplugin.impl.services.sal.PacketProcessingServiceImpl}.
+ * Test for {@link PacketProcessingServiceImpl}.
  */
 public class PacketProcessingServiceImplTest extends ServiceMocking {
 
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/SalAsyncConfigServiceImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/SalAsyncConfigServiceImplTest.java
new file mode 100644 (file)
index 0000000..50d9078
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.services.sal;
+
+import static org.mockito.Mockito.verify;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.Future;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.openflowplugin.impl.services.ServiceMocking;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.GetAsyncOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.async.config.service.rev170619.SetAsyncInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.SetAsyncInput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * Test for {@link SalAsyncConfigServiceImpl}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SalAsyncConfigServiceImplTest extends ServiceMocking {
+
+    private SalAsyncConfigServiceImpl salAsyncConfigService;
+
+    @Before
+    public void setUp() throws Exception {
+        salAsyncConfigService = new SalAsyncConfigServiceImpl(
+                mockedRequestContextStack, mockedDeviceContext);
+    }
+
+    @Test
+    public void testSetAsync() throws Exception {
+        final SetAsyncInput setAsyncInput = new org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol
+                .rev130731.SetAsyncInputBuilder().build();
+        final RpcResult<SetAsyncInput> replyRpcResult = RpcResultBuilder.success(setAsyncInput).build();
+        final ListenableFuture<RpcResult<SetAsyncInput>> replyFuture = Futures.immediateFuture(replyRpcResult);
+        Mockito.when(mockedRequestContext.getFuture()).thenReturn(replyFuture);
+
+        final Future<RpcResult<Void>> setAsyncResult =
+                salAsyncConfigService.setAsync(new SetAsyncInputBuilder().build());
+
+        Assert.assertNotNull(setAsyncResult);
+        Assert.assertTrue(setAsyncResult.isDone());
+        Assert.assertTrue(setAsyncResult.get().isSuccessful());
+        verify(mockedRequestContextStack).createRequestContext();
+    }
+
+    @Test
+    public void testGetAsyncTest() throws Exception {
+        final GetAsyncOutput getAsyncOutput = new GetAsyncOutputBuilder().build();
+        final RpcResult<GetAsyncOutput> replyRpcResult = RpcResultBuilder.success(getAsyncOutput).build();
+        final ListenableFuture<RpcResult<GetAsyncOutput>> replyFuture = Futures.immediateFuture(replyRpcResult);
+        Mockito.when(mockedRequestContext.getFuture()).thenReturn(replyFuture);
+
+        final Future<RpcResult<GetAsyncOutput>> getAsyncResult =
+                salAsyncConfigService.getAsync(new GetAsyncInputBuilder().build());
+
+        Assert.assertNotNull(getAsyncResult);
+        Assert.assertTrue(getAsyncResult.isDone());
+        Assert.assertTrue(getAsyncResult.get().isSuccessful());
+        verify(mockedRequestContextStack).createRequestContext();
+        verify(mockedOutboundQueue).commitEntry(Matchers.eq(ServiceMocking.DUMMY_XID_VALUE),
+                Matchers.<OfHeader>any(), Matchers.<FutureCallback<OfHeader>>any());
+    }
+}
\ No newline at end of file
index 199ed588565dd993e9a737c5ae81d3041d2984d4..acfee6858c1b5af2d8a6d758be3e8a52fd6cd7f8 100644 (file)
@@ -41,7 +41,7 @@ public class MdSalRegistrationUtilsTest {
      * Number of currently registrated services (can be changed)
      * (RpcContext, DeviceContext)}.
      */
-    private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 15;
+    private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 16;
     private static final int NUMBER_OF_STAT_COMPAT_RPC_SERVICE_REGISTRATION = 5;
 
     @Mock
index 3791d89ef6536708e1cb262ccefcd99d26a3eaf7..8a336d87331eb63e7957aba4e2ac0183e0332c64 100644 (file)
@@ -91,4 +91,4 @@ public class ConvertorManagerFactory {
                 .registerConvertor(OFConstants.OFP_VERSION_1_0, flowFlagsV10Convertor)
                 .registerConvertor(OFConstants.OFP_VERSION_1_3, flowFlagsConvertor);
     }
-}
\ No newline at end of file
+}