From 5bdf763c2dc77c92cff97268087811077837e151 Mon Sep 17 00:00:00 2001 From: Shigeru Yasuda Date: Tue, 17 Mar 2015 00:43:58 +0900 Subject: [PATCH] Migrate flow condition to MD-SAL. Change-Id: I9dee805ae9c0de38502cab5e3032ff2bc90e55e5 Signed-off-by: Shigeru Yasuda --- manager/implementation/pom.xml | 4 + .../vtn/manager/internal/ContainerConfig.java | 5 - .../{VTNFlowMatch.java => FlowSelector.java} | 6 +- .../vtn/manager/internal/MacAddressTable.java | 15 +- .../vtn/manager/internal/MacMapCleaner.java | 6 +- .../vtn/manager/internal/PacketContext.java | 245 ++-- ...thFlowMatch.java => PathFlowSelector.java} | 10 +- ...Match.java => PathPolicyFlowSelector.java} | 10 +- ...lowMatch.java => RemovedFlowSelector.java} | 10 +- .../vtn/manager/internal/TxContext.java | 8 + .../vtn/manager/internal/VTNFlowDatabase.java | 20 +- .../vtn/manager/internal/VTNManagerImpl.java | 677 +++------- .../manager/internal/VTNManagerProvider.java | 25 +- .../vtn/manager/internal/VTNSubSystem.java | 43 + .../vtn/manager/internal/VTNThreadData.java | 33 +- .../internal/cluster/DlAddrActionImpl.java | 43 +- .../internal/cluster/EthernetMatchImpl.java | 422 ------- .../internal/cluster/FlowCondImpl.java | 468 ------- .../internal/cluster/FlowConditionEvent.java | 172 --- .../internal/cluster/FlowFilterImpl.java | 24 +- .../internal/cluster/FlowMatchImpl.java | 235 ---- .../internal/cluster/IcmpMatchImpl.java | 233 ---- .../internal/cluster/Inet4AddressMatch.java | 224 ---- .../internal/cluster/Inet4MatchImpl.java | 254 ---- .../cluster/InetAddressActionImpl.java | 15 +- .../internal/cluster/InetMatchImpl.java | 272 ---- .../manager/internal/cluster/L4MatchImpl.java | 87 -- .../manager/internal/cluster/L4PortMatch.java | 176 --- .../vtn/manager/internal/cluster/MapType.java | 22 +- .../manager/internal/cluster/PacketMatch.java | 36 - .../manager/internal/cluster/PathMapImpl.java | 9 +- .../manager/internal/cluster/PortBridge.java | 13 +- .../internal/cluster/PortProtoMatchImpl.java | 189 --- .../internal/cluster/SetDlDstActionImpl.java | 5 +- .../internal/cluster/SetDlSrcActionImpl.java | 5 +- .../cluster/SetIcmpCodeActionImpl.java | 2 +- .../cluster/SetIcmpTypeActionImpl.java | 2 +- .../cluster/SetInet4DstActionImpl.java | 9 +- .../cluster/SetInet4SrcActionImpl.java | 9 +- .../internal/cluster/TcpMatchImpl.java | 115 -- .../internal/cluster/UdpMatchImpl.java | 113 -- .../manager/internal/cluster/VBridgeImpl.java | 6 +- .../manager/internal/cluster/VTenantImpl.java | 9 +- .../internal/cluster/VTerminalImpl.java | 18 +- .../internal/config/VTNConfigManager.java | 6 - .../internal/flow/cond/FlowCondChange.java | 97 ++ .../internal/flow/cond/FlowCondManager.java | 490 ++++++++ .../flow/cond/RemoveFlowConditionTask.java | 111 ++ .../flow/cond/RemoveFlowMatchTask.java | 156 +++ .../internal/flow/cond/RemoveMatchTask.java | 64 + .../flow/cond/SetFlowConditionTask.java | 166 +++ .../internal/flow/cond/SetFlowMatchTask.java | 166 +++ .../internal/flow/cond/SetMatchTask.java | 51 + .../internal/packet/cache/CachedPacket.java | 6 +- .../internal/packet/cache/EtherPacket.java | 410 +++--- .../internal/packet/cache/IcmpPacket.java | 142 ++- .../internal/packet/cache/Inet4Packet.java | 429 +++---- .../internal/packet/cache/L4Packet.java | 4 +- .../packet/cache/PortProtoPacket.java | 164 ++- .../internal/packet/cache/TcpPacket.java | 35 +- .../internal/packet/cache/UdpPacket.java | 35 +- .../internal/provider/SubSystemRegistry.java | 207 +++ .../provider/VTNManagerProviderImpl.java | 74 +- .../internal/routing/PathPolicyChange.java | 10 +- .../internal/routing/PathPolicyListener.java | 42 +- .../routing/PathPolicyRpcContext.java | 12 +- .../internal/routing/RemovePathCostTask.java | 6 +- .../routing/RemovePathPolicyTask.java | 6 +- .../internal/routing/SetPathCostTask.java | 6 +- .../internal/routing/SetPathPolicyTask.java | 13 +- .../internal/routing/VTNRoutingManager.java | 47 +- .../vtn/manager/internal/util/MiscUtils.java | 51 +- .../manager/internal/util/ProtocolUtils.java | 302 ++++- .../manager/internal/util/XmlConfigFile.java | 9 +- .../util/flow/cond/FlowCondReader.java | 114 ++ .../util/flow/cond/FlowCondUtils.java | 372 ++++++ .../util/flow/cond/VTNFlowCondition.java | 486 +++++++ .../internal/util/flow/cond/VTNFlowMatch.java | 204 +++ .../internal/util/flow/cond/package-info.java | 31 + .../util/flow/match/FlowMatchContext.java | 39 + .../util/flow/match/FlowMatchType.java | 135 ++ .../util/flow/match/VTNEtherMatch.java | 666 ++++++++++ .../util/flow/match/VTNIcmpMatch.java | 349 ++++++ .../util/flow/match/VTNInet4Match.java | 248 ++++ .../util/flow/match/VTNInetMatch.java | 674 ++++++++++ .../util/flow/match/VTNLayer4Match.java | 218 ++++ .../util/flow/match/VTNLayer4PortMatch.java | 258 ++++ .../internal/util/flow/match/VTNMatch.java | 403 ++++++ .../util/flow/match/VTNPortRange.java | 325 +++++ .../internal/util/flow/match/VTNTcpMatch.java | 225 ++++ .../internal/util/flow/match/VTNUdpMatch.java | 225 ++++ .../util/flow/match/package-info.java | 31 + .../util/packet/ArpPacketBuilder.java | 169 +++ .../internal/util/packet/EtherHeader.java | 96 ++ .../internal/util/packet/IcmpHeader.java | 43 + .../internal/util/packet/InetHeader.java | 70 ++ .../internal/util/packet/Layer4Header.java | 16 + .../util/packet/Layer4PortHeader.java | 45 + .../internal/util/packet/PacketHeader.java | 49 + .../internal/util/packet/ProtocolHeader.java | 22 + .../internal/util/packet/TcpHeader.java | 16 + .../internal/util/packet/UdpHeader.java | 16 + .../manager/internal/util/rpc/RpcFuture.java | 6 - .../internal/util/tx/ReadTxContext.java | 20 + .../manager/internal/util/tx/TxQueueImpl.java | 20 + .../vtn/manager/internal/DataGenerator.java | 11 +- .../vtn/manager/internal/TestBase.java | 23 - .../cluster/EthernetMatchImplTest.java | 962 -------------- .../internal/cluster/FlowCondImplTest.java | 551 -------- .../cluster/FlowConditionEventTest.java | 39 - .../internal/cluster/FlowMatchImplTest.java | 1000 --------------- .../internal/cluster/IcmpMatchImplTest.java | 608 --------- .../cluster/Inet4AddressMatchTest.java | 263 ---- .../internal/cluster/Inet4MatchImplTest.java | 1113 ----------------- .../internal/cluster/L4PortMatchTest.java | 274 ---- .../manager/internal/cluster/MapTypeTest.java | 8 +- .../internal/cluster/PacketMatchTest.java | 168 --- .../cluster/SetDlDstActionImplTest.java | 5 +- .../cluster/SetDlSrcActionImplTest.java | 5 +- .../cluster/SetInet4DstActionImplTest.java | 4 +- .../cluster/SetInet4SrcActionImplTest.java | 4 +- .../internal/cluster/TcpMatchImplTest.java | 961 -------------- .../internal/cluster/UdpMatchImplTest.java | 884 ------------- .../packet/cache/EtherPacketTest.java | 235 ++-- .../internal/packet/cache/IcmpPacketTest.java | 82 +- .../packet/cache/Inet4PacketTest.java | 163 +-- .../internal/packet/cache/TcpPacketTest.java | 37 +- .../internal/packet/cache/UdpPacketTest.java | 37 +- .../manager/internal/util/MiscUtilsTest.java | 15 +- .../util/flow/cond/FlowCondParams.java | 318 +++++ .../util/flow/cond/FlowCondReaderTest.java | 115 ++ .../util/flow/cond/FlowCondUtilsTest.java | 811 ++++++++++++ .../util/flow/cond/FlowMatchParams.java | 214 ++++ .../util/flow/cond/VTNFlowConditionTest.java | 651 ++++++++++ .../util/flow/cond/VTNFlowMatchTest.java | 248 ++++ .../util/flow/match/EtherMatchParams.java | 494 ++++++++ .../util/flow/match/FlowMatchTypeTest.java | 90 ++ .../util/flow/match/IcmpMatchParams.java | 349 ++++++ .../util/flow/match/Inet4MatchParams.java | 558 +++++++++ .../util/flow/match/Layer4MatchParams.java | 154 +++ .../flow/match/Layer4PortMatchParams.java | 300 +++++ .../internal/util/flow/match/MatchParams.java | 616 +++++++++ .../util/flow/match/PortRangeParams.java | 218 ++++ .../util/flow/match/TcpMatchParams.java | 294 +++++ .../util/flow/match/TestMatchContext.java | 197 +++ .../util/flow/match/UdpMatchParams.java | 294 +++++ .../util/flow/match/VTNEtherMatchTest.java | 848 +++++++++++++ .../util/flow/match/VTNIcmpMatchTest.java | 330 +++++ .../util/flow/match/VTNInet4MatchTest.java | 669 ++++++++++ .../util/flow/match/VTNMatchTest.java | 916 ++++++++++++++ .../util/flow/match/VTNPortRangeTest.java | 438 +++++++ .../util/flow/match/VTNTcpMatchTest.java | 569 +++++++++ .../util/flow/match/VTNUdpMatchTest.java | 569 +++++++++ .../util/packet/ArpPacketBuilderTest.java | 185 +++ .../src/test/resources/logback.xml | 4 + manager/model/pom.xml | 18 + manager/model/src/main/yang/vtn-config.yang | 1 + .../src/main/yang/vtn-flow-condition.yang | 467 +++++++ manager/model/src/main/yang/vtn-types.yang | 26 + 159 files changed, 19886 insertions(+), 11739 deletions(-) rename manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/{VTNFlowMatch.java => FlowSelector.java} (86%) rename manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/{PathFlowMatch.java => PathFlowSelector.java} (83%) rename manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/{PathPolicyFlowMatch.java => PathPolicyFlowSelector.java} (81%) rename manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/{RemovedFlowMatch.java => RemovedFlowSelector.java} (88%) create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNSubSystem.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEvent.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatch.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetMatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4MatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatch.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatch.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortProtoMatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImpl.java delete mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImpl.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondChange.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondManager.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowConditionTask.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowMatchTask.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveMatchTask.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowConditionTask.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowMatchTask.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetMatchTask.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/SubSystemRegistry.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtils.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowCondition.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/package-info.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchContext.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchType.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4Match.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInetMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4Match.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4PortMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRange.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatch.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/package-info.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilder.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/EtherHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/IcmpHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/InetHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4Header.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4PortHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/PacketHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ProtocolHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/TcpHeader.java create mode 100644 manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/UdpHeader.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImplTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImplTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEventTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImplTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImplTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatchTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImplTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatchTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatchTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImplTest.java delete mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImplTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReaderTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtilsTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowMatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowConditionTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/EtherMatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchTypeTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/IcmpMatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Inet4MatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4MatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4PortMatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/MatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/PortRangeParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TcpMatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TestMatchContext.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/UdpMatchParams.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4MatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRangeTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatchTest.java create mode 100644 manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilderTest.java create mode 100644 manager/model/src/main/yang/vtn-flow-condition.yang diff --git a/manager/implementation/pom.xml b/manager/implementation/pom.xml index 903040d6..a3e243b5 100644 --- a/manager/implementation/pom.xml +++ b/manager/implementation/pom.xml @@ -133,6 +133,10 @@ org.opendaylight.yangtools.model ietf-topology + + org.opendaylight.yangtools.model + opendaylight-l2-types + diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ContainerConfig.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ContainerConfig.java index df6bb9bf..ea72aaab 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ContainerConfig.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ContainerConfig.java @@ -63,11 +63,6 @@ public final class ContainerConfig implements IObjectReader { */ TENANT, - /** - * Indicates the configuration of the flow condition. - */ - FLOWCOND, - /** * Indicates the configuration of the container path map list. */ diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/FlowSelector.java similarity index 86% rename from manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowMatch.java rename to manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/FlowSelector.java index d9cbab56..20bd9203 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowMatch.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/FlowSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -12,10 +12,10 @@ package org.opendaylight.vtn.manager.internal; import org.opendaylight.vtn.manager.internal.cluster.VTNFlow; /** - * {@code VTNFlowMatch} provides interfaces to be implemented by classes which + * {@code FlowSelector} provides interfaces to be implemented by classes which * search for specific flow entries. */ -public interface VTNFlowMatch { +public interface FlowSelector { /** * Test if the specified VTN flow should be accepted or not. * diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacAddressTable.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacAddressTable.java index 33c9b36f..35271a2a 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacAddressTable.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacAddressTable.java @@ -561,13 +561,14 @@ public class MacAddressTable { * @param bnode A {@link VBridgeNode} which maps the incoming packet. */ public void add(PacketContext pctx, VBridgeNode bnode) { - byte[] src = pctx.getSourceAddress(); - if (!EtherAddress.isUnicast(src)) { + EtherAddress src = pctx.getSourceAddress(); + if (!src.isUnicast()) { return; } // Determine attributes of a new MAC address table entry. - Long key = getTableKey(src); + byte[] srcMac = src.getBytes(); + Long key = Long.valueOf(src.getAddress()); if (key.longValue() == 0L) { // Zero address should be ignored. LOG.warn("{}: Ignore zero MAC address: {}", @@ -576,7 +577,7 @@ public class MacAddressTable { } NodeConnector port = pctx.getIncomingNodeConnector(); - short vlan = pctx.getVlan(); + short vlan = (short)pctx.getVlan(); InetAddress ipaddr = getSourceInetAddress(pctx); // Add a MAC address table entry. @@ -591,7 +592,7 @@ public class MacAddressTable { if (ipaddr != null) { try { HostNodeConnector host = - new HostNodeConnector(src, ipaddr, port, vlan); + new HostNodeConnector(srcMac, ipaddr, port, vlan); if (LOG.isTraceEnabled()) { LOG.trace("{}: Notify new host: ipaddr={}, host={}", getTableName(), ipaddr.getHostAddress(), host); @@ -602,7 +603,7 @@ public class MacAddressTable { StringBuilder builder = new StringBuilder(getTableName()); builder.append(": Unable to create host: src="). - append(ByteUtils.toHexString(src)). + append(src.getText()). append(", ipaddr=").append(ipaddr). append(", port=").append(port.toString()). append(", vlan=").append((int)vlan); @@ -611,7 +612,7 @@ public class MacAddressTable { } } else if (pctx.isIPv4() && tent.isProbeNeeded()) { // Try to detect IP address of the host. - pctx.probeInetAddress(vtnManager); + pctx.probeInetAddress(); } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacMapCleaner.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacMapCleaner.java index 434c6fd0..93eca3a6 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacMapCleaner.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MacMapCleaner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -30,7 +30,7 @@ import org.opendaylight.controller.sal.core.NodeConnector; * MAC mapping. */ public final class MacMapCleaner - implements MapCleaner, VTNFlowMatch, MacTableEntryFilter { + implements MapCleaner, FlowSelector, MacTableEntryFilter { /** * A global resource manager instance. */ @@ -199,7 +199,7 @@ public final class MacMapCleaner return mapped; } - // VTNFlowMatch + // FlowSelector /** * {@inheritDoc} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java index 824223f2..3e83a5ba 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java @@ -9,7 +9,6 @@ package org.opendaylight.vtn.manager.internal; -import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; @@ -27,8 +26,8 @@ import org.opendaylight.vtn.manager.VNodeRoute.Reason; import org.opendaylight.vtn.manager.VNodeRoute; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.VTenantPath; -import org.opendaylight.vtn.manager.util.ByteUtils; import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.Ip4Network; import org.opendaylight.vtn.manager.util.NumberUtils; import org.opendaylight.vtn.manager.internal.cluster.MacTableEntry; @@ -46,6 +45,12 @@ import org.opendaylight.vtn.manager.internal.packet.cache.L4Packet; import org.opendaylight.vtn.manager.internal.packet.cache.TcpPacket; import org.opendaylight.vtn.manager.internal.packet.cache.UdpPacket; import org.opendaylight.vtn.manager.internal.util.SalPort; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.ArpPacketBuilder; +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; import org.opendaylight.controller.sal.action.Action; import org.opendaylight.controller.sal.core.NodeConnector; @@ -69,7 +74,7 @@ import org.opendaylight.controller.sal.utils.EtherTypes; * This class is designed to be used by a single thread. *

*/ -public class PacketContext implements Cloneable { +public class PacketContext implements Cloneable, FlowMatchContext { /** * Logger instance. */ @@ -81,14 +86,6 @@ public class PacketContext implements Cloneable { */ private static final int ETHER_TYPE_MASK = 0xffff; - /** - * Flow match fields to be configured in an unicast flow entry. - */ - private static final MatchType[] UNICAST_MATCHES = { - MatchType.DL_SRC, - MatchType.DL_DST, - }; - /** * A received raw packet. */ @@ -131,11 +128,11 @@ public class PacketContext implements Cloneable { private List virtualRoute = new ArrayList(); /** - * A set of {@link MatchType} instances which represents match fields + * A set of {@link FlowMatchType} instances which represents match fields * to be configured. */ - private EnumSet matchFields = - EnumSet.noneOf(MatchType.class); + private EnumSet matchFields = + EnumSet.noneOf(FlowMatchType.class); /** * A {@link VNodeRoute} instance which represents the hop to the egress @@ -277,7 +274,7 @@ public class PacketContext implements Cloneable { * * @return The source MAC address. */ - public byte[] getSourceAddress() { + public EtherAddress getSourceAddress() { return etherFrame.getSourceAddress(); } @@ -286,7 +283,7 @@ public class PacketContext implements Cloneable { * * @return The destination MAC address. */ - public byte[] getDestinationAddress() { + public EtherAddress getDestinationAddress() { return etherFrame.getDestinationAddress(); } @@ -373,7 +370,7 @@ public class PacketContext implements Cloneable { } NodeConnector nc = rawPacket.getIncomingNodeConnector(); - return new PortVlan(nc, etherFrame.getOriginalVlan()); + return new PortVlan(nc, (short)etherFrame.getOriginalVlan()); } /** @@ -392,8 +389,8 @@ public class PacketContext implements Cloneable { * @return VLAN ID. Zero is returned if no VLAN tag was found in the * packet. */ - public short getVlan() { - return etherFrame.getVlan(); + public int getVlan() { + return etherFrame.getVlanId(); } /** @@ -401,8 +398,8 @@ public class PacketContext implements Cloneable { * * @param vid A VLAN ID. */ - public void setVlan(short vid) { - etherFrame.setVlan(vid); + public void setVlan(int vid) { + etherFrame.setVlanId(vid); } /** @@ -414,27 +411,30 @@ public class PacketContext implements Cloneable { * @throws VTNException * Failed to commit packet modification. */ - public Ethernet createFrame(short vlan) throws VTNException { + public Ethernet createFrame(int vlan) throws VTNException { // Configure VLAN ID for outgoing packet. It is used to determine // flow actions to be configured. - etherFrame.setVlan(vlan); + etherFrame.setVlanId(vlan); // Commit changes made by flow filters to the packet. commit(); + EtherAddress src = etherFrame.getSourceAddress(); + EtherAddress dst = etherFrame.getDestinationAddress(); Ethernet ether = new Ethernet(); - ether.setSourceMACAddress(etherFrame.getSourceAddress()). - setDestinationMACAddress(etherFrame.getDestinationAddress()); + ether.setSourceMACAddress(src.getBytes()). + setDestinationMACAddress(dst.getBytes()); short ethType = (short)etherFrame.getEtherType(); IEEE8021Q vlanTag = etherFrame.getVlanTag(); Packet payload = etherFrame.getPayload(); - if (vlan != 0 || (vlanTag != null && vlanTag.getVid() == 0)) { + if (vlan != EtherHeader.VLAN_NONE || + (vlanTag != null && vlanTag.getVid() == EtherHeader.VLAN_NONE)) { // Add a VLAN tag. // We don't strip VLAN tag with zero VLAN ID because PCP field // in the VLAN tag should affect even if the VLAN ID is zero. IEEE8021Q tag = new IEEE8021Q(); - byte pcp = etherFrame.getVlanPriority(); + byte pcp = (byte)etherFrame.getVlanPriority(); if (pcp < 0) { pcp = (byte)0; } @@ -445,7 +445,8 @@ public class PacketContext implements Cloneable { } else { cfi = (byte)0; } - tag.setCfi(cfi).setPcp(pcp).setVid(vlan).setEtherType(ethType); + tag.setCfi(cfi).setPcp(pcp).setVid((short)vlan). + setEtherType(ethType); ether.setEtherType(EtherTypes.VLANTAGGED.shortValue()); // Set payload to IEEE 802.1Q header. @@ -549,7 +550,7 @@ public class PacketContext implements Cloneable { return getDescription(etherFrame.getSourceAddress(), etherFrame.getDestinationAddress(), etherFrame.getEtherType(), port, - etherFrame.getVlan()); + etherFrame.getVlanId()); } /** @@ -561,9 +562,10 @@ public class PacketContext implements Cloneable { * @return A brief description of the specified ethernet frame. */ public String getDescription(Ethernet ether, NodeConnector port, - short vlan) { - return getDescription(ether.getSourceMACAddress(), - ether.getDestinationMACAddress(), + int vlan) { + EtherAddress src = new EtherAddress(ether.getSourceMACAddress()); + EtherAddress dst = new EtherAddress(ether.getDestinationMACAddress()); + return getDescription(src, dst, (int)ether.getEtherType() & ETHER_TYPE_MASK, port, vlan); } @@ -578,19 +580,16 @@ public class PacketContext implements Cloneable { * @param vlan VLAN ID. * @return A brief description of the specified ethernet frame. */ - public String getDescription(byte[] src, byte[] dst, int type, - NodeConnector port, short vlan) { - String srcmac = ByteUtils.toHexString(src); - String dstmac = ByteUtils.toHexString(dst); - + public String getDescription(EtherAddress src, EtherAddress dst, int type, + NodeConnector port, int vlan) { StringBuilder builder = new StringBuilder("src="); - builder.append(srcmac). - append(", dst=").append(dstmac); + builder.append(src.getText()). + append(", dst=").append(dst.getText()); if (port != null) { builder.append(", port=").append(port); } builder.append(", type=0x").append(Integer.toHexString(type)). - append(", vlan=").append((int)vlan); + append(", vlan=").append(vlan); return builder.toString(); } @@ -654,8 +653,7 @@ public class PacketContext implements Cloneable { * packet. */ public boolean isUnicast() { - byte[] dst = etherFrame.getDestinationAddress(); - return EtherAddress.isUnicast(dst); + return etherFrame.getDestinationAddress().isUnicast(); } /** @@ -666,7 +664,7 @@ public class PacketContext implements Cloneable { */ public void setMapReference(MapReference ref) { mapReference = ref; - MatchType mtype = ref.getMapType().getMatchType(); + FlowMatchType mtype = ref.getMapType().getMatchType(); if (mtype != null) { matchFields.add(mtype); } @@ -674,69 +672,29 @@ public class PacketContext implements Cloneable { /** * Try to probe IP address of the source address of this packet. - * - * @param mgr VTN Manager service. */ - public void probeInetAddress(VTNManagerImpl mgr) { + public void probeInetAddress() { Inet4Packet ipv4 = getInet4Packet(); if (ipv4 != null) { // Send an ARP request to the source address of this packet. - int srcIp = ipv4.getSourceAddress(); - byte[] dst = etherFrame.getSourceAddress(); - byte[] tpa = NumberUtils.toBytes(srcIp); - short vlan = etherFrame.getOriginalVlan(); - Ethernet ether = mgr.createArpRequest(dst, tpa, vlan); + VTNManagerProvider provider = txContext.getProvider(); + Ip4Network tpa = ipv4.getSourceAddress(); + EtherAddress src = + provider.getVTNConfig().getControllerMacAddress(); + EtherAddress dst = etherFrame.getSourceAddress(); + int vlan = etherFrame.getOriginalVlan(); + Ethernet ether = new ArpPacketBuilder(vlan).build(src, dst, tpa); SalPort sport = getIngressPort(); if (LOG.isTraceEnabled()) { - String dstmac = ByteUtils.toHexString(dst); - String target; - try { - InetAddress ia = InetAddress.getByAddress(tpa); - target = ia.getHostAddress(); - } catch (Exception e) { - target = ByteUtils.toHexString(tpa); - } - LOG.trace("{}: Send an ARP request to detect IP address: " + + String dstmac = dst.getText(); + String target = tpa.getText(); + LOG.trace("Send an ARP request to detect IP address: " + "dst={}, tpa={}, vlan={}, port={}", - mgr.getContainerName(), dstmac, target, vlan, sport); + dstmac, target, vlan, sport); } - mgr.transmit(sport, ether); - } - } - - /** - * Add a match field to be configured into a flow entry. - * - * @param type A match type to be added. - */ - public void addMatchField(MatchType type) { - if (!flooding) { - matchFields.add(type); - } - } - - /** - * Determine whether the given match field will be configured in a flow - * entry or not. - * - * @param type A match type to be tested. - * @return {@code true} only if the given match type will be configured - * in a flow entry. - */ - public boolean hasMatchField(MatchType type) { - return matchFields.contains(type); - } - - /** - * Add match fields to be configured into an unicast flow entry. - */ - public void addUnicastMatchFields() { - if (!flooding) { - for (MatchType type: UNICAST_MATCHES) { - matchFields.add(type); - } + provider.transmit(sport, ether); } } @@ -905,18 +863,13 @@ public class PacketContext implements Cloneable { /** * Return a priority value for flow entries. * - * @param mgr VTN Manager service. * @return A flow priority value. */ - public int getFlowPriority(VTNManagerImpl mgr) { - int pri = mgr.getVTNConfig().getL2FlowPriority(); - int nmatches = matchFields.size(); - for (MatchType type: UNICAST_MATCHES) { - if (matchFields.contains(type)) { - nmatches--; - } - } - + public int getFlowPriority() { + VTNManagerProvider provider = txContext.getProvider(); + int pri = provider.getVTNConfig().getL2FlowPriority(); + int nmatches = matchFields.size() - + FlowMatchType.getUnicastTypeCount(matchFields); return (pri + nmatches); } @@ -950,7 +903,7 @@ public class PacketContext implements Cloneable { // Create a flow entry that discards the given packet. NodeConnector incoming = getIncomingNodeConnector(); Match match = createMatch(incoming); - int pri = getFlowPriority(mgr); + int pri = getFlowPriority(); VTNFlow vflow = fdb.create(mgr); vflow.addFlow(mgr, match, pri); @@ -1226,4 +1179,82 @@ public class PacketContext implements Cloneable { throw new IllegalStateException("clone() failed", e); } } + + // FlowMatchContext + + /** + * {@inheritDoc} + */ + @Override + public void addMatchField(FlowMatchType type) { + if (!flooding) { + matchFields.add(type); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasMatchField(FlowMatchType type) { + return matchFields.contains(type); + } + + /** + * {@inheritDoc} + */ + @Override + public void addUnicastMatchFields() { + if (!flooding) { + FlowMatchType.addUnicastTypes(matchFields); + } + } + + // PacketHeader + + /** + * {@inheritDoc} + */ + @Override + public EtherHeader getEtherHeader() { + return etherFrame; + } + + /** + * {@inheritDoc} + */ + @Override + public InetHeader getInetHeader() { + return getInet4Packet(); + } + + /** + * {@inheritDoc} + */ + @Override + public Layer4Header getLayer4Header() { + return getL4Packet(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getHeaderDescription() { + StringBuilder builder = new StringBuilder(); + getEtherHeader().setDescription(builder); + + InetHeader inet = getInetHeader(); + if (inet != null) { + builder.append(','); + inet.setDescription(builder); + Layer4Header l4 = getLayer4Header(); + if (l4 != null) { + builder.append(','); + l4.setDescription(builder); + } + } + + return builder.toString(); + } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathFlowMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathFlowSelector.java similarity index 83% rename from manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathFlowMatch.java rename to manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathFlowSelector.java index 3d232fc5..d61dac9f 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathFlowMatch.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathFlowSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -13,10 +13,10 @@ import org.opendaylight.vtn.manager.VTenantPath; import org.opendaylight.vtn.manager.internal.cluster.VTNFlow; /** - * {@link VTNFlowMatch} implementation which accepts VTN flows which depend + * {@link FlowSelector} implementation which accepts VTN flows which depend * on the specified virtual node path. */ -public class PathFlowMatch implements VTNFlowMatch { +public class PathFlowSelector implements FlowSelector { /** * A {@link VTenantPath} instance which specifies the virtual node. */ @@ -28,10 +28,12 @@ public class PathFlowMatch implements VTNFlowMatch { * @param path A path to the virtual node. * Specifying {@code null} results in undefined behavior. */ - public PathFlowMatch(VTenantPath path) { + public PathFlowSelector(VTenantPath path) { nodePath = path; } + // FlowSelector + /** * {@inheritDoc} */ diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathPolicyFlowMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathPolicyFlowSelector.java similarity index 81% rename from manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathPolicyFlowMatch.java rename to manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathPolicyFlowSelector.java index ed5f822b..1ff5cac2 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathPolicyFlowMatch.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PathPolicyFlowSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -12,10 +12,10 @@ package org.opendaylight.vtn.manager.internal; import org.opendaylight.vtn.manager.internal.cluster.VTNFlow; /** - * {@link VTNFlowMatch} implementation which accepts VTN flows which was + * {@link FlowSelector} implementation which accepts VTN flows which was * determined the packet route by the specified path policy. */ -public class PathPolicyFlowMatch implements VTNFlowMatch { +public class PathPolicyFlowSelector implements FlowSelector { /** * The identifier of the path policy. */ @@ -26,10 +26,12 @@ public class PathPolicyFlowMatch implements VTNFlowMatch { * * @param id The identifier of the path policy. */ - public PathPolicyFlowMatch(int id) { + public PathPolicyFlowSelector(int id) { policyId = id; } + // FlowSelector + /** * {@inheritDoc} */ diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/RemovedFlowMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/RemovedFlowSelector.java similarity index 88% rename from manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/RemovedFlowMatch.java rename to manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/RemovedFlowSelector.java index 003763aa..94383f61 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/RemovedFlowMatch.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/RemovedFlowSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -19,10 +19,10 @@ import org.opendaylight.controller.forwardingrulesmanager. IForwardingRulesManager; /** - * {@link VTNFlowMatch} implementation which accepts VTN flows which are + * {@link FlowSelector} implementation which accepts VTN flows which are * already removed. */ -public class RemovedFlowMatch implements VTNFlowMatch { +public class RemovedFlowSelector implements FlowSelector { /** * Forwarding rules manager service. */ @@ -33,10 +33,12 @@ public class RemovedFlowMatch implements VTNFlowMatch { * * @param frm Forwarding rules manager service. */ - public RemovedFlowMatch(IForwardingRulesManager frm) { + public RemovedFlowSelector(IForwardingRulesManager frm) { fwRulesManager = frm; } + // FlowSelector + /** * Test if the specified VTN flow should be accepted or not. * diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/TxContext.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/TxContext.java index 987c4d3f..6ec63f2a 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/TxContext.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/TxContext.java @@ -10,6 +10,7 @@ package org.opendaylight.vtn.manager.internal; import org.opendaylight.vtn.manager.internal.util.InventoryReader; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondReader; import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; @@ -42,6 +43,13 @@ public interface TxContext { */ InventoryReader getInventoryReader(); + /** + * Return flow condition reader that uses current transaction. + * + * @return A {@link FlowCondReader} instance. + */ + FlowCondReader getFlowCondReader(); + /** * Cancel current transaction for MD-SAL datastore. */ diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowDatabase.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowDatabase.java index 71da889a..5f26597d 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowDatabase.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNFlowDatabase.java @@ -639,8 +639,8 @@ public class VTNFlowDatabase { * entry to be removed. */ public FlowRemoveTask removeFlows(VTNManagerImpl mgr, VTenantPath path) { - PathFlowMatch fmatch = new PathFlowMatch(path); - return removeFlows(mgr, fmatch); + PathFlowSelector selector = new PathFlowSelector(path); + return removeFlows(mgr, selector); } /** @@ -733,7 +733,7 @@ public class VTNFlowDatabase { } /** - * Remove all VTN flows accepted by the specified {@link VTNFlowMatch} + * Remove all VTN flows accepted by the specified {@link FlowSelector} * instance. * *

@@ -742,16 +742,16 @@ public class VTNFlowDatabase { * returned {@link FlowRemoveTask} object. *

* - * @param mgr VTN Manager service. - * @param fmatch A {@link VTNFlowMatch} instance which determines VTN - * flows to be removed. - * Specifying {@code null} results in undefined behavior. + * @param mgr VTN Manager service. + * @param selector A {@link FlowSelector} instance which determines VTN + * flows to be removed. + * Specifying {@code null} results in undefined behavior. * @return A {@link FlowRemoveTask} object that will execute the actual * work is returned. {@code null} is returned if there is no flow * entry to be removed. */ public synchronized FlowRemoveTask removeFlows(VTNManagerImpl mgr, - VTNFlowMatch fmatch) { + FlowSelector selector) { VTNManagerProvider provider = mgr.getVTNProvider(); if (provider == null) { return null; @@ -761,12 +761,12 @@ public class VTNFlowDatabase { for (Iterator it = vtnFlows.values().iterator(); it.hasNext();) { VTNFlow vflow = it.next(); - if (fmatch.accept(vflow)) { + if (selector.accept(vflow)) { FlowGroupId gid = vflow.getGroupId(); if (LOG.isDebugEnabled()) { LOG.debug("{}:{}: Remove VTN flow accepted by filter" + "({}): group={}", mgr.getContainerName(), - tenantName, fmatch.getDescription(), gid); + tenantName, selector.getDescription(), gid); } // Remove this VTN flow from the database. diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerImpl.java index a8c570f5..8797b4aa 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerImpl.java @@ -9,10 +9,8 @@ package org.opendaylight.vtn.manager.internal; -import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Deque; @@ -84,8 +82,8 @@ import org.opendaylight.vtn.manager.internal.config.VTNConfigImpl; import org.opendaylight.vtn.manager.internal.inventory.VTNInventoryListener; import org.opendaylight.vtn.manager.internal.inventory.VtnNodeEvent; import org.opendaylight.vtn.manager.internal.inventory.VtnPortEvent; -import org.opendaylight.vtn.manager.internal.packet.VTNPacketListener; import org.opendaylight.vtn.manager.internal.packet.PacketInEvent; +import org.opendaylight.vtn.manager.internal.packet.VTNPacketListener; import org.opendaylight.vtn.manager.internal.routing.RoutingEvent; import org.opendaylight.vtn.manager.internal.routing.VTNRoutingListener; import org.opendaylight.vtn.manager.internal.util.InventoryReader; @@ -96,6 +94,10 @@ import org.opendaylight.vtn.manager.internal.util.SalNode; import org.opendaylight.vtn.manager.internal.util.SalPort; import org.opendaylight.vtn.manager.internal.util.concurrent.AbstractVTNFuture; import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowCondition; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowMatch; +import org.opendaylight.vtn.manager.internal.util.packet.ArpPacketBuilder; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathCostConfigBuilder; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyConfigBuilder; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyUtils; @@ -105,11 +107,8 @@ import org.opendaylight.vtn.manager.internal.cluster.ClusterEvent; import org.opendaylight.vtn.manager.internal.cluster.ClusterEventId; import org.opendaylight.vtn.manager.internal.cluster.ContainerPathMapEvent; import org.opendaylight.vtn.manager.internal.cluster.ContainerPathMapImpl; -import org.opendaylight.vtn.manager.internal.cluster.FlowCondImpl; -import org.opendaylight.vtn.manager.internal.cluster.FlowConditionEvent; import org.opendaylight.vtn.manager.internal.cluster.FlowFilterMap; import org.opendaylight.vtn.manager.internal.cluster.FlowGroupId; -import org.opendaylight.vtn.manager.internal.cluster.FlowMatchImpl; import org.opendaylight.vtn.manager.internal.cluster.FlowModResult; import org.opendaylight.vtn.manager.internal.cluster.MacMapPath; import org.opendaylight.vtn.manager.internal.cluster.MacTableEntry; @@ -146,13 +145,8 @@ import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; -import org.opendaylight.controller.sal.packet.ARP; import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.IEEE8021Q; -import org.opendaylight.controller.sal.packet.Packet; import org.opendaylight.controller.sal.packet.address.DataLinkAddress; -import org.opendaylight.controller.sal.packet.address.EthernetAddress; -import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; @@ -161,6 +155,20 @@ import org.opendaylight.controller.statisticsmanager.IStatisticsManager; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditionService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.remove.flow.condition.match.output.RemoveMatchResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.input.FlowMatchList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.output.SetMatchResult; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostInputBuilder; @@ -206,11 +214,6 @@ public class VTNManagerImpl */ private static final long RPC_TIMEOUT = 60L; - /** - * The number of bytes in an IPv4 address. - */ - static final int IPV4_ADDRLEN = 4; - /** * Cluster cache name associated with {@link #tenantDB}. */ @@ -221,11 +224,6 @@ public class VTNManagerImpl */ static final String CACHE_STATE = "vtn.state"; - /** - * The name of the cluster cache which keeps flow conditions. - */ - static final String CACHE_FLOWCOND = "vtn.flowcond"; - /** * The name of the cluster cache which keeps container path maps. */ @@ -277,11 +275,6 @@ public class VTNManagerImpl */ private ConcurrentMap flowDB; - /** - * Keeps flow conditions configured in this container. - */ - private ConcurrentMap flowCondDB; - /** * Keeps container path maps configured in this container. */ @@ -792,7 +785,6 @@ public class VTNManagerImpl clusterEvent = new ConcurrentHashMap(); flowDB = new ConcurrentHashMap(); - flowCondDB = new ConcurrentHashMap(); pathMapDB = new ConcurrentHashMap(); macAddressDB = null; return; @@ -804,15 +796,12 @@ public class VTNManagerImpl IClusterServices.cacheMode.SYNC); createCache(cluster, CACHE_TENANT, cmode); createCache(cluster, CACHE_STATE, cmode); - createCache(cluster, CACHE_FLOWCOND, cmode); createCache(cluster, CACHE_PATHMAP, cmode); tenantDB = (ConcurrentMap) getCache(cluster, CACHE_TENANT); stateDB = (ConcurrentMap) getCache(cluster, CACHE_STATE); - flowCondDB = (ConcurrentMap) - getCache(cluster, CACHE_FLOWCOND); pathMapDB = (ConcurrentMap) getCache(cluster, CACHE_PATHMAP); @@ -914,7 +903,6 @@ public class VTNManagerImpl if (cluster != null) { cluster.destroyCache(CACHE_TENANT); cluster.destroyCache(CACHE_STATE); - cluster.destroyCache(CACHE_FLOWCOND); cluster.destroyCache(CACHE_PATHMAP); cluster.destroyCache(CACHE_EVENT); cluster.destroyCache(CACHE_FLOWS); @@ -1336,15 +1324,6 @@ public class VTNManagerImpl return flowDB; } - /** - * Return the flow condition DB. - * - * @return The flow condition DB. - */ - public ConcurrentMap getFlowCondDB() { - return flowCondDB; - } - /** * Let the specified VTN visible to other controllers in the cluster. * @@ -1601,9 +1580,10 @@ public class VTNManagerImpl */ public void cleanUpRemovedFlows() { if (clusterService.amICoordinator()) { - RemovedFlowMatch fmatch = new RemovedFlowMatch(fwRuleManager); + RemovedFlowSelector selector = + new RemovedFlowSelector(fwRuleManager); for (VTNFlowDatabase fdb: vtnFlowMap.values()) { - fdb.removeFlows(this, fmatch); + fdb.removeFlows(this, selector); } } } @@ -1639,118 +1619,6 @@ public class VTNManagerImpl } } - /** - * Create an ethernet frame which contains an ARP request message. - * - *

- * Controller's MAC address is used as source MAC adddress, and zero - * is used as sender protocol address. - *

- * - * @param dst Destination MAC address. - * @param addr Target IP address. - * @return An ethernet frame. {@code null} is returned if {@code addr} - * is invalid. - */ - public Ethernet createArpRequest(byte[] dst, InetAddress addr) { - return createArpRequest(dst, addr, (short)0); - } - - /** - * Create an ethernet frame which contains an ARP request message. - * - *

- * Controller's MAC address is used as source MAC adddress, and zero - * is used as sender protocol address. - *

- * - * @param dst Destination MAC address. - * @param addr Target IP address. - * @param vlan VLAN ID. Zero means VLAN tag should not be added. - * @return An ethernet frame. {@code null} is returned if {@code addr} - * is invalid. - */ - public Ethernet createArpRequest(byte[] dst, InetAddress addr, - short vlan) { - // IP address must be an IPv4 address. - if (addr instanceof Inet4Address) { - return createArpRequest(dst, addr.getAddress(), vlan); - } - return null; - } - - /** - * Create an ethernet frame which contains an ARP request message. - * - *

- * Controller's MAC address is used as source MAC adddress, and zero - * is used as sender protocol address. - *

- * - * @param dst Destination MAC address. - * @param target Target IP address. - * @param vlan VLAN ID. Zero means VLAN tag should not be added. - * @return An ethernet frame. - */ - public Ethernet createArpRequest(byte[] dst, byte[] target, short vlan) { - // Set controller's MAC address to source MAC address. - byte[] src = getVTNConfig().getControllerMacAddress().getBytes(); - - // Create an ARP request message. - // Set zero to sender protocol address. - byte[] sender = new byte[]{0, 0, 0, 0}; - return createArp(ARP.REQUEST, src, dst, sender, target, vlan); - } - - /** - * Create an ethernet frame which contains an ARP message. - * - * @param op Operation code defined by ARP. - * @param src Source MAC address. - * @param dst Destination MAC address. - * @param sender Sender IP address. - * @param target Target IP address. - * @param vlan VLAN ID. Zero means VLAN tag should not be added. - * @return An ethernet frame. - */ - public Ethernet createArp(short op, byte[] src, byte[] dst, byte[] sender, - byte[] target, short vlan) { - assert src.length == EthernetAddress.SIZE && - dst.length == EthernetAddress.SIZE && - sender.length == IPV4_ADDRLEN && target.length == IPV4_ADDRLEN; - - byte[] tha = (EtherAddress.isBroadcast(dst)) - ? new byte[]{0, 0, 0, 0, 0, 0} : dst; - - // Create an ARP request message. - ARP arp = new ARP(); - arp.setHardwareType(ARP.HW_TYPE_ETHERNET). - setProtocolType(EtherTypes.IPv4.shortValue()). - setHardwareAddressLength((byte)EthernetAddress.SIZE). - setProtocolAddressLength((byte)target.length). - setOpCode(op). - setSenderHardwareAddress(src).setSenderProtocolAddress(sender). - setTargetHardwareAddress(tha).setTargetProtocolAddress(target); - - short ethType = EtherTypes.ARP.shortValue(); - Packet payload = arp; - if (vlan != 0) { - // Add a VLAN tag. - IEEE8021Q tag = new IEEE8021Q(); - tag.setCfi((byte)0).setPcp((byte)0).setVid(vlan). - setEtherType(ethType).setPayload(arp); - ethType = EtherTypes.VLANTAGGED.shortValue(); - payload = tag; - } - - // Create an ethernet frame. - Ethernet ether = new Ethernet(); - ether.setSourceMACAddress(src).setDestinationMACAddress(dst). - setEtherType(ethType).setPayload(payload); - - return ether; - } - /** * Save virtual tenant configuration, and apply current configuration to * the VTN Manager. @@ -1888,11 +1756,6 @@ public class VTNManagerImpl loadTenantConfig(ctx, cfg, name); } - // Load flow conditions. - for (String name: cfg.getKeys(ContainerConfig.Type.FLOWCOND)) { - loadFlowCondition(cfg, name); - } - // Load container path maps. for (String name: cfg.getKeys(ContainerConfig.Type.PATHMAP)) { loadContainerPathMap(cfg, name); @@ -1917,16 +1780,6 @@ public class VTNManagerImpl // Remove configuration files for obsolete tenants. cfg.deleteAll(ContainerConfig.Type.TENANT, names); - // Update configuration files for flow conditions. - names.clear(); - for (FlowCondImpl fc: flowCondDB.values()) { - fc.saveConfig(this); - names.add(fc.getName()); - } - - // Remove configuration files for obsolete flow conditions. - cfg.deleteAll(ContainerConfig.Type.FLOWCOND, names); - // Update configuration files for container path maps. names.clear(); for (ContainerPathMapImpl cpm: pathMapDB.values()) { @@ -1964,29 +1817,6 @@ public class VTNManagerImpl } } - /** - * Load the specified flow condition from the file. - * - * @param cfg A {@link ContainerConfig} instance. - * @param name The name of the flow condition. - */ - private void loadFlowCondition(ContainerConfig cfg, String name) { - FlowCondImpl newfc = (FlowCondImpl) - cfg.load(ContainerConfig.Type.FLOWCOND, name); - if (newfc != null) { - FlowCondImpl fc = flowCondDB.putIfAbsent(name, newfc); - if (fc == null) { - if (LOG.isTraceEnabled()) { - LOG.trace("{}: Flow condition was loaded.", - containerName); - } else { - LOG.info("{}: Flow condition was loaded: {}", - containerName, name); - } - } - } - } - /** * Load the specified container path map from the file. * @@ -2076,18 +1906,6 @@ public class VTNManagerImpl return new Status(StatusCode.NOTFOUND, msg); } - /** - * Return a failure status that indicates the specified flow condition - * does not exist. - * - * @param name The name of the flow condition. - * @return A failure status. - */ - private Status flowConditionNotFound(String name) { - String msg = name + ": Flow condition does not exist"; - return new Status(StatusCode.NOTFOUND, msg); - } - /** * Return the name of the virtual tenant in the given tenant path. * @@ -2150,59 +1968,6 @@ public class VTNManagerImpl return vtn; } - /** - * Ensure that the specified flow condition name is not null. - * - * @param name The name of the flow condition. - * @throws VTNException An error occurred. - */ - private void checkFlowConditionName(String name) throws VTNException { - if (name == null) { - throw new VTNException(MiscUtils. - argumentIsNull("Flow condition name")); - } - } - - /** - * Return the flow condition instance associated with the given name. - * - *

- * This method must be called with the VTN Manager lock. - *

- * - * @param name The name of the flow condition. - * @return A flow condition associated with the specified name. - * @throws VTNException An error occurred. - */ - private FlowCondImpl getFlowCondImpl(String name) throws VTNException { - FlowCondImpl fc = flowCondDB.get(name); - if (fc == null) { - throw new VTNException(flowConditionNotFound(name)); - } - - return fc; - } - - /** - * Return the flow condition instance associated with the given name. - * - *
    - *
  • - * This method ensures that the specified name is not {@code null}. - *
  • - *
  • This method must be called with the VTN Manager lock.
  • - *
- * - * @param name The name of the flow condition. - * @return A flow condition associated with the specified name. - * @throws VTNException An error occurred. - */ - private FlowCondImpl getFlowCondImplCheck(String name) - throws VTNException { - checkFlowConditionName(name); - return getFlowCondImpl(name); - } - /** * Record an error log message which indicates an unexpected exception * was caught. @@ -3049,74 +2814,6 @@ public class VTNManagerImpl } } - /** - * Called when a flow condition was added, removed, or changed by - * remote cluster node. - * - * @param name The name of the flow condition. - * @param index The match index which specifies the flow match condition - * in the flow condition. A negative value is specified if - * the target is flow condition itself. - * @param type {@code ADDED} if added. - * {@code REMOVED} if removed. - * {@code CHANGED} if changed. - */ - public void updateFlowCondition(String name, int index, UpdateType type) { - ContainerConfig cfg = new ContainerConfig(containerName); - final ContainerConfig.Type cfgType = ContainerConfig.Type.FLOWCOND; - - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - if (type == UpdateType.REMOVED && index < 0) { - // Delete the configuration file for the flow condition. - cfg.delete(cfgType, name); - - if (index < 0) { - LOG.info("{}:{}: Flow condition was removed.", - containerName, name); - } else { - LOG.info("{}:{}.{}: Flow match condition was removed.", - containerName, name, index); - } - - return; - } - - // Save the configuration for the flow condition. - FlowCondImpl fc = flowCondDB.get(name); - if (fc == null) { - LOG.debug("{}:{}: Ignore phantom event of the " + - "flow condition: index={}", containerName, - name, index); - return; - } - - fc.saveConfig(this); - if (!LOG.isTraceEnabled()) { - // Record a simple informational log. - if (index < 0) { - LOG.info("{}:{}: Flow condition was {}.", - containerName, name, type.getName()); - } else { - LOG.info("{}:{}.{}: Flow match condition was {}.", - containerName, name, index, type.getName()); - } - return; - } - - if (index < 0) { - LOG.trace("{}:{}: Flow condition was {}: {}", - containerName, name, type.getName(), fc); - } else { - LOG.trace("{}:{}.{}: Flow match condition was {}: {}", - containerName, name, index, type.getName(), fc); - } - } finally { - rdlock.unlock(); - } - } - /** * Called when a container path map was added, removed, or changed by * remote cluster node. @@ -3246,17 +2943,17 @@ public class VTNManagerImpl } /** - * Remove all flows accepted by the specified {@link VTNFlowMatch} + * Remove all flows accepted by the specified {@link FlowSelector} * instance. * - * @param fmatch A {@link VTNFlowMatch} instance which determines VTN - * All flow entries are removed if {@code null} is - * specified. + * @param selector A {@link FlowSelector} instance which determines VTN + * All flow entries are removed if {@code null} is + * specified. * @return A list of {@link FlowRemoveTask} instances. */ - public List removeFlows(VTNFlowMatch fmatch) { + public List removeFlows(FlowSelector selector) { List list = new ArrayList<>(); - if (fmatch == null) { + if (selector == null) { for (VTNFlowDatabase fdb: vtnFlowMap.values()) { FlowRemoveTask task = fdb.clear(this); if (task != null) { @@ -3265,7 +2962,7 @@ public class VTNManagerImpl } } else { for (VTNFlowDatabase fdb: vtnFlowMap.values()) { - FlowRemoveTask task = fdb.removeFlows(this, fmatch); + FlowRemoveTask task = fdb.removeFlows(this, selector); if (task != null) { list.add(task); } @@ -3275,6 +2972,28 @@ public class VTNManagerImpl return list; } + /** + * Remove all flows accepted by the specified {@link FlowSelector} + * instance. + * + * @param tname The name of the VTN. + * @param selector A {@link FlowSelector} instance which determines VTN + * All flow entries are removed if {@code null} is + * specified. + * @return A list of {@link FlowRemoveTask} instances. + */ + public FlowRemoveTask removeFlows(String tname, FlowSelector selector) { + VTNFlowDatabase fdb = getTenantFlowDB(tname); + FlowRemoveTask task = null; + if (fdb != null) { + task = (selector == null) + ? fdb.clear(this) + : fdb.removeFlows(this, selector); + } + + return task; + } + /** * Change VTN mode if needed. * @@ -4742,8 +4461,8 @@ public class VTNManagerImpl } // Create an ARP request with specifying broadcast address. - byte[] bcast = EtherAddress.BROADCAST.getBytes(); - Ethernet ether = createArpRequest(bcast, addr); + Ethernet ether = new ArpPacketBuilder(). + build(getVTNConfig().getControllerMacAddress(), addr); if (ether == null) { return; } @@ -4829,7 +4548,9 @@ public class VTNManagerImpl } short vlan = host.getVlan(); - Ethernet ether = createArpRequest(dst, target, vlan); + Ethernet ether = new ArpPacketBuilder((int)vlan). + build(getVTNConfig().getControllerMacAddress(), + new EtherAddress(dst), target); if (ether == null) { LOG.debug("{}: probeHost: Ignore request for {}: " + "Invalid IP address", containerName, host); @@ -5095,22 +4816,25 @@ public class VTNManagerImpl */ @Override public List getFlowConditions() throws VTNException { - ArrayList list; - Lock rdlock = rwLock.readLock(); - rdlock.lock(); + ArrayList list = new ArrayList<>(); + VTNManagerProvider provider = checkService(); + TxContext ctx = provider.newTxContext(); try { - list = new ArrayList(flowCondDB.size()); - for (FlowCondImpl fc: flowCondDB.values()) { - list.add(fc.getFlowCondition()); + ReadTransaction rtx = ctx.getTransaction(); + List vlist = + FlowCondUtils.readFlowConditions(rtx); + for (VTNFlowCondition vfcond: vlist) { + list.add(vfcond.toFlowCondition()); } } finally { - rdlock.unlock(); + ctx.cancelTransaction(); } // Sort flow conditions by their name. VTNIdentifiableComparator comparator = new VTNIdentifiableComparator<>(String.class); Collections.sort(list, comparator); + return list; } @@ -5124,13 +4848,15 @@ public class VTNManagerImpl */ @Override public FlowCondition getFlowCondition(String name) throws VTNException { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); + VTNManagerProvider provider = checkService(); + TxContext ctx = provider.newTxContext(); try { - FlowCondImpl fc = getFlowCondImplCheck(name); - return fc.getFlowCondition(); + ReadTransaction rtx = ctx.getTransaction(); + VTNFlowCondition vfcond = + FlowCondUtils.readFlowCondition(rtx, name); + return vfcond.toFlowCondition(); } finally { - rdlock.unlock(); + ctx.cancelTransaction(); } } @@ -5147,63 +4873,22 @@ public class VTNManagerImpl @Override public UpdateType setFlowCondition(String name, FlowCondition fcond) throws VTNException { - MiscUtils.checkName("Flow condition", name); - - VTNThreadData data = VTNThreadData.create(rwLock.writeLock()); - try { - checkUpdate(); - - UpdateType result; - FlowCondImpl fc; - while (true) { - FlowCondImpl oldfc = flowCondDB.get(name); - if (oldfc == null) { - // Create a new flow condition. - fc = new FlowCondImpl(name, fcond); - if (flowCondDB.putIfAbsent(name, fc) == null) { - result = UpdateType.ADDED; - break; - } - } else { - // Update existing flow condition. - fc = oldfc.clone(); - List matches = (fcond == null) - ? null : fcond.getMatches(); - if (!fc.setMatches(matches)) { - // No change was made to flow condition. - return null; - } - - if (flowCondDB.replace(name, oldfc, fc)) { - result = UpdateType.CHANGED; - break; - } - } - } - - // REVISIT: Select flow entries affected by the change. - for (VTNFlowDatabase fdb: vtnFlowMap.values()) { - VTNThreadData.removeFlows(this, fdb); - } + VTNManagerProvider provider = checkUpdate(); - Status status = fc.saveConfig(this); - if (!status.isSuccess()) { - throw new VTNException(status); - } + // Construct an RPC input that replaces the flow condition specified + // by the given name. + VTNFlowCondition vfcond = new VTNFlowCondition(name, fcond); + SetFlowConditionInput input = vfcond.toSetFlowConditionInputBuilder(). + setOperation(VtnUpdateOperationType.SET).build(); - if (LOG.isTraceEnabled()) { - LOG.trace("{}:{}: Flow condition was {}: {}", - containerName, name, result.getName(), fcond); - } else { - LOG.info("{}:{}: Flow condition was {}.", - containerName, name, result.getName()); - } - FlowConditionEvent.raise(this, name, result); + // Invoke RPC and await its completion. + VtnFlowConditionService rpc = + provider.getVtnRpcService(VtnFlowConditionService.class); + SetFlowConditionOutput output = + getRpcOutput(rpc.setFlowCondition(input)); - return result; - } finally { - data.cleanUp(this); - } + // Convert the result. + return MiscUtils.toUpdateType(output.getStatus()); } /** @@ -5215,35 +4900,17 @@ public class VTNManagerImpl */ @Override public Status removeFlowCondition(String name) { - VTNThreadData data = VTNThreadData.create(rwLock.writeLock()); try { - checkFlowConditionName(name); - checkUpdate(); - - FlowCondImpl fc = flowCondDB.remove(name); - if (fc == null) { - return flowConditionNotFound(name); - } - - // REVISIT: Select flow entries affected by the change. - for (VTNFlowDatabase fdb: vtnFlowMap.values()) { - VTNThreadData.removeFlows(this, fdb); - } - - fc.destroy(this); + VTNManagerProvider provider = checkUpdate(); + RemoveFlowConditionInput input = + new RemoveFlowConditionInputBuilder().setName(name).build(); - if (LOG.isTraceEnabled()) { - LOG.trace("{}:{}: Flow condition was removed: {}", - containerName, name, fc.getFlowCondition()); - } else { - LOG.info("{}:{}: Flow condition was removed.", - containerName, name); - } - FlowConditionEvent.raise(this, name, UpdateType.REMOVED); + // Invoke RPC and await its completion. + VtnFlowConditionService rpc = + provider.getVtnRpcService(VtnFlowConditionService.class); + getRpcOutput(rpc.removeFlowCondition(input), true); } catch (VTNException e) { return e.getStatus(); - } finally { - data.cleanUp(this); } return new Status(StatusCode.SUCCESS, null); @@ -5265,13 +4932,15 @@ public class VTNManagerImpl @Override public FlowMatch getFlowConditionMatch(String name, int index) throws VTNException { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); + VTNManagerProvider provider = checkService(); + TxContext ctx = provider.newTxContext(); try { - FlowCondImpl fc = getFlowCondImplCheck(name); - return fc.getMatch(index); + ReadTransaction rtx = ctx.getTransaction(); + VTNFlowMatch vfmatch = + FlowCondUtils.readFlowMatch(rtx, name, index); + return (vfmatch == null) ? null : vfmatch.toFlowMatch(); } finally { - rdlock.unlock(); + ctx.cancelTransaction(); } } @@ -5292,7 +4961,7 @@ public class VTNManagerImpl public UpdateType setFlowConditionMatch(String name, int index, FlowMatch match) throws VTNException { - checkFlowConditionName(name); + VTNManagerProvider provider = checkUpdate(); // Complete FlowMatch instance. FlowMatch mt; @@ -5304,46 +4973,30 @@ public class VTNManagerImpl mt = match.assignIndex(index); } - // Acquire writer lock in order to block notifyPacket(). - VTNThreadData data = VTNThreadData.create(rwLock.writeLock()); - try { - checkUpdate(); - - UpdateType result; - FlowCondImpl fc, oldfc; - do { - oldfc = getFlowCondImpl(name); - fc = oldfc.clone(); - result = fc.setMatch(mt); - if (result == null) { - // No change was made to flow condition. - return null; - } - } while (!flowCondDB.replace(name, oldfc, fc)); - - // REVISIT: Select flow entries affected by the change. - for (VTNFlowDatabase fdb: vtnFlowMap.values()) { - VTNThreadData.removeFlows(this, fdb); - } - - Status status = fc.saveConfig(this); - if (!status.isSuccess()) { - throw new VTNException(status); - } + VTNFlowMatch vfmatch = new VTNFlowMatch(mt); + List fml = + Collections.singletonList(vfmatch.toFlowMatchListBuilder().build()); - if (LOG.isTraceEnabled()) { - LOG.trace("{}:{}.{}: Flow match condition was {}: {}", - containerName, name, index, result.getName(), mt); - } else { - LOG.info("{}:{}.{}: Flow match condition was {}.", - containerName, name, index, result.getName()); - } - FlowConditionEvent.raise(this, name, index, result); + // Construct an RPC input that adds the given flow match configuration + // to the specified flow condition. + SetFlowConditionMatchInput input = new SetFlowConditionMatchInputBuilder(). + setName(name).setFlowMatchList(fml).build(); - return result; - } finally { - data.cleanUp(this); + // Invoke RPC and await its completion. + VtnFlowConditionService rpc = + provider.getVtnRpcService(VtnFlowConditionService.class); + SetFlowConditionMatchOutput output = + getRpcOutput(rpc.setFlowConditionMatch(input)); + SetMatchResult result = + getRpcOutput(output.getSetMatchResult(), 0, false); + Integer idx = vfmatch.getIdentifier(); + if (!idx.equals(result.getIndex())) { + throw new VTNException("Unexpected match index in RPC output: " + + output.getSetMatchResult()); } + + // Convert the result. + return MiscUtils.toUpdateType(result.getStatus()); } /** @@ -5358,50 +5011,37 @@ public class VTNManagerImpl */ @Override public Status removeFlowConditionMatch(String name, int index) { - // Acquire writer lock in order to block notifyPacket(). - VTNThreadData data = VTNThreadData.create(rwLock.writeLock()); + Integer idx = Integer.valueOf(index); try { - checkFlowConditionName(name); - checkUpdate(); + VTNManagerProvider provider = checkUpdate(); - FlowCondImpl fc, oldfc; - FlowMatchImpl fm; - do { - oldfc = getFlowCondImpl(name); - fc = oldfc.clone(); - fm = fc.removeMatch(index); - if (fm == null) { - // No change was made to flow condition. - return null; - } - } while (!flowCondDB.replace(name, oldfc, fc)); + // Construct an RPC input that removes the flow match associated + // with the given index in the flow condition. + RemoveFlowConditionMatchInput input = new RemoveFlowConditionMatchInputBuilder(). + setName(name).setMatchIndex(Collections.singletonList(idx)). + build(); - // REVISIT: Select flow entries affected by the change. - for (VTNFlowDatabase fdb: vtnFlowMap.values()) { - VTNThreadData.removeFlows(this, fdb); + // Invoke RPC and await its completion. + VtnFlowConditionService rpc = + provider.getVtnRpcService(VtnFlowConditionService.class); + RemoveFlowConditionMatchOutput output = + getRpcOutput(rpc.removeFlowConditionMatch(input)); + RemoveMatchResult result = + getRpcOutput(output.getRemoveMatchResult(), 0, false); + if (!idx.equals(result.getIndex())) { + throw new VTNException( + "Unexpected match index in RPC output: " + + output.getRemoveMatchResult()); } - - Status status = fc.saveConfig(this); - if (status.isSuccess()) { - if (LOG.isTraceEnabled()) { - LOG.trace("{}:{}.{}: " + - "Flow match condition was removed: {}", - containerName, name, index, fm); - } else { - LOG.info("{}:{}.{}: Flow match condition was removed.", - containerName, name, index); - } - - FlowConditionEvent.raise(this, name, index, - UpdateType.REMOVED); + if (result.getStatus() == null) { + // The specified match index was not found. + return null; } - - return status; } catch (VTNException e) { return e.getStatus(); - } finally { - data.cleanUp(this); } + + return new Status(StatusCode.SUCCESS, null); } /** @@ -5686,9 +5326,6 @@ public class VTNManagerImpl getRpcOutput(rpc.removePathCost(input)); RemovePathCostResult result = getRpcOutput(output.getRemovePathCostResult(), 0, false); - if (result == null) { - throw new VTNException("RPC set null as result."); - } if (!vdesc.equals(result.getPortDesc())) { throw new VTNException("Unexpected port desc in RPC output: " + output.getRemovePathCostResult()); @@ -5697,8 +5334,6 @@ public class VTNManagerImpl // The specified path cost configuration did not exist. return null; } - - return new Status(StatusCode.SUCCESS, null); } catch (VTNException e) { return e.getStatus(); } finally { @@ -5706,6 +5341,8 @@ public class VTNManagerImpl ctx.cancelTransaction(); } } + + return new Status(StatusCode.SUCCESS, null); } /** @@ -6343,14 +5980,6 @@ public class VTNManagerImpl } } - // Save flow condition configurations. - for (FlowCondImpl fc: flowCondDB.values()) { - Status st = fc.saveConfig(this); - if (!st.isSuccess()) { - status = st; - } - } - return status; } finally { unlock(rdlock); @@ -6538,9 +6167,9 @@ public class VTNManagerImpl // Create a packet context. PacketContext pctx = new PacketContext(ev); - byte[] src = pctx.getSourceAddress(); - byte[] ctlrMac = getVTNConfig().getControllerMacAddress().getBytes(); - if (Arrays.equals(src, ctlrMac)) { + EtherAddress src = pctx.getSourceAddress(); + EtherAddress ctlrMac = getVTNConfig().getControllerMacAddress(); + if (src.equals(ctlrMac)) { if (LOG.isTraceEnabled()) { NodeConnector nc = ev.getIngressPort().getAdNodeConnector(); LOG.trace("{}: Ignore self-originated packet: {}", @@ -6574,8 +6203,10 @@ public class VTNManagerImpl } // Determine virtual network mapping that maps the packet. - short vlan = pctx.getVlan(); - MapReference ref = resourceManager.getMapReference(src, nc, vlan); + short vlan = (short)pctx.getVlan(); + byte[] srcMac = src.getBytes(); + MapReference ref = + resourceManager.getMapReference(srcMac, nc, vlan); if (ref != null && containerName.equals(ref.getContainerName())) { pctx.setMapReference(ref); VNodePath path = ref.getPath(); diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerProvider.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerProvider.java index 8e38e94a..f18ce9e5 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerProvider.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerProvider.java @@ -131,13 +131,30 @@ public interface VTNManagerProvider extends AutoCloseable, Executor, TxQueue { * Note that this method affects all VTNs. *

* - * @param fmatch A {@link VTNFlowMatch} instance. - * All flow entries are removed if {@code null} is - * specified. + * @param selector A {@link FlowSelector} instance. + * All flow entries are removed if {@code null} is + * specified. * @return A list of {@link VTNFuture} instances associated with flow * removal tasks. */ - List> removeFlows(VTNFlowMatch fmatch); + List> removeFlows(FlowSelector selector); + + /** + * Remove flow entries that match the given condition. + * + *

+ * Note that this method removes flow entries present in the specified + * VTN. + *

+ * + * @param tname The name of the VTN. + * @param selector A {@link FlowSelector} instance. + * All flow entries are removed if {@code null} is + * specified. + * @return A {@link VTNFuture} instance associated with flow removal task. + * {@code null} if no flow entry is removed. + */ + VTNFuture removeFlows(String tname, FlowSelector selector); /** * Return an implementation of the specified RPC service. diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNSubSystem.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNSubSystem.java new file mode 100644 index 00000000..79ef7f8b --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNSubSystem.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal; + +import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; +import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; + +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; + +/** + * {@code VTNSubSystem} describes a manager instance for a subsystem in the + * VTN Manager. + */ +public interface VTNSubSystem extends AutoCloseable { + /** + * Post a MD-SAL datastore transaction task that initializes the + * configuration. + * + * @param master {@code true} if the local node is the configuration + * provider. + * @return A {@link VTNFuture} instance associated with the task for + * initialization. {@code null} means that there is nothing to + * do on initialization. + */ + VTNFuture initConfig(boolean master); + + /** + * Register RPC implementation required by the subsystem. + * + * @param rpcReg A {@link RpcProviderRegistry} service instance. + * @param regs A {@link CompositeAutoCloseable} instance to store + * RPC registration. + */ + void initRpcServices(RpcProviderRegistry rpcReg, + CompositeAutoCloseable regs); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNThreadData.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNThreadData.java index 4582e542..753936fa 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNThreadData.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNThreadData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014 NEC Corporation + * Copyright (c) 2013-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -171,7 +171,7 @@ public final class VTNThreadData { } /** - * Remove all VTN flows accepted by the specified {@link VTNFlowMatch} + * Remove all VTN flows accepted by the specified {@link FlowSelector} * instance. * *

@@ -183,22 +183,22 @@ public final class VTNThreadData { * * @param mgr VTN Manager service. * @param tenantName The name of the virtual tenant. - * @param fmatch A {@link VTNFlowMatch} instance which determines + * @param selector A {@link FlowSelector} instance which determines * VTN flows to be removed. * Specifying {@code null} results in undefined * behavior. - * @see VTNFlowDatabase#removeFlows(VTNManagerImpl, VTNFlowMatch) + * @see VTNFlowDatabase#removeFlows(VTNManagerImpl, FlowSelector) */ public static void removeFlows(VTNManagerImpl mgr, String tenantName, - VTNFlowMatch fmatch) { + FlowSelector selector) { VTNFlowDatabase fdb = mgr.getTenantFlowDB(tenantName); if (fdb != null) { - addTask(fdb.removeFlows(mgr, fmatch)); + addTask(fdb.removeFlows(mgr, selector)); } } /** - * Remove all VTN flows accepted by the specified {@link VTNFlowMatch} + * Remove all VTN flows accepted by the specified {@link FlowSelector} * instance. * *

@@ -208,17 +208,18 @@ public final class VTNThreadData { * when {@link #cleanUp(VTNManagerImpl)} is called. *

* - * @param mgr VTN Manager service. - * @param fdb VTN flow database object associated with the virtual tenant. - * @param fmatch A {@link VTNFlowMatch} instance which determines - * VTN flows to be removed. - * Specifying {@code null} results in undefined - * behavior. - * @see VTNFlowDatabase#removeFlows(VTNManagerImpl, VTNFlowMatch) + * @param mgr VTN Manager service. + * @param fdb VTN flow database object associated with the virtual + * tenant. + * @param selector A {@link FlowSelector} instance which determines + * VTN flows to be removed. + * Specifying {@code null} results in undefined + * behavior. + * @see VTNFlowDatabase#removeFlows(VTNManagerImpl, FlowSelector) */ public static void removeFlows(VTNManagerImpl mgr, VTNFlowDatabase fdb, - VTNFlowMatch fmatch) { - addTask(fdb.removeFlows(mgr, fmatch)); + FlowSelector selector) { + addTask(fdb.removeFlows(mgr, selector)); } /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/DlAddrActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/DlAddrActionImpl.java index da09167d..497d3ecd 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/DlAddrActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/DlAddrActionImpl.java @@ -9,11 +9,10 @@ package org.opendaylight.vtn.manager.internal.cluster; -import java.util.Arrays; +import java.util.Objects; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.DlAddrAction; -import org.opendaylight.vtn.manager.util.ByteUtils; import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.internal.util.MiscUtils; @@ -39,7 +38,7 @@ public abstract class DlAddrActionImpl extends FlowActionImpl { /** * MAC address to be set. */ - private final byte[] address; + private final EtherAddress address; /** * Construct a new instance. @@ -56,45 +55,37 @@ public abstract class DlAddrActionImpl extends FlowActionImpl { throw new VTNException(st); } - byte[] addr = act.getAddress(); - if (addr == null) { + address = act.getEtherAddress(); + if (address == null) { String msg = getErrorMessage(act, "MAC address"); st = MiscUtils.argumentIsNull(msg); throw new VTNException(st); } - if (addr.length != EtherAddress.SIZE) { - String msg = getErrorMessage( - act, "Invalid MAC address length: ", - ByteUtils.toHexString(addr)); - throw new VTNException(StatusCode.BADREQUEST, msg); - } - - if (EtherAddress.isBroadcast(addr)) { + if (address.isBroadcast()) { String msg = getErrorMessage( act, "Broadcast address cannot be specified"); throw new VTNException(StatusCode.BADREQUEST, msg); } - if (!EtherAddress.isUnicast(addr)) { + if (!address.isUnicast()) { String msg = getErrorMessage( act, "Multicast address cannot be specified: ", - ByteUtils.toHexString(addr)); + address.getText()); throw new VTNException(StatusCode.BADREQUEST, msg); } - if (EtherAddress.toLong(addr) == 0) { + if (address.getAddress() == 0L) { String msg = getErrorMessage(act, "Zero cannot be specified"); throw new VTNException(StatusCode.BADREQUEST, msg); } - - address = addr.clone(); } /** * Return a raw bytes of MAC address. * - * @return An array of bytes which represents a MAC address. + * @return An {@link EtherAddress} instance which represents + * a MAC address. */ - protected final byte[] getAddress() { + protected final EtherAddress getAddress() { return address; } @@ -114,7 +105,7 @@ public abstract class DlAddrActionImpl extends FlowActionImpl { } DlAddrActionImpl act = (DlAddrActionImpl)o; - return Arrays.equals(address, act.address); + return Objects.equals(address, act.address); } /** @@ -124,7 +115,12 @@ public abstract class DlAddrActionImpl extends FlowActionImpl { */ @Override public final int hashCode() { - return super.hashCode() ^ Arrays.hashCode(address); + int hash = super.hashCode(); + if (address != null) { + hash ^= address.hashCode(); + } + + return hash; } /** @@ -136,7 +132,6 @@ public abstract class DlAddrActionImpl extends FlowActionImpl { public String toString() { StringBuilder builder = new StringBuilder(getClass().getSimpleName()); return builder.append("[addr="). - append(ByteUtils.toHexString(address)). - append(']').toString(); + append(address.getText()).append(']').toString(); } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImpl.java deleted file mode 100644 index d50a2331..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImpl.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; -import org.opendaylight.vtn.manager.util.EtherAddress; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.packet.cache.EtherPacket; -import org.opendaylight.vtn.manager.internal.util.MiscUtils; -import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.address.EthernetAddress; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code EthernetMatchImpl} describes the condition to match Ethernet header - * fields in packet. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class EthernetMatchImpl implements PacketMatch { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -3306965790129460767L; - - /** - * A pseudo MAC address which indicates every MAC address should match. - */ - private static final long MAC_ANY = -1L; - - /** - * A pseudo Ethernet type value which indicates every Ethernet type - * should match. - */ - private static final int ETHTYPE_ANY = -1; - - /** - * A pseudo VLAN ID which indicates every VLAN ID should match. - */ - private static final short VLAN_ANY = -1; - - /** - * A pseudo VLAN priority which indicates every VLAN priority should match. - */ - private static final byte VLANPRI_ANY = -1; - - /** - * A mask value which represents valid bits in an Ethernet type. - */ - private static final int MASK_TYPE = 0xffff; - - /** - * Source MAC address to match. - */ - private final long sourceAddress; - - /** - * Destination MAC address to match. - */ - private final long destinationAddress; - - /** - * Ethernet type to match. - */ - private int etherType; - - /** - * VLAN ID to match. - */ - private final short vlan; - - /** - * VLAN priority to match. - */ - private final byte vlanPriority; - - /** - * Construct a new instance which specifies only the condition for the - * Ethernet type. - * - * @param type An Ethernet type. - */ - public EthernetMatchImpl(int type) { - sourceAddress = MAC_ANY; - destinationAddress = MAC_ANY; - etherType = type; - vlan = VLAN_ANY; - vlanPriority = VLANPRI_ANY; - } - - /** - * Construct a new instance. - * - * @param match An {@link EthernetMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - public EthernetMatchImpl(EthernetMatch match) throws VTNException { - Status st = match.getValidationStatus(); - if (st != null) { - throw new VTNException(st); - } - - sourceAddress = getMacAddress(match.getSourceAddress()); - destinationAddress = getMacAddress(match.getDestinationAddress()); - - Integer i = match.getType(); - if (i == null) { - etherType = ETHTYPE_ANY; - } else { - etherType = i.intValue(); - if ((etherType & ~MASK_TYPE) != 0) { - String msg = "Invalid Ethernet type: " + i; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - } - - Short s = match.getVlan(); - if (s == null) { - vlan = VLAN_ANY; - } else { - vlan = s.shortValue(); - ProtocolUtils.checkVlan(vlan); - } - - Byte b = match.getVlanPriority(); - if (b == null) { - vlanPriority = VLANPRI_ANY; - } else { - vlanPriority = b.byteValue(); - if (!ProtocolUtils.isVlanPriorityValid(vlanPriority)) { - String msg = "Invalid VLAN priority: " + b; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - if (vlan <= 0) { - String msg = "VLAN priority requires a valid VLAN ID."; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - } - } - - /** - * Return a long value which represents the source MAC address to match - * against packets. - * - * @return A long value which represents the source MAC address to match. - * A negative value is returned if the source MAC address is - * not specified. - */ - public long getSourceAddress() { - return sourceAddress; - } - - /** - * Return a long value which represents the destination MAC address to - * match against packets. - * - * @return A long value which represents the destination MAC address to - * match. A negative value is returned if the source MAC address - * is not specified. - */ - public long getDestinationAddress() { - return destinationAddress; - } - - /** - * Return the Ethernet type to match against packets. - * - * @return An integer which represents the Ethernet type to mach against - * packets. A negative value is returned if the Ethernet type is - * not specified. - */ - public int getEtherType() { - return etherType; - } - - /** - * Return the VLAN ID to match against packets. - * - * @return A short integer value which represents the VLAN ID to mach - * against packets. A negative value is returned if the VLAN ID - * is not specified. - */ - public short getVlan() { - return vlan; - } - - /** - * Return the VLAN priority to match against packets. - * - * @return A byte value which represents the VLAN priority to mach - * against packets. A negative value is returned if the - * VLAN priority is not specified. - */ - public byte getVlanPriority() { - return vlanPriority; - } - - /** - * Return an {@link EthernetMatch} instance which represents this - * condition. - * - * @return An {@link EthernetMatch} instance. - */ - public EthernetMatch getMatch() { - EthernetAddress src = toEthernetAddress(sourceAddress); - EthernetAddress dst = toEthernetAddress(destinationAddress); - Integer ethType = (etherType < 0) ? null : Integer.valueOf(etherType); - Short vid = (vlan < 0) ? null : Short.valueOf(vlan); - Byte pri = (vlanPriority < 0) ? null : Byte.valueOf(vlanPriority); - - return new EthernetMatch(src, dst, ethType, vid, pri); - } - - /** - * Set the Ethernet type to match against packets. - * - * @param type An Ethernet type. - * @throws VTNException - * The specified type is different from the type in this instance. - */ - void setEtherType(int type) throws VTNException { - if (etherType != ETHTYPE_ANY && etherType != type) { - StringBuilder builder = - new StringBuilder("Ethernet type conflict: type=0x"); - builder.append(Integer.toHexString(etherType)). - append(", expected=0x").append(Integer.toHexString(type)); - throw new VTNException(StatusCode.BADREQUEST, builder.toString()); - } - - etherType = type; - } - - /** - * Convert an {@link EthernetAddress} instance into a long integer value. - * - * @param eaddr An {@link EthernetAddress} instance or {@code null}. - * @return A long integer which represents the specified value. - * {@link #MAC_ANY} is returned if {@code null} is specified. - */ - private long getMacAddress(EthernetAddress eaddr) { - if (eaddr == null) { - return MAC_ANY; - } - - byte[] raw = eaddr.getValue(); - return EtherAddress.toLong(raw); - } - - /** - * Convert a long integer value into an {@link EthernetAddress} instance. - * - * @param mac A long integer which represents a MAC address. - * @return A {@link EthernetAddress} instance converted from the specified - * value. - * {@code null} is returned if {@link #MAC_ANY} is specified. - */ - private EthernetAddress toEthernetAddress(long mac) { - if (mac == MAC_ANY) { - return null; - } - - byte[] b = EtherAddress.toBytes(mac); - try { - return new EthernetAddress(b); - } catch (Exception e) { - // This should never happen. - StringBuilder builder = - new StringBuilder("Unexpected exception: addr="); - builder.append(Long.toHexString(mac)); - throw new IllegalStateException(builder.toString(), e); - } - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof EthernetMatchImpl)) { - return false; - } - - EthernetMatchImpl match = (EthernetMatchImpl)o; - return (sourceAddress == match.sourceAddress && - destinationAddress == match.destinationAddress && - etherType == match.etherType && vlan == match.vlan && - vlanPriority == match.vlanPriority); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - return NumberUtils.hashCode(sourceAddress) + - (NumberUtils.hashCode(destinationAddress) * 7) + - (etherType * 13) + ((int)vlan * 17) * (vlanPriority * 31); - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder("EthernetMatchImpl["); - String sep = ""; - if (sourceAddress != MAC_ANY) { - builder.append(sep).append("src="). - append(MiscUtils.formatMacAddress(sourceAddress)); - sep = ","; - } - if (destinationAddress != MAC_ANY) { - builder.append(sep).append("dst="). - append(MiscUtils.formatMacAddress(destinationAddress)); - sep = ","; - } - if (etherType != ETHTYPE_ANY) { - builder.append(sep).append("type=0x"). - append(Integer.toHexString(etherType)); - sep = ","; - } - if (vlan != VLAN_ANY) { - builder.append(sep).append("vlan=").append((int)vlan); - sep = ","; - } - if (vlanPriority != VLANPRI_ANY) { - builder.append(sep).append("pcp=").append((int)vlanPriority); - } - - builder.append(']'); - - return builder.toString(); - } - - // PacketMatch - - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - @Override - public boolean match(PacketContext pctx) { - EtherPacket ether = pctx.getEtherPacket(); - - // Test source MAC address. - if (sourceAddress != MAC_ANY) { - pctx.addMatchField(MatchType.DL_SRC); - if (sourceAddress != ether.getSourceMacAddress()) { - return false; - } - } - - // Test destination MAC address. - if (destinationAddress != MAC_ANY) { - pctx.addMatchField(MatchType.DL_DST); - if (destinationAddress != ether.getDestinationMacAddress()) { - return false; - } - } - - // Test Ethernet type. - if (etherType != ETHTYPE_ANY) { - pctx.addMatchField(MatchType.DL_TYPE); - if (etherType != ether.getEtherType()) { - return false; - } - } - - // Test VLAN ID. - // We don't need to set DL_VLAN field to PacketContext because it is - // mandatory. - if (vlan != VLAN_ANY) { - if (vlan != ether.getVlan()) { - return false; - } - - // Test VLAN priority only if a VLAN ID is specified. - if (vlanPriority != VLANPRI_ANY) { - pctx.addMatchField(MatchType.DL_VLAN_PR); - if (vlanPriority != ether.getVlanPriority()) { - return false; - } - } - } - - return true; - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImpl.java deleted file mode 100644 index e3c3ec3e..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImpl.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.NavigableMap; -import java.util.TreeMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.FlowCondition; -import org.opendaylight.vtn.manager.flow.cond.FlowMatch; -import org.opendaylight.vtn.manager.internal.ContainerConfig; -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; - -import org.opendaylight.controller.sal.core.UpdateType; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * Implementation of flow condition. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class FlowCondImpl implements Serializable, Cloneable { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -8740384891077272459L; - - /** - * Logger instance. - */ - private static final Logger LOG = - LoggerFactory.getLogger(FlowCondImpl.class); - - /** - * The name of the flow condition. - */ - private final String name; - - /** - * A list of {@link FlowMatchImpl} instances sorted by match index. - */ - private NavigableMap matches; - - /** - * Read write lock to synchronize {@link #matches}. - */ - private transient ReentrantReadWriteLock rwLock = - new ReentrantReadWriteLock(); - - /** - * Construct a new instance. - * - * @param name The name of the flow condition. - * @param fcond A {@link FlowCondition} instance. - * @throws VTNException An error occurred. - */ - public FlowCondImpl(String name, FlowCondition fcond) throws VTNException { - this.name = name; - - List list = (fcond == null) ? null : fcond.getMatches(); - this.matches = createMatches(list); - } - - /** - * Return the name of the flow condition. - * - * @return The name of the flow condition. - */ - public String getName() { - return name; - } - - /** - * Return a {@link FlowCondition} instance which represents this - * flow condition. - * - * @return A {@link FlowCondition} instance. - */ - public FlowCondition getFlowCondition() { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - List list = new ArrayList(matches.size()); - for (FlowMatchImpl fc: matches.values()) { - list.add(fc.getMatch()); - } - - return new FlowCondition(name, list); - } finally { - rdlock.unlock(); - } - } - - /** - * Change the list of {@link FlowMatch} instances as specified. - * - * @param list A list of {@link FlowMatch} instances. - * @return {@code true} if the list was actually changed. - * {@code false} if the list was not changed. - * @throws VTNException An error occurred. - */ - public boolean setMatches(List list) throws VTNException { - NavigableMap map = createMatches(list); - Lock wrlock = rwLock.writeLock(); - wrlock.lock(); - try { - boolean changed = !map.equals(matches); - matches = map; - - return changed; - } finally { - wrlock.unlock(); - } - } - - /** - * Return the flow match at the specified match index. - * - * @param index A match index. - * @return A {@link FlowMatch} instance if found. - * {@code null} if not found. - */ - public FlowMatch getMatch(int index) { - Integer idx = Integer.valueOf(index); - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - FlowMatchImpl match = matches.get(idx); - return (match == null) ? null : match.getMatch(); - } finally { - rdlock.unlock(); - } - } - - /** - * Update the condition at the specified index. - * - * @param match A {@link FlowMatch} instance. - * @return {@link UpdateType#ADDED} if the specified match condition was - * newly added. - * {@link UpdateType#CHANGED} if the flow match at the index - * configured in {@code match} was changed. - * {@code null} if the flow match was not changed. - * @throws VTNException An error occurred. - */ - public UpdateType setMatch(FlowMatch match) throws VTNException { - FlowMatchImpl fc = new FlowMatchImpl(match); - Integer idx = fc.getIndex(); - Lock wrlock = rwLock.writeLock(); - wrlock.lock(); - try { - FlowMatchImpl old = matches.put(idx, fc); - UpdateType ret; - if (old == null) { - ret = UpdateType.ADDED; - } else if (old.equals(fc)) { - ret = null; - } else { - ret = UpdateType.CHANGED; - } - - return ret; - } finally { - wrlock.unlock(); - } - } - - /** - * Remove the flow match at the specified index. - * - * @param index The match index which specifies the flow match to be - * removed. - * @return A {@link FlowMatchImpl} instance removed from this instance. - * {@code null} if no flow match was found at the specified - * index. - */ - public FlowMatchImpl removeMatch(int index) { - Integer idx = Integer.valueOf(index); - Lock wrlock = rwLock.writeLock(); - wrlock.lock(); - try { - return matches.remove(idx); - } finally { - wrlock.unlock(); - } - } - - /** - * Determine whether this flow condition matches the specified packet - * or not. - * - * @param mgr VTN Manager service. - * @param pctx A packet context which contains the packet. - * @return {@code true} if this flow condition matches the specified - * packet. Otherwise {@code false}. - */ - public boolean match(VTNManagerImpl mgr, PacketContext pctx) { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - if (matches.isEmpty()) { - if (LOG.isTraceEnabled()) { - LOG.trace("{}: {}: Matched an empty condition: packet={}", - mgr.getContainerName(), name, - pctx.getDescription(null)); - } - return true; - } - - for (FlowMatchImpl match: matches.values()) { - if (match.match(pctx)) { - if (LOG.isTraceEnabled()) { - LOG.trace("{}: {}: Matched the condition: match={}, " + - "packet={}", mgr.getContainerName(), name, - match, pctx.getDescription(null)); - } - return true; - } - } - - if (LOG.isTraceEnabled()) { - LOG.trace("{}: Unmatched: packet={}", name, - pctx.getDescription(null)); - } - return false; - } finally { - rdlock.unlock(); - } - } - - /** - * Save the configuration of this flow condition to the configuration file. - * - * @param mgr VTN Manager service. - * @return "Success" or failure reason. - */ - public Status saveConfig(VTNManagerImpl mgr) { - Status status; - String container = mgr.getContainerName(); - ContainerConfig cfg = new ContainerConfig(container); - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - status = cfg.save(ContainerConfig.Type.FLOWCOND, name, this); - if (status.isSuccess()) { - if (LOG.isTraceEnabled()) { - LOG.trace("{}:{}: Flow condition was saved", - container, name); - } - return status; - } - } finally { - rdlock.unlock(); - } - - String msg = "Failed to save flow condition configuration"; - LOG.error("{}:{}: {}: {}", container, name, msg, status); - return new Status(StatusCode.INTERNALERROR, msg); - } - - /** - * Destroy this flow condition. - * - * @param mgr VTN Manager service. - */ - public void destroy(VTNManagerImpl mgr) { - String container = mgr.getContainerName(); - ContainerConfig cfg = new ContainerConfig(container); - cfg.delete(ContainerConfig.Type.FLOWCOND, name); - } - - /** - * Construct a flow condition map from the specified list of - * {@link FlowMatch} instances. - * - * @param list A list of {@link FlowMatch} instances. - * @return A map which contains flow conditions. - * @throws VTNException An error occurred. - */ - private NavigableMap createMatches( - List list) throws VTNException { - TreeMap map = - new TreeMap(); - if (list != null) { - for (FlowMatch match: list) { - FlowMatchImpl fc = new FlowMatchImpl(match); - int index = fc.getIndex(); - Integer idx = Integer.valueOf(index); - if (map.put(idx, fc) != null) { - String msg = "Duplicate match index: " + idx; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - } - } - - return map; - } - - /** - * Create a copy of {@link #matches}. - * - * @return A copy of {@link #matches}. - */ - private NavigableMap copyMatches() { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - return (NavigableMap) - ((TreeMap)matches).clone(); - } finally { - rdlock.unlock(); - } - } - - /** - * Read data from the given input stream and deserialize. - * - * @param in An input stream. - * @throws IOException - * An I/O error occurred. - * @throws ClassNotFoundException - * At least one necessary class was not found. - */ - @SuppressWarnings("unused") - private void readObject(ObjectInputStream in) - throws IOException, ClassNotFoundException { - // Read serialized fields. - // Note that the lock does not need to be acquired here because this - // instance is not yet visible. - in.defaultReadObject(); - - // Reset the lock. - rwLock = new ReentrantReadWriteLock(); - } - - /** - * Serialize this object and write it to the given output stream. - * - * @param out An output stream. - * @throws IOException - * An I/O error occurred. - */ - @SuppressWarnings("unused") - private void writeObject(ObjectOutputStream out) - throws IOException { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - out.defaultWriteObject(); - } finally { - rdlock.unlock(); - } - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof FlowCondImpl)) { - return false; - } - - FlowCondImpl fc = (FlowCondImpl)o; - - // Create a copy of matches in order to avoid deadlock. - NavigableMap otherMatches = fc.copyMatches(); - - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - return (name.equals(fc.name) && matches.equals(otherMatches)); - } finally { - rdlock.unlock(); - } - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - return name.hashCode() + matches.hashCode(); - } finally { - rdlock.unlock(); - } - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder("FlowCondImpl[name="); - builder.append(name).append(",matches="); - - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - builder.append(matches.values()); - } finally { - rdlock.unlock(); - } - - return builder.append(']').toString(); - } - - // Cloneable - /** - * Return a shallow copy of this instance. - * - * @return A shallow copy of this instance. - */ - @Override - public FlowCondImpl clone() { - Lock rdlock = rwLock.readLock(); - rdlock.lock(); - try { - FlowCondImpl fc = (FlowCondImpl)super.clone(); - fc.rwLock = new ReentrantReadWriteLock(); - fc.matches = (NavigableMap) - ((TreeMap)matches).clone(); - return fc; - } catch (CloneNotSupportedException e) { - // This should never happen. - throw new IllegalStateException("clone() failed", e); - } finally { - rdlock.unlock(); - } - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEvent.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEvent.java deleted file mode 100644 index 177768cf..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEvent.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.slf4j.Logger; - -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; - -import org.opendaylight.controller.sal.core.UpdateType; - -/** - * {@code FlowConditionEvent} describes an cluster event object which notifies - * that a flow condition was added, changed, or removed. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class FlowConditionEvent extends ClusterEvent { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -7615218001174276730L; - - /** - * A pseudo match index which indicates the flow condition itself. - */ - private static final int INDEX_SELF = -1; - - /** - * The name of the flow condition. - */ - private final String name; - - /** - * The match index which specifies the flow match condition in the - * flow condition. - */ - private final int index; - - /** - * Update type of this event. - */ - private final UpdateType updateType; - - /** - * Generate a flow condition event which indicates that the flow condition - * was added, removed, or changed. - * - * @param mgr VTN Manager service. - * @param name The name of the flow condition. - * @param type Update type. - */ - public static void raise(VTNManagerImpl mgr, String name, - UpdateType type) { - raise(mgr, name, INDEX_SELF, type); - } - - /** - * Generate a flow condition event which indicates that the flow match - * condition in the flow condition was added, removed, or changed. - * - * @param mgr VTN Manager service. - * @param name The name of the flow condition. - * @param index The match index that specifies the flow match condition. - * A negative value means that the flow condition itself - * was added, removed, or changed. - * @param type Update type. - */ - public static void raise(VTNManagerImpl mgr, String name, int index, - UpdateType type) { - mgr.enqueueEvent(new FlowConditionEvent(name, index, type)); - } - - /** - * Construct a new flow condition event. - * - * @param name The name of the flow condition. - * @param index The match index that specifies the flow match condition. - * A negative value means that the flow condition itself - * was added, removed, or changed. - * @param type Update type. - */ - private FlowConditionEvent(String name, int index, UpdateType type) { - this.name = name; - this.index = index; - updateType = type; - } - - /** - * Return the name of the flow condition. - * - * @return The name of the flow condition. - */ - public String getName() { - return name; - } - - /** - * Return the match index which specifies the flow match condition in the - * flow condition. - * - * @return The match index. - * A negative value is returned if this event notifies that the - * flow condition was added, removed, or changed. - */ - public int getIndex() { - return index; - } - - /** - * Return update type of this event. - * - * @return Update type. - */ - public UpdateType getUpdateType() { - return updateType; - } - - /** - * Invoked when a cluster event has been received. - * - * @param mgr VTN Manager service. - * @param local {@code true} if this event is generated by the local node. - */ - @Override - protected void eventReceived(VTNManagerImpl mgr, boolean local) { - if (!local) { - mgr.updateFlowCondition(name, index, updateType); - } - } - - /** - * Record a trace log which indicates that a cluster event has been - * received from remote node. - * - * @param mgr VTN Manager service. - * @param logger A logger instance. - * @param key A cluster event key associated with this event. - */ - @Override - public void traceLog(VTNManagerImpl mgr, Logger logger, - ClusterEventId key) { - logger.trace("{}:{}: Received flow condition event: " + - "name={}, type={}, index={}", - mgr.getContainerName(), key, name, updateType, index); - } - - /** - * Determine whether this event should be delivered on the VTN task thread - * or not. - * - * @param local {@code true} if this event is generated by the local node. - * {@code false} if this event is generated by remote cluster - * node. - * @return {@code true} is returned if this event should be delivered - * on the VTN task thread. Otherwise {@code false} is returned. - */ - @Override - public boolean isSingleThreaded(boolean local) { - return true; - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterImpl.java index ca0a71c7..993ed389 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -26,6 +26,8 @@ import org.opendaylight.vtn.manager.flow.filter.RedirectFilter; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.VTNManagerImpl; import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondReader; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowCondition; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; @@ -210,8 +212,8 @@ public abstract class FlowFilterImpl implements Serializable { throws DropFlowException, RedirectFlowException { boolean ret = false; try { - FlowCondImpl fc = getCondition(mgr, pctx); - if (fc.match(mgr, pctx)) { + VTNFlowCondition vfcond = getCondition(pctx); + if (vfcond.match(pctx)) { // Apply this flow filter. if (needFlowAction()) { applyFlowActions(pctx, ffmap); @@ -355,7 +357,7 @@ public abstract class FlowFilterImpl implements Serializable { } /** - * Return a {@link FlowCondImpl} instance which determines whether this + * Return a {@link VTNFlowCondition} instance which determines whether this * flow filter needs to be applied to the given packet. * *

@@ -363,13 +365,12 @@ public abstract class FlowFilterImpl implements Serializable { * the given packet or not. *

* - * @param mgr VTN Manager service. * @param pctx A packet context which contains the packet. - * @return A {@link FlowCondImpl} instance which selects the packet. + * @return A {@link VTNFlowCondition} instance which selects the packet. * @throws UnsupportedPacketException * This flow filter does not support the given packet. */ - private FlowCondImpl getCondition(VTNManagerImpl mgr, PacketContext pctx) + private VTNFlowCondition getCondition(PacketContext pctx) throws UnsupportedPacketException { if (!pctx.isUnicast() && !isMulticastSupported()) { throw new UnsupportedPacketException( @@ -381,12 +382,13 @@ public abstract class FlowFilterImpl implements Serializable { "flooding packet is not supported"); } - FlowCondImpl fc = mgr.getFlowCondDB().get(condition); - if (fc == null) { - throw new UnsupportedPacketException("flow condition not found"); + FlowCondReader reader = pctx.getTxContext().getFlowCondReader(); + VTNFlowCondition vfcond = reader.get(condition); + if (vfcond == null) { + throw new UnsupportedPacketException("Flow condition not found"); } - return fc; + return vfcond; } /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImpl.java deleted file mode 100644 index c7dd2f7d..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImpl.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.util.Objects; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; -import org.opendaylight.vtn.manager.flow.cond.FlowMatch; -import org.opendaylight.vtn.manager.flow.cond.InetMatch; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.util.MiscUtils; - -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * Implementation of flow match. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class FlowMatchImpl implements PacketMatch { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -2201310174894943217L; - - /** - * The minimum value of match index. - */ - private static final int INDEX_MIN = 1; - - /** - * The maximum value of match index. - */ - private static final int INDEX_MAX = 65535; - - /** - * An index value assigned to this condition. - */ - private final int index; - - /** - * Condition to test Ethernet header. - */ - private final EthernetMatchImpl ethernetMatch; - - /** - * Condition to test IP header. - */ - private final InetMatchImpl inetMatch; - - /** - * Condition to layer 4 protocol header in an IP packet. - */ - private final L4MatchImpl l4Match; - - /** - * Construct a new instance. - * - * @param match A {@link FlowMatch} instance. - * @throws VTNException - * {@code match} contains invalid value. - */ - public FlowMatchImpl(FlowMatch match) throws VTNException { - if (match == null) { - Status st = MiscUtils.argumentIsNull("Flow match"); - throw new VTNException(st); - } - - Integer idx = match.getIndex(); - if (idx == null) { - Status st = MiscUtils.argumentIsNull("Match index"); - throw new VTNException(st); - } - - index = idx.intValue(); - if (index < INDEX_MIN || index > INDEX_MAX) { - String msg = "Invalid match index: " + idx; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - - EthernetMatch eth = match.getEthernetMatch(); - InetMatch inet = match.getInetMatch(); - L4Match l4 = match.getLayer4Match(); - - EthernetMatchImpl ematch = (eth == null) - ? null : new EthernetMatchImpl(eth); - InetMatchImpl imatch = (inet == null) - ? null : InetMatchImpl.create(inet); - - if (l4 == null) { - l4Match = null; - } else { - l4Match = L4MatchImpl.create(l4); - - // IP protocol number must be specified. - short proto = l4Match.getInetProtocol(); - if (imatch == null) { - imatch = new Inet4MatchImpl(proto); - } else { - imatch.setProtocol(proto); - } - } - - if (imatch != null) { - // Ethernet type must be specified. - int etype = imatch.getEtherType(); - if (ematch == null) { - ematch = new EthernetMatchImpl(etype); - } else { - ematch.setEtherType(etype); - } - } - - ethernetMatch = ematch; - inetMatch = imatch; - } - - /** - * Return the match index assigned to this instance. - * - * @return The match index. - */ - public int getIndex() { - return index; - } - - /** - * Return a {@link FlowMatch} instance which represents this condition. - * - * @return A {@link FlowMatch} instance. - */ - public FlowMatch getMatch() { - EthernetMatch eth = (ethernetMatch == null) - ? null : ethernetMatch.getMatch(); - InetMatch inet = (inetMatch == null) ? null : inetMatch.getMatch(); - L4Match l4 = (l4Match == null) ? null : l4Match.getMatch(); - - return new FlowMatch(index, eth, inet, l4); - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof FlowMatchImpl)) { - return false; - } - - FlowMatchImpl match = (FlowMatchImpl)o; - return (index == match.index && - Objects.equals(ethernetMatch, match.ethernetMatch) && - Objects.equals(inetMatch, match.inetMatch) && - Objects.equals(l4Match, match.l4Match)); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - return Objects.hash(ethernetMatch, inetMatch, l4Match) ^ index; - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder("FlowMatchImpl[index="); - builder.append(index); - if (ethernetMatch != null) { - builder.append(",ether=").append(ethernetMatch.toString()); - } - if (inetMatch != null) { - builder.append(",inet=").append(inetMatch.toString()); - } - if (l4Match != null) { - builder.append(",L4=").append(l4Match.toString()); - } - builder.append(']'); - - return builder.toString(); - } - - // PacketMatch - - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - @Override - public boolean match(PacketContext pctx) { - // Test Ethernet header. - if (ethernetMatch != null && !ethernetMatch.match(pctx)) { - return false; - } - - // Test IP header. - if (inetMatch != null && !inetMatch.match(pctx)) { - return false; - } - - // Test layer 4 protocol header. - return (l4Match == null || l4Match.match(pctx)); - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImpl.java deleted file mode 100644 index 25a63199..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImpl.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.packet.cache.CachedPacket; -import org.opendaylight.vtn.manager.internal.packet.cache.IcmpPacket; -import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.utils.IPProtocols; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code IcmpMatchImpl} describes the condition to match ICMP header fields - * in IPv4 packet. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class IcmpMatchImpl extends L4MatchImpl { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -5344880600123638848L; - - /** - * A value which indicates every ICMP type and code should match. - */ - private static final short VALUE_ANY = -1; - - /** - * ICMP type value to match. - */ - private final short type; - - /** - * ICMP code value to match. - */ - private final short code; - - /** - * Construct a new instance. - * - * @param match An {@link IcmpMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - public IcmpMatchImpl(IcmpMatch match) throws VTNException { - type = getValue(match.getType(), "ICMP type"); - code = getValue(match.getCode(), "ICMP code"); - } - - /** - * Return ICMP type value configured in this instance. - * - * @return An ICMP type value. - * A negative value is returned if ICMP type is not specified. - */ - public short getType() { - return type; - } - - /** - * Return ICMP code value configured in this instance. - * - * @return An ICMP code value. - * A negative value is returned if ICMP code is not specified. - */ - public short getCode() { - return code; - } - - /** - * Return a short value in the specified instance. - * - * @param s A {@link Short} instance. - * @param desc A brief description about the value. - * @return A short integer value in the given instance. - * {@link #VALUE_ANY} is returned if {@code null} is specified - * to {@code s}. - * @throws VTNException - * An invalid value is configured in {@code s}. - */ - private short getValue(Short s, String desc) throws VTNException { - if (s == null) { - return VALUE_ANY; - } - - short value = s.shortValue(); - if (!ProtocolUtils.isIcmpValueValid(value)) { - throw new VTNException(StatusCode.BADREQUEST, - "Invalid value for " + desc + ": " + s); - } - - return value; - } - - /** - * Return a {@link Short} instance which represents the given value. - * - * @param value A short value. - * @return A {@link Short} instance. - * {@code null} is returned if a negative value is specified. - */ - private Short getShort(short value) { - return (value < 0) ? null : Short.valueOf(value); - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof IcmpMatchImpl)) { - return false; - } - - IcmpMatchImpl match = (IcmpMatchImpl)o; - return (type == match.type && code == match.code); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - return (int)(((int)type << Short.SIZE) | - (int)(code & NumberUtils.MASK_SHORT)); - } - - // L4PacketMatch - - /** - * Return an IP protocol number assigned to this protocol. - * - * @return An IP protocol number. - */ - @Override - public short getInetProtocol() { - return IPProtocols.ICMP.shortValue(); - } - - /** - * Return a {@link L4Match} instance which represents this condition. - * - * @return A {@link L4Match} instance. - */ - @Override - public L4Match getMatch() { - return new IcmpMatch(getShort(type), getShort(code)); - } - - // PacketMatch - - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - @Override - public boolean match(PacketContext pctx) { - CachedPacket packet = pctx.getL4Packet(); - if (!(packet instanceof IcmpPacket)) { - return false; - } - - IcmpPacket icmp = (IcmpPacket)packet; - if (type >= 0) { - pctx.addMatchField(MatchType.TP_SRC); - if (type != icmp.getType()) { - return false; - } - } - if (code >= 0) { - pctx.addMatchField(MatchType.TP_DST); - if (code != icmp.getCode()) { - return false; - } - } - - return true; - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder("IcmpMatchImpl["); - String sep = ""; - if (type != VALUE_ANY) { - builder.append("type=").append((int)type); - sep = ","; - } - if (code != VALUE_ANY) { - builder.append(sep).append("code=").append((int)code); - } - builder.append(']'); - - return builder.toString(); - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatch.java deleted file mode 100644 index 37c0c7cf..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatch.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.io.Serializable; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.util.MiscUtils; - -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code Inet4AddressMatch} describes an IPv4 address and netmask. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class Inet4AddressMatch implements Serializable { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -4629368100388947618L; - - /** - * An IP address mask value which indicates all bits in an IPv4 address. - */ - public static final int MASK_ALL = -1; - - /** - * The number of bits in an IPv4 address. - */ - private static final int LENGTH = 32; - - /** - * The minimum value of the CIDR suffix. - */ - protected static final int CIDR_SUFFIX_MIN = 1; - - /** - * The maximum value of the CIDR suffix. - */ - protected static final int CIDR_SUFFIX_MAX = LENGTH - 1; - - /** - * An IPv4 address. - */ - private final int address; - - /** - * A netmask used to test IP address. - */ - private final int mask; - - /** - * Construct a new instance. - * - * @param addr An {@link InetAddress} instance which represents an - * IPv4 address. - * @param suff A {@link Short} instance which represents a CIDR suffix - * which represents netmask. - * @throws NullPointerException - * {@code addr} is {@code null}. - * @throws VTNException - * Invalid value is specified to {@code suff}. - */ - public Inet4AddressMatch(InetAddress addr, Short suff) - throws VTNException { - mask = toNetMask(suff); - address = NumberUtils.toInteger(addr.getAddress()) & mask; - } - - /** - * Return an integer value which represents an IPv4 address configured in - * this instance. - * - * @return An integer value which represents an IPv4 address. - */ - public int getAddress() { - return address; - } - - /** - * Return an {@link InetAddress} instance configured in this instance. - * - * @return An {@link InetAddress} instance. - * @throws IllegalStateException - * An error occurred. - */ - public InetAddress getInetAddress() { - return MiscUtils.toInetAddress(address); - } - - /** - * Return a netmask configured in this instance. - * - * @return A netmask configured in this instance. - * {@link #MASK_ALL} is returned if no netmask is configured. - */ - public int getMask() { - return mask; - } - - /** - * Return a CIDR suffix configured in this instance. - * - * @return A {@link Short} instance which represents a CIDR suffix. - * {@code null} is returned if no CIDR suffix is configured. - */ - public Short getCidrSuffix() { - if (mask == MASK_ALL) { - return null; - } - - int nbits = Integer.SIZE - Integer.numberOfTrailingZeros(mask); - return Short.valueOf((short)nbits); - } - - /** - * Determine whether the specified IPv4 address match the condition - * described by this instance. - * - * @param addr An integer value which represents an IPv4 address. - * @return {@code true} is returned if the specified IPv4 address matches - * the condition. Otherwise {@code false} is returned. - */ - public boolean match(int addr) { - return (address == (addr & mask)); - } - - /** - * Convert a CIDR suffix into netmask. - * - * @param suffix A {@link Short} instance which represents a CIDR suffix. - * @return A netmask converted from {@code suffix}. - * @throws VTNException - * An invalid CIDR suffix is specified. - */ - private int toNetMask(Short suffix) throws VTNException { - if (suffix == null) { - return MASK_ALL; - } - - int suff = suffix.intValue(); - if (suff < CIDR_SUFFIX_MIN || suff > CIDR_SUFFIX_MAX) { - String msg = "Invalid CIDR suffix: " + suff; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - - int nzeroes = LENGTH - suff; - return (MASK_ALL << nzeroes); - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Inet4AddressMatch)) { - return false; - } - - Inet4AddressMatch cond = (Inet4AddressMatch)o; - - return (address == cond.address && mask == cond.mask); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - int h = address; - if (mask != MASK_ALL) { - h += Integer.numberOfTrailingZeros(mask); - } - - return h; - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - byte[] addr = NumberUtils.toBytes(address); - String sep = ""; - for (byte b: addr) { - int i = NumberUtils.getUnsigned(b); - builder.append(sep).append(i); - sep = "."; - } - - if (mask != MASK_ALL) { - int suff = Integer.SIZE - Integer.numberOfTrailingZeros(mask); - builder.append('/').append(suff); - } - - return builder.toString(); - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImpl.java deleted file mode 100644 index b81f48a2..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImpl.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.util.Objects; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.Inet4Match; -import org.opendaylight.vtn.manager.flow.cond.InetMatch; -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.packet.cache.Inet4Packet; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.utils.EtherTypes; - -/** - * {@code Inet4MatchImpl} describes the condition to match IPv4 header fields - * in packet. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class Inet4MatchImpl extends InetMatchImpl { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = 2950598600572887764L; - - /** - * A source IP address to match against packets. - */ - private final Inet4AddressMatch source; - - /** - * A destination IP address to match against packets. - */ - private final Inet4AddressMatch destination; - - /** - * Construct a new instance that contains only the condition for the - * IP protocol number. - * - * @param proto An IP protocol number to match. - */ - public Inet4MatchImpl(short proto) { - super(proto); - source = null; - destination = null; - } - - /** - * Construct a new instance. - * - * @param match An {@link InetMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - public Inet4MatchImpl(InetMatch match) throws VTNException { - super(match); - - InetAddress addr = match.getSourceAddress(); - if (addr == null) { - source = null; - } else { - Short suffix = match.getSourceSuffix(); - source = new Inet4AddressMatch(addr, suffix); - } - - addr = match.getDestinationAddress(); - if (addr == null) { - destination = null; - } else { - Short suffix = match.getDestinationSuffix(); - destination = new Inet4AddressMatch(addr, suffix); - } - } - - /** - * Return an {@link Inet4AddressMatch} instance which represents the source - * IP address to match against packets. - * - * @return An {@link Inet4AddressMatch} instance which represents a - * source IP address. {@code null} is returned if this condition - * does not specify the source IP address. - */ - public Inet4AddressMatch getSource() { - return source; - } - - /** - * Return an {@link Inet4AddressMatch} instance which represents the - * destination IP address to match against packets. - * - * @return An {@link Inet4AddressMatch} instance which represents the - * destination IP address. {@code null} is returned if this - * condition does not specify the destination IP address. - */ - public Inet4AddressMatch getDestination() { - return destination; - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!super.equals(o)) { - return false; - } - - Inet4MatchImpl match = (Inet4MatchImpl)o; - return (Objects.equals(source, match.source) && - Objects.equals(destination, match.destination)); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - return Objects.hash(source, destination) + (super.hashCode() * 31); - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder("Inet4MatchImpl["); - String sep = ""; - if (source != null) { - builder.append("src=").append(source.toString()); - sep = ","; - } - if (destination != null) { - builder.append(sep).append("dst=").append(destination.toString()); - sep = ","; - } - - short proto = getProtocol(); - if (proto >= 0) { - builder.append(sep).append("proto=").append((int)proto); - sep = ","; - } - - byte dscp = getDscp(); - if (dscp >= 0) { - builder.append(sep).append("dscp=").append((int)dscp); - } - builder.append(']'); - - return builder.toString(); - } - - // PacketMatch - - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - @Override - public boolean match(PacketContext pctx) { - Inet4Packet ipv4 = pctx.getInet4Packet(); - if (ipv4 == null) { - return false; - } - - // Test source IP address. - if (source != null) { - pctx.addMatchField(MatchType.NW_SRC); - if (!source.match(ipv4.getSourceAddress())) { - return false; - } - } - - // Test destination IP address. - if (destination != null) { - pctx.addMatchField(MatchType.NW_DST); - if (!destination.match(ipv4.getDestinationAddress())) { - return false; - } - } - - return match(pctx, ipv4.getProtocol(), ipv4.getDscp()); - } - - // InetMatchImpl - - /** - * Return an Ethernet protocol type assigned to this protocol. - * - * @return An Ethernet protocol type for IPv4. - */ - @Override - public int getEtherType() { - return EtherTypes.IPv4.intValue(); - } - - /** - * Return an {@link InetMatch} instance which represents this condition. - * - * @return An {@link InetMatch} instance. - */ - @Override - public InetMatch getMatch() { - InetAddress src, dst; - Short srcSuff, dstSuff; - if (source == null) { - src = null; - srcSuff = null; - } else { - src = source.getInetAddress(); - srcSuff = source.getCidrSuffix(); - } - - if (destination == null) { - dst = null; - dstSuff = null; - } else { - dst = destination.getInetAddress(); - dstSuff = destination.getCidrSuffix(); - } - - return new Inet4Match(src, srcSuff, dst, dstSuff, getProtocolShort(), - getDscpByte()); - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java index f07ed70c..28d984f8 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -9,10 +9,9 @@ package org.opendaylight.vtn.manager.internal.cluster; -import java.net.InetAddress; - import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.InetAddressAction; +import org.opendaylight.vtn.manager.util.IpNetwork; import org.opendaylight.vtn.manager.internal.util.MiscUtils; @@ -36,7 +35,7 @@ public abstract class InetAddressActionImpl extends FlowActionImpl { /** * IP address to be set. */ - private final InetAddress address; + private final IpNetwork address; /** * Construct a new instance. @@ -54,7 +53,7 @@ public abstract class InetAddressActionImpl extends FlowActionImpl { throw new VTNException(st); } - address = act.getAddress(); + address = act.getIpNetwork(); if (address == null) { String msg = getErrorMessage(act, "IP address"); st = MiscUtils.argumentIsNull(msg); @@ -65,9 +64,9 @@ public abstract class InetAddressActionImpl extends FlowActionImpl { /** * Return an IP address to be set. * - * @return An {@link InetAddress} instance. + * @return An {@link IpNetwork} instance. */ - protected final InetAddress getAddress() { + protected final IpNetwork getAddress() { return address; } @@ -108,7 +107,7 @@ public abstract class InetAddressActionImpl extends FlowActionImpl { @Override public String toString() { StringBuilder builder = new StringBuilder(getClass().getSimpleName()); - return builder.append("[addr=").append(address.getHostAddress()). + return builder.append("[addr=").append(address.getText()). append(']').toString(); } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetMatchImpl.java deleted file mode 100644 index f3b439ae..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetMatchImpl.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.Inet4Match; -import org.opendaylight.vtn.manager.flow.cond.InetMatch; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code InetMatchImpl} describes the condition to match IP protocol header - * fields in packet. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public abstract class InetMatchImpl implements PacketMatch { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = 7890231558329145625L; - - /** - * A pseudo IP protocol number which indicates every protocol number - * shold match. - */ - protected static final short PROTO_ANY = -1; - - /** - * A pseudo DSCP field value which indicates every DSCP value should match. - */ - protected static final byte DSCP_ANY = -1; - - /** - * A mask value which represents valid bits in an IP protocol number. - */ - private static final short MASK_PROTO = 0xff; - - /** - * An IP protocol type value to match against packets. - */ - private short protocol; - - /** - * A DSCP field value to match against packets. - */ - private final byte dscp; - - /** - * Create a new {@code InetMatchImpl} instance from the given - * {@link InetMatch} instance. - * - * @param match A {@link InetMatch} instance. - * @return A {@link InetMatch} instance constructed from {@code match}. - * @throws VTNException - * An invalid instance is specified to {@code match}. - */ - public static final InetMatchImpl create(InetMatch match) - throws VTNException { - if (match instanceof Inet4Match) { - return new Inet4MatchImpl((Inet4Match)match); - } - - // This should never happen. - throw new VTNException(StatusCode.BADREQUEST, - "Unexpected inet match instance: " + match); - } - - /** - * Construct a new instance that contains only the condition for the - * IP protocol number. - * - * @param proto An IP protocol number to match. - */ - protected InetMatchImpl(short proto) { - protocol = proto; - dscp = DSCP_ANY; - } - - /** - * Construct a new instance. - * - * @param match An {@link InetMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - protected InetMatchImpl(InetMatch match) throws VTNException { - Status st = match.getValidationStatus(); - if (st != null) { - throw new VTNException(st); - } - - Short proto = match.getProtocol(); - if (proto == null) { - protocol = PROTO_ANY; - } else { - protocol = proto.shortValue(); - if ((protocol & ~MASK_PROTO) != 0) { - String msg = "Invalid IP protocol number: " + proto; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - } - - Byte d = match.getDscp(); - if (d == null) { - dscp = DSCP_ANY; - } else { - dscp = d.byteValue(); - if (!ProtocolUtils.isDscpValid(dscp)) { - String msg = "Invalid DSCP field value: " + d; - throw new VTNException(StatusCode.BADREQUEST, msg); - } - } - } - - /** - * Return the IP protocol type to match against packets. - * - * @return A short integer value which represents the IP protocol type - * to match against packets. - * A negative value is returned if this instance does not - * specify the IP protocol type to match. - */ - public final short getProtocol() { - return protocol; - } - - /** - * Return the IP protocol type to match against packets. - * - * @return A {@link Short} instance which represents the IP protocol type - * to match against packets. - * {@code null} is returned if this instance does not - * specify the IP protocol type to match. - */ - public final Short getProtocolShort() { - return (protocol < 0) ? null : Short.valueOf(protocol); - } - - /** - * Return the DSCP field value to match against packets. - * - * @return A byte value which represents the DSCP field value to match - * against packets. - * A negative value is returned if this instance does not - * specify the DSCP field value to match. - */ - public final byte getDscp() { - return dscp; - } - - /** - * Return the DSCP field value to match against packets. - * - * @return A {@link Byte} instance which represents the DSCP field value - * to match against packets. - * {@code null} is returned if this instance does not specify - * the DSCP field value to match. - */ - public final Byte getDscpByte() { - return (dscp < 0) ? null : Byte.valueOf(dscp); - } - - /** - * Determine whether the IP protocol number and DSCP field match the - * condition described by this instance. - * - * @param pctx The context of the packet to be tested. - * @param proto An IP protocol number to be tested. - * @param ds A DSCP field value to be tested. - * @return {@code true} is returned if the specified arguments match the - * condition. Otherwise {@code false} is returned. - */ - public final boolean match(PacketContext pctx, short proto, byte ds) { - if (protocol >= 0) { - pctx.addMatchField(MatchType.NW_PROTO); - if (protocol != proto) { - return false; - } - } - - if (dscp >= 0) { - pctx.addMatchField(MatchType.NW_TOS); - if (dscp != ds) { - return false; - } - } - - return true; - } - - /** - * Set the IP protocol number to match against packets. - * - * @param proto An IP protocol number. - * @throws VTNException - * The specified protocol number is different from the number configured - * in this instance. - */ - void setProtocol(short proto) throws VTNException { - if (protocol != PROTO_ANY && protocol != proto) { - StringBuilder builder = - new StringBuilder("IP protocol conflict: proto="); - builder.append((int)protocol).append(", expected="). - append((int)proto); - throw new VTNException(StatusCode.BADREQUEST, builder.toString()); - } - - protocol = proto; - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == null || !getClass().equals(o.getClass())) { - return false; - } - - InetMatchImpl match = (InetMatchImpl)o; - return (protocol == match.protocol && dscp == match.dscp); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - int h = (int)(((int)protocol << Byte.SIZE) | - (dscp & NumberUtils.MASK_BYTE)); - return h; - } - - /** - * Return an Ethernet protocol type assigned to this protocol. - * - * @return An Ethernet protocol type. - */ - public abstract int getEtherType(); - - /** - * Return an {@link InetMatch} instance which represents this condition. - * - * @return An {@link InetMatch} instance. - */ - public abstract InetMatch getMatch(); -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4MatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4MatchImpl.java deleted file mode 100644 index e2adbe7e..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4MatchImpl.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.flow.cond.TcpMatch; -import org.opendaylight.vtn.manager.flow.cond.UdpMatch; - -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code L4MatchImpl} describes the condition to match layer 4 protocol - * header fields in packet. - * - *
    - *
  • - * This class assumes that all supported layer 4 protocols are implemented - * on Internet Protocol. - *
  • - *
  • - * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *
  • - *
- */ -public abstract class L4MatchImpl implements PacketMatch { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -8133751263574088210L; - - /** - * Create a new {@code L4MatchImpl} instance from the given - * {@link L4Match} instance. - * - * @param match A {@link L4Match} instance. - * @return A {@link L4MatchImpl} instance constructed from {@code match}. - * @throws VTNException - * An invalid instance is specified to {@code match}. - */ - public static final L4MatchImpl create(L4Match match) - throws VTNException { - if (match instanceof TcpMatch) { - return new TcpMatchImpl((TcpMatch)match); - } - if (match instanceof UdpMatch) { - return new UdpMatchImpl((UdpMatch)match); - } - if (match instanceof IcmpMatch) { - return new IcmpMatchImpl((IcmpMatch)match); - } - - // This should never happen. - throw new VTNException(StatusCode.BADREQUEST, - "Unexpected L4 match instance: " + match); - } - - /** - * Construct a new instance. - */ - protected L4MatchImpl() { - } - - /** - * Return an IP protocol number assigned to this protocol. - * - * @return An IP protocol number. - */ - public abstract short getInetProtocol(); - - /** - * Return a {@link L4Match} instance which represents this condition. - * - * @return A {@link L4Match} instance. - */ - public abstract L4Match getMatch(); -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatch.java deleted file mode 100644 index 1aee14e9..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatch.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.io.Serializable; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.PortMatch; - -import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; - -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code L4PortMatch} describes the range of TCP/UDP port number. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class L4PortMatch implements Serializable { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = 5154123070973523206L; - - /** - * The minimum value (inclusive) in the range of TCP/UDP port numbers - * to match against packets. - */ - private final int portFrom; - - /** - * The maximum value (inclusive) in the range of TCP/UDP port numbers - * to match against packets. - */ - private final int portTo; - - /** - * Construct a new instance. - * - * @param match A {@link PortMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - public L4PortMatch(PortMatch match) throws VTNException { - Integer from = match.getPortFrom(); - if (from == null) { - throw new VTNException(StatusCode.BADREQUEST, - "\"from\" is not specified."); - } - - portFrom = from.intValue(); - checkPort(portFrom, "from"); - - Integer to = match.getPortTo(); - if (to == null) { - portTo = portFrom; - } else { - portTo = to.intValue(); - checkPort(portTo, "to"); - if (from > to) { - StringBuilder builder = - new StringBuilder("Invalid port range: from="); - builder.append(portFrom).append(", to=").append(portTo); - throw new VTNException(StatusCode.BADREQUEST, - builder.toString()); - } - } - } - - /** - * Return the minimum (inclusive) value in the range of TCP/UDP port - * numbers to match against packets. - * - * @return The minimum value in the range of TCP/UDP port numbers. - */ - public int getPortFrom() { - return portFrom; - } - - /** - * Return the maximum (inclusive) value in the range of TCP/UDP port - * numbers to match against packets. - * - * @return The maximum value in the range of TCP/UDP port numbers. - */ - public int getPortTo() { - return portTo; - } - - /** - * Determine whether the given port number is in the range configured - * in this instance. - * - * @param port A port number to be tested. - * @return {@code true} is returned if the specified port number is - * in the range of port numbers specified by this instance. - * Otherwise {@code false} is returned. - */ - public boolean match(int port) { - return (port >= portFrom && port <= portTo); - } - - /** - * Validate the given port number. - * - * @param port A port number. - * @param desc A brief description about the value. - * @throws VTNException - * An invalid port number is specified. - */ - private void checkPort(int port, String desc) throws VTNException { - if (!ProtocolUtils.isPortNumberValid(port)) { - StringBuilder builder = new StringBuilder(desc); - builder.append(": Invalid port number: ").append(port); - throw new VTNException(StatusCode.BADREQUEST, builder.toString()); - } - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof L4PortMatch)) { - return false; - } - - L4PortMatch match = (L4PortMatch)o; - return (portFrom == match.portFrom && portTo == match.portTo); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public int hashCode() { - return portFrom + portTo * 17; - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(portFrom); - if (portTo != portFrom) { - builder.append('-').append(portTo); - } - - return builder.toString(); - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MapType.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MapType.java index 0b2fb902..378cdf60 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MapType.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MapType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014 NEC Corporation + * Copyright (c) 2013-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -11,7 +11,7 @@ package org.opendaylight.vtn.manager.internal.cluster; import org.opendaylight.vtn.manager.VNodeRoute.Reason; -import org.opendaylight.controller.sal.match.MatchType; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; /** * {@code MapType} class represents types of mappings between virtual and @@ -26,7 +26,7 @@ public enum MapType { /** * MAC mapping. */ - MAC(1 << 1, Reason.MACMAPPED, MatchType.DL_SRC), + MAC(1 << 1, Reason.MACMAPPED, FlowMatchType.DL_SRC), /** * VLAN mapping. @@ -50,10 +50,10 @@ public enum MapType { private final Reason reason; /** - * A {@link MatchType} instance which represents flow match field + * A {@link FlowMatchType} instance which represents flow match field * to be specfied in the ingress flow entry. */ - private final MatchType matchType; + private final FlowMatchType matchType; /** * Construct a new mapping type. @@ -81,10 +81,10 @@ public enum MapType { * @param mask A bitmask which identifies the mapping type. * @param reason A {@link Reason} instance associated with the mapping * type. - * @param mtype A {@link MatchType} instance which represents flow match - * fields to specify the packet. + * @param mtype A {@link FlowMatchType} instance which represents flow + * match fields to specify the packet. */ - private MapType(int mask, Reason reason, MatchType mtype) { + private MapType(int mask, Reason reason, FlowMatchType mtype) { this.mask = mask; this.reason = reason; matchType = mtype; @@ -112,14 +112,14 @@ public enum MapType { } /** - * Return a {@link MatchType} instance which represents the flow match + * Return a {@link FlowMatchType} instance which represents the flow match * field to be specified in the ingress flow entry. * - * @return A {@link MatchType} instance. + * @return A {@link FlowMatchType} instance. * {@code null} is returned if no additional match field is * required. */ - public MatchType getMatchType() { + public FlowMatchType getMatchType() { return matchType; } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatch.java deleted file mode 100644 index e4679fb9..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatch.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.io.Serializable; - -import org.opendaylight.vtn.manager.internal.PacketContext; - -/** - * {@code PacketMatch} defines interfaces to be implemented by classes - * which tests protocol header files in packet. - * - *

- * Although this interface is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public interface PacketMatch extends Serializable { - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - boolean match(PacketContext pctx); -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PathMapImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PathMapImpl.java index d3391e69..9d613ade 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PathMapImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PathMapImpl.java @@ -21,6 +21,8 @@ import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.RouteResolver; import org.opendaylight.vtn.manager.internal.VTNManagerImpl; import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondReader; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowCondition; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyConfigBuilder; import org.opendaylight.controller.sal.core.NodeConnector; @@ -199,9 +201,10 @@ public abstract class PathMapImpl * packet. Otherwise {@code null}. */ public RouteResolver evaluate(VTNManagerImpl mgr, PacketContext pctx) { - FlowCondImpl fc = mgr.getFlowCondDB().get(condition); + FlowCondReader reader = pctx.getTxContext().getFlowCondReader(); + VTNFlowCondition vfcond = reader.get(condition); Logger logger = getLogger(); - if (fc == null) { + if (vfcond == null) { logger.debug("{}{}: Ignore path map: condition not found: {}", mgr.getContainerName(), getLogPrefix(), condition); return null; @@ -214,7 +217,7 @@ public abstract class PathMapImpl return null; } - if (fc.match(mgr, pctx)) { + if (vfcond.match(pctx)) { if (idleTimeout >= 0) { // Set flow timeout. pctx.setFlowTimeout(idleTimeout, hardTimeout); diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortBridge.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortBridge.java index 597c4c34..8ab11447 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortBridge.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortBridge.java @@ -22,7 +22,6 @@ import org.opendaylight.vtn.manager.VNodePath; import org.opendaylight.vtn.manager.VNodeState; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.VTenantPath; -import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.internal.ActionList; import org.opendaylight.vtn.manager.internal.LockStack; @@ -198,8 +197,8 @@ public abstract class PortBridge PacketContext pctx) throws VTNException { NodeConnector nc = pctx.getOutgoingNodeConnector(); assert nc != null; - short vlan = pctx.getVlan(); - long mac = EtherAddress.toLong(pctx.getDestinationAddress()); + short vlan = (short)pctx.getVlan(); + long mac = pctx.getDestinationAddress().getAddress(); Lock rdlock = readLock(); try { @@ -250,8 +249,8 @@ public abstract class PortBridge PacketContext pctx) throws DropFlowException, RedirectFlowException { NodeConnector incoming = pctx.getIncomingNodeConnector(); - short vlan = pctx.getVlan(); - long mac = EtherAddress.toLong(pctx.getSourceAddress()); + short vlan = (short)pctx.getVlan(); + long mac = pctx.getSourceAddress().getAddress(); // Writer lock is required because this method may change the state // of the bridge. @@ -519,8 +518,8 @@ public abstract class PortBridge pctx.addUnicastMatchFields(); NodeConnector incoming = pctx.getIncomingNodeConnector(); - short vlan = pctx.getEtherPacket().getOriginalVlan(); - int pri = pctx.getFlowPriority(mgr); + short vlan = (short)pctx.getEtherPacket().getOriginalVlan(); + int pri = pctx.getFlowPriority(); VTNFlow vflow = fdb.create(mgr); // Create flow entries except for egress flow. diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortProtoMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortProtoMatchImpl.java deleted file mode 100644 index b90b7c39..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortProtoMatchImpl.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.util.Objects; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.PortMatch; -import org.opendaylight.vtn.manager.flow.cond.PortProtoMatch; - -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * {@code PortProtoMatchImpl} describes the condition to match layer 4 protocol - * header fields, which identifies the service using 16-bit port number. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public abstract class PortProtoMatchImpl extends L4MatchImpl { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = -5599948746651922234L; - - /** - * A {@link L4PortMatch} instance which describes the range of - * source port numbers to match against packets. - */ - private final L4PortMatch sourcePort; - - /** - * A {@link L4PortMatch} instance which describes the range of - * destination port numbers to match against packets. - */ - private final L4PortMatch destinationPort; - - /** - * Construct a new instance. - * - * @param match An {@link PortProtoMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - protected PortProtoMatchImpl(PortProtoMatch match) throws VTNException { - sourcePort = getL4PortMatch(match.getSourcePort(), "source"); - destinationPort = getL4PortMatch(match.getDestinationPort(), - "destination"); - } - - /** - * Return a {@link L4PortMatch} instance which describes the range of - * source port numbers to match against packets. - * - * @return A {@link L4PortMatch} instances which describes the source - * port numbers to match. - * {@code null} is returned if no source port number is specified. - */ - public final L4PortMatch getSourcePort() { - return sourcePort; - } - - /** - * Return a {@link L4PortMatch} instance which describes the range of - * destination port numbers to match against packets. - * - * @return A {@link L4PortMatch} instance which describes the destination - * port numbers to match. - * {@code null} is returned if no destination port number is - * specified. - */ - public final L4PortMatch getDestinationPort() { - return destinationPort; - } - - /** - * Return a {@link PortMatch} instance which represents the specified - * {@link L4PortMatch} instance. - * - * @param match A {@link L4PortMatch} instance. - * @return A {@link PortMatch} instance. - * {@code null} is returned if {@code null} is specified. - */ - protected PortMatch getPortMatch(L4PortMatch match) { - if (match == null) { - return null; - } - - int from = match.getPortFrom(); - int to = match.getPortTo(); - return (from == to) - ? new PortMatch(Integer.valueOf(from)) - : new PortMatch(Integer.valueOf(from), Integer.valueOf(to)); - } - - /** - * Return a {@link L4PortMatch} instance which represents the contents - * of the specified {@link PortMatch} instance. - * - * @param match A {@link PortMatch} instance. - * @param desc A brief description about the value. - * @return A {@link L4PortMatch} instance. - * {@code null} is returned if {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - private L4PortMatch getL4PortMatch(PortMatch match, String desc) - throws VTNException { - if (match == null) { - return null; - } - - try { - return new L4PortMatch(match); - } catch (VTNException e) { - StringBuilder builder = new StringBuilder(desc); - builder.append(": ").append(e.getStatus().getDescription()); - Status st = new Status(StatusCode.BADREQUEST, builder.toString()); - throw new VTNException(st, e); - } - } - - /** - * Determine whether the given object is identical to this object. - * - * @param o An object to be compared. - * @return {@code true} if identical. Otherwise {@code false}. - */ - @Override - public final boolean equals(Object o) { - if (o == this) { - return true; - } - if (o == null || !getClass().equals(o.getClass())) { - return false; - } - - PortProtoMatchImpl match = (PortProtoMatchImpl)o; - return (Objects.equals(sourcePort, match.sourcePort) && - Objects.equals(destinationPort, match.destinationPort)); - } - - /** - * Return the hash code of this object. - * - * @return The hash code. - */ - @Override - public final int hashCode() { - return Objects.hash(sourcePort, destinationPort); - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - */ - @Override - public final String toString() { - StringBuilder builder = new StringBuilder(getClass().getSimpleName()); - builder.append('['); - String sep = ""; - - if (sourcePort != null) { - builder.append("src=").append(sourcePort.toString()); - sep = ","; - } - if (destinationPort != null) { - builder.append(sep).append("dst="). - append(destinationPort.toString()); - } - builder.append(']'); - - return builder.toString(); - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java index c92023b4..88450a87 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java @@ -11,6 +11,7 @@ package org.opendaylight.vtn.manager.internal.cluster; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.SetDlDstAction; +import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.packet.cache.EtherPacket; @@ -60,9 +61,9 @@ public final class SetDlDstActionImpl extends DlAddrActionImpl { @Override public boolean apply(PacketContext pctx) { EtherPacket ether = pctx.getEtherPacket(); - byte[] addr = getAddress(); + EtherAddress addr = getAddress(); ether.setDestinationAddress(addr); - pctx.addFilterAction(new SetDlDst(addr)); + pctx.addFilterAction(new SetDlDst(addr.getBytes())); return true; } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java index 5e1c5ba5..07b9e431 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java @@ -11,6 +11,7 @@ package org.opendaylight.vtn.manager.internal.cluster; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction; +import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.packet.cache.EtherPacket; @@ -60,9 +61,9 @@ public final class SetDlSrcActionImpl extends DlAddrActionImpl { @Override public boolean apply(PacketContext pctx) { EtherPacket ether = pctx.getEtherPacket(); - byte[] addr = getAddress(); + EtherAddress addr = getAddress(); ether.setSourceAddress(addr); - pctx.addFilterAction(new SetDlSrc(addr)); + pctx.addFilterAction(new SetDlSrc(addr.getBytes())); return true; } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java index 1cd7f41b..1012a4a1 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java @@ -119,7 +119,7 @@ public final class SetIcmpCodeActionImpl extends FlowActionImpl { L4Packet packet = pctx.getL4Packet(); if (packet instanceof IcmpPacket) { IcmpPacket icmp = (IcmpPacket)packet; - icmp.setCode(code); + icmp.setIcmpCode(code); pctx.addFilterAction(new SetTpDst((int)code)); return true; } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java index cbe2e2b9..02ecaeb4 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java @@ -119,7 +119,7 @@ public final class SetIcmpTypeActionImpl extends FlowActionImpl { L4Packet packet = pctx.getL4Packet(); if (packet instanceof IcmpPacket) { IcmpPacket icmp = (IcmpPacket)packet; - icmp.setType(type); + icmp.setIcmpType(type); pctx.addFilterAction(new SetTpSrc((int)type)); return true; } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java index 4c43ee63..fae879c7 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java @@ -9,10 +9,9 @@ package org.opendaylight.vtn.manager.internal.cluster; -import java.net.InetAddress; - import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction; +import org.opendaylight.vtn.manager.util.IpNetwork; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.packet.cache.Inet4Packet; @@ -63,9 +62,9 @@ public final class SetInet4DstActionImpl extends InetAddressActionImpl { public boolean apply(PacketContext pctx) { Inet4Packet ipv4 = pctx.getInet4Packet(); if (ipv4 != null) { - InetAddress iaddr = getAddress(); - ipv4.setDestinationAddress(iaddr); - pctx.addFilterAction(new SetNwDst(iaddr)); + IpNetwork ipn = getAddress(); + ipv4.setDestinationAddress(ipn); + pctx.addFilterAction(new SetNwDst(ipn.getInetAddress())); return true; } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java index c6e298fc..5e1f546c 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java @@ -9,10 +9,9 @@ package org.opendaylight.vtn.manager.internal.cluster; -import java.net.InetAddress; - import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction; +import org.opendaylight.vtn.manager.util.IpNetwork; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.packet.cache.Inet4Packet; @@ -63,9 +62,9 @@ public final class SetInet4SrcActionImpl extends InetAddressActionImpl { public boolean apply(PacketContext pctx) { Inet4Packet ipv4 = pctx.getInet4Packet(); if (ipv4 != null) { - InetAddress iaddr = getAddress(); - ipv4.setSourceAddress(iaddr); - pctx.addFilterAction(new SetNwSrc(iaddr)); + IpNetwork ipn = getAddress(); + ipv4.setSourceAddress(ipn); + pctx.addFilterAction(new SetNwSrc(ipn.getInetAddress())); return true; } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImpl.java deleted file mode 100644 index 4c22f542..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImpl.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.flow.cond.TcpMatch; -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.packet.cache.CachedPacket; -import org.opendaylight.vtn.manager.internal.packet.cache.TcpPacket; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.utils.IPProtocols; - -/** - * {@code TcpMatchImpl} describes the condition to match TCP header fields - * in IP packet. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class TcpMatchImpl extends PortProtoMatchImpl { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = 4196379454588474512L; - - /** - * Construct a new instance. - * - * @param match A {@link TcpMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - public TcpMatchImpl(TcpMatch match) throws VTNException { - super(match); - } - - // L4MatchImpl - - /** - * Return an IP protocol number assigned to this protocol. - * - * @return An IP protocol number. - */ - @Override - public short getInetProtocol() { - return IPProtocols.TCP.shortValue(); - } - - - /** - * Return a {@link L4Match} instance which represents this condition. - * - * @return A {@link L4Match} instance. - */ - @Override - public L4Match getMatch() { - L4PortMatch src = getSourcePort(); - L4PortMatch dst = getDestinationPort(); - return new TcpMatch(getPortMatch(src), getPortMatch(dst)); - } - - // PacketMatch - - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - @Override - public boolean match(PacketContext pctx) { - CachedPacket packet = pctx.getL4Packet(); - if (!(packet instanceof TcpPacket)) { - return false; - } - - TcpPacket tcp = (TcpPacket)packet; - L4PortMatch src = getSourcePort(); - L4PortMatch dst = getDestinationPort(); - - if (src != null) { - pctx.addMatchField(MatchType.TP_SRC); - int port = tcp.getSourcePort(); - if (!src.match(port)) { - return false; - } - } - - if (dst != null) { - pctx.addMatchField(MatchType.TP_DST); - int port = tcp.getDestinationPort(); - if (!dst.match(port)) { - return false; - } - } - - return true; - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImpl.java deleted file mode 100644 index cc9c5665..00000000 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImpl.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.flow.cond.UdpMatch; -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.packet.cache.CachedPacket; -import org.opendaylight.vtn.manager.internal.packet.cache.UdpPacket; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.utils.IPProtocols; - -/** - * {@code UdpMatchImpl} describes the condition to match UDP header fields - * in IP packet. - * - *

- * Although this class is public to other packages, this class does not - * provide any API. Applications other than VTN Manager must not use this - * class. - *

- */ -public final class UdpMatchImpl extends PortProtoMatchImpl { - /** - * Version number for serialization. - */ - private static final long serialVersionUID = 6510518830317668833L; - - /** - * Construct a new instance. - * - * @param match A {@link UdpMatch} instance. - * @throws NullPointerException - * {@code match} is {@code null}. - * @throws VTNException - * {@code match} contains invalid value. - */ - public UdpMatchImpl(UdpMatch match) throws VTNException { - super(match); - } - - // L4MatchImpl - - /** - * Return an IP protocol number assigned to this protocol. - * - * @return An IP protocol number. - */ - @Override - public short getInetProtocol() { - return IPProtocols.UDP.shortValue(); - } - - /** - * Return a {@link L4Match} instance which represents this condition. - * - * @return A {@link L4Match} instance. - */ - @Override - public L4Match getMatch() { - L4PortMatch src = getSourcePort(); - L4PortMatch dst = getDestinationPort(); - return new UdpMatch(getPortMatch(src), getPortMatch(dst)); - } - - // PacketMatch - - /** - * Determine whether the specified packet matches the condition defined - * by this instance. - * - * @param pctx The context of the packet to be tested. - * @return {@code true} if the specified packet matches the condition. - * Otherwise {@code false}. - */ - @Override - public boolean match(PacketContext pctx) { - CachedPacket packet = pctx.getL4Packet(); - if (!(packet instanceof UdpPacket)) { - return false; - } - - UdpPacket udp = (UdpPacket)packet; - L4PortMatch src = getSourcePort(); - L4PortMatch dst = getDestinationPort(); - - if (src != null) { - pctx.addMatchField(MatchType.TP_SRC); - int port = udp.getSourcePort(); - if (!src.match(port)) { - return false; - } - } - if (dst != null) { - pctx.addMatchField(MatchType.TP_DST); - int port = udp.getDestinationPort(); - if (!dst.match(port)) { - return false; - } - } - - return true; - } -} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VBridgeImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VBridgeImpl.java index 1286159e..7c897544 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VBridgeImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VBridgeImpl.java @@ -810,14 +810,14 @@ public final class VBridgeImpl extends PortBridge PacketContext pctx, MacAddressTable table) throws DropFlowException, RedirectFlowException, VTNException { - byte[] dst = pctx.getDestinationAddress(); - if (!EtherAddress.isUnicast(dst)) { + EtherAddress dst = pctx.getDestinationAddress(); + if (!dst.isUnicast()) { // Flood the non-unicast packet. flood(mgr, pctx); return null; } - Long key = MacAddressTable.getTableKey(dst); + Long key = Long.valueOf(dst.getAddress()); MacTableEntry tent = table.get(key); if (tent == null) { // Flood the received packet. diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTenantImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTenantImpl.java index b7e59787..4c0c0f45 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTenantImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTenantImpl.java @@ -12,7 +12,6 @@ package org.opendaylight.vtn.manager.internal.cluster; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.IOException; -import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; @@ -56,6 +55,7 @@ import org.opendaylight.vtn.manager.VTerminalPath; import org.opendaylight.vtn.manager.VlanMap; import org.opendaylight.vtn.manager.VlanMapConfig; import org.opendaylight.vtn.manager.flow.filter.FlowFilterId; +import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.internal.ContainerConfig; import org.opendaylight.vtn.manager.internal.LockStack; @@ -2350,10 +2350,9 @@ public final class VTenantImpl implements FlowFilterNode { * controller. Otherwise {@code false} is returned. */ private boolean isToController(VTNManagerImpl mgr, PacketContext pctx) { - byte[] ctlrMac = mgr.getVTNConfig(). - getControllerMacAddress().getBytes(); - byte[] dst = pctx.getDestinationAddress(); - return Arrays.equals(ctlrMac, dst); + EtherAddress ctlrMac = mgr.getVTNConfig().getControllerMacAddress(); + EtherAddress dst = pctx.getDestinationAddress(); + return (ctlrMac.getAddress() == dst.getAddress()); } /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java index 966965c1..3e981fdb 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java @@ -39,11 +39,11 @@ import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.VTNManagerImpl; import org.opendaylight.vtn.manager.internal.VTNThreadData; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.UpdateType; -import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.packet.PacketResult; import org.opendaylight.controller.sal.utils.StatusCode; @@ -224,12 +224,12 @@ public final class VTerminalImpl extends PortBridge { * @param pctx The context of the received packet. */ private void notifyHost(VTNManagerImpl mgr, PacketContext pctx) { - byte[] src = pctx.getSourceAddress(); - if (!EtherAddress.isUnicast(src)) { + EtherAddress src = pctx.getSourceAddress(); + if (!src.isUnicast()) { return; } - long mac = EtherAddress.toLong(src); + long mac = src.getAddress(); if (mac == 0L) { // Zero address should be ignored. LOG.warn("{}:{}: Ignore zero MAC address: {}", @@ -254,11 +254,11 @@ public final class VTerminalImpl extends PortBridge { } NodeConnector port = pctx.getIncomingNodeConnector(); - short vlan = pctx.getVlan(); + short vlan = (short)pctx.getVlan(); try { HostNodeConnector host = - new HostNodeConnector(src, iaddr, port, vlan); + new HostNodeConnector(src.getBytes(), iaddr, port, vlan); if (LOG.isTraceEnabled()) { LOG.trace("{}:{}: Notify new host: ipaddr={}, host={}", getContainerName(), getNodePath(), @@ -270,7 +270,7 @@ public final class VTerminalImpl extends PortBridge { StringBuilder builder = new StringBuilder(getContainerName()); builder.append(':').append(getNodePath()). append(": Unable to create host: src="). - append(ByteUtils.toHexString(src)). + append(src.getText()). append(", ipaddr=").append(iaddr). append(", port=").append(port.toString()). append(", vlan=").append((int)vlan); @@ -498,8 +498,8 @@ public final class VTerminalImpl extends PortBridge { // In that case we should specify multicast address in a // drop flow entry, or it may discard packets to be // filtered by flow filter. - pctx.addMatchField(MatchType.DL_TYPE); - pctx.addMatchField(MatchType.DL_DST); + pctx.addMatchField(FlowMatchType.DL_TYPE); + pctx.addMatchField(FlowMatchType.DL_DST); } LogProvider lp = new LogProvider() { diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/config/VTNConfigManager.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/config/VTNConfigManager.java index a20f9189..fbc51469 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/config/VTNConfigManager.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/config/VTNConfigManager.java @@ -64,11 +64,6 @@ public final class VTNConfigManager implements AutoCloseable, VTNConfig { */ private final AtomicReference current; - /** - * VTN Manager provider service. - */ - private final VTNManagerProvider vtnProvider; - /** * A MD-SAL datastore transaction queue for the global configuration. */ @@ -287,7 +282,6 @@ public final class VTNConfigManager implements AutoCloseable, VTNConfig { * @param provider A VTN Manager provider service. */ public VTNConfigManager(VTNManagerProvider provider) { - vtnProvider = provider; XmlConfigFile.init(); // Determine MAC address of the local node. diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondChange.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondChange.java new file mode 100644 index 00000000..449f8096 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondChange.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; + +import org.opendaylight.vtn.manager.internal.util.XmlConfigFile; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowCondition; + +/** + * {@code FlowCondChange} describes changes to the flow condition + * configuration. + * + *

+ * Note that this class is not synchronized. + *

+ */ +final class FlowCondChange { + /** + * A map that keeps updated flow conditions. + */ + private final Map updatedConditions = + new HashMap<>(); + + /** + * A map that keeps names for created flow conditions. + */ + private final Set createdConditions = new HashSet<>(); + + /** + * A set of removed flow condition names. + */ + private final Set removedConditions = new HashSet<>(); + + /** + * Add the updated flow condition. + * + * @param vfcond A {@link VTNFlowCondition} instance. + * @param created {@code true} means that the given flow condition has + * been newly created. + */ + public void addUpdated(VTNFlowCondition vfcond, boolean created) { + String name = vfcond.getIdentifier(); + if (!removedConditions.contains(name)) { + updatedConditions.put(name, vfcond); + if (created) { + createdConditions.add(name); + } + } + } + + /** + * Add the removed flow condition. + * + * @param name The name of the flow condition that has been removed. + */ + public void addRemoved(String name) { + if (removedConditions.add(name)) { + updatedConditions.remove(name); + createdConditions.remove(name); + } + } + + /** + * Apply changes to the flow condition configuration. + * + * @param logger A {@link Logger} instance. + */ + public void apply(Logger logger) { + XmlConfigFile.Type ftype = XmlConfigFile.Type.FLOWCOND; + for (VTNFlowCondition vfcond: updatedConditions.values()) { + // Save configuration into file. + String name = vfcond.getIdentifier(); + XmlConfigFile.save(ftype, name, vfcond); + logger.info("{}: Flow condition has been {}.", name, + (createdConditions.contains(name)) + ? "created" : "updated"); + } + for (String name: removedConditions) { + // Remove configuration file. + XmlConfigFile.delete(ftype, name); + logger.info("{}: Path policy has been removed.", name); + } + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondManager.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondManager.java new file mode 100644 index 00000000..9a7ce432 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/FlowCondManager.java @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.Future; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.TxContext; +import org.opendaylight.vtn.manager.internal.TxTask; +import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.VTNSubSystem; +import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; +import org.opendaylight.vtn.manager.internal.util.DataStoreListener; +import org.opendaylight.vtn.manager.internal.util.DataStoreUtils; +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.XmlConfigFile; +import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowCondition; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcFuture; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcUtils; +import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditionService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; + +/** + * Flow condition manager. + */ +public final class FlowCondManager + extends DataStoreListener + implements VTNSubSystem, VtnFlowConditionService { + /** + * Logger instance. + */ + private static final Logger LOG = + LoggerFactory.getLogger(FlowCondManager.class); + + /** + * VTN Manager provider service. + */ + private final VTNManagerProvider vtnProvider; + + /** + * A set of flow condition names loaded by {@link FlowCondLoadTask}. + */ + private Set loadedConditions; + + /** + * MD-SAL transaction task to load flow condition configurations. + * + *

+ * This task returns current {@link VtnFlowConditions} instance. + *

+ */ + private class FlowCondLoadTask extends AbstractTxTask { + /** + * {@inheritDoc} + */ + @Override + public VtnFlowConditions execute(TxContext ctx) throws VTNException { + loadedConditions = null; + Set loaded = new ConcurrentSkipListSet<>(); + + // Load configuration from file. + XmlConfigFile.Type ftype = XmlConfigFile.Type.FLOWCOND; + List vlist = new ArrayList<>(); + for (String key: XmlConfigFile.getKeys(ftype)) { + VTNFlowCondition vfcond = XmlConfigFile.load( + ftype, key, VTNFlowCondition.class); + if (vfcond != null) { + try { + vfcond.verify(); + vlist.add(vfcond.toVtnFlowConditionBuilder().build()); + loaded.add(vfcond.getIdentifier()); + } catch (VTNException e) { + String msg = MiscUtils.joinColon( + "Ignore invalid flow condition configuration", + key, e.getMessage()); + LOG.warn(msg); + } + } + } + + VtnFlowConditionsBuilder builder = new VtnFlowConditionsBuilder(); + if (!vlist.isEmpty()) { + builder.setVtnFlowCondition(vlist); + } + InstanceIdentifier path = + InstanceIdentifier.create(VtnFlowConditions.class); + + // Remove old configuration, and install loaded configuration. + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + ReadWriteTransaction tx = ctx.getReadWriteTransaction(); + DataStoreUtils.delete(tx, oper, path); + + VtnFlowConditions conditions = builder.build(); + tx.put(oper, path, conditions, true); + if (!loaded.isEmpty()) { + loadedConditions = loaded; + } + + return conditions; + } + + /** + * {@inheritDoc} + */ + @Override + public void onSuccess(VTNManagerProvider provider, + VtnFlowConditions result) { + List vlist = result.getVtnFlowCondition(); + if (vlist != null) { + for (VtnFlowCondition vfc: vlist) { + String name = vfc.getName().getValue(); + LOG.info("Flow condition was loaded: {}", name); + } + } + } + } + + /** + * MD-SAL transaction task to save current flow condition configurations. + * + *

+ * This task returns current {@link VtnFlowConditions} instance. + *

+ */ + private static class FlowCondSaveTask + extends AbstractTxTask { + /** + * A list of {@link VtnFlowCondition} instances to be saved. + */ + private List saveConfig = new ArrayList<>(); + + /** + * Set {@code true} if the root container has been created. + */ + private boolean created; + + /** + * {@inheritDoc} + */ + @Override + public VtnFlowConditions execute(TxContext ctx) throws VTNException { + saveConfig.clear(); + created = false; + + // Load current configuration. + InstanceIdentifier path = + InstanceIdentifier.create(VtnFlowConditions.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + ReadWriteTransaction tx = ctx.getReadWriteTransaction(); + VtnFlowConditions conditions = + DataStoreUtils.read(tx, oper, path).orNull(); + if (conditions == null) { + // Initialize the flow condition container. + conditions = new VtnFlowConditionsBuilder().build(); + tx.put(oper, path, conditions, true); + created = true; + } else { + List vlist = + conditions.getVtnFlowCondition(); + if (vlist != null) { + for (VtnFlowCondition vfc: vlist) { + saveConfig.add(vfc); + } + } + } + + return conditions; + } + + /** + * {@inheritDoc} + */ + @Override + public void onSuccess(VTNManagerProvider provider, + VtnFlowConditions result) { + if (created) { + LOG.info( + "An empty flow condition configuration has been created."); + } + + Set names = new HashSet<>(); + XmlConfigFile.Type ftype = XmlConfigFile.Type.FLOWCOND; + for (VtnFlowCondition vfc: saveConfig) { + // Save configuration into a file. + VTNFlowCondition vfcond = VTNFlowCondition.create(vfc); + if (vfcond != null) { + String name = vfcond.getIdentifier(); + XmlConfigFile.save(ftype, name, vfcond); + names.add(name); + } + } + + // Remove obsolete configuration files. + XmlConfigFile.deleteAll(ftype, names); + } + } + + /** + * Construct a new instance. + * + * @param provider VTN Manager provider service. + */ + public FlowCondManager(VTNManagerProvider provider) { + super(VtnFlowCondition.class); + vtnProvider = provider; + registerListener(provider.getDataBroker(), + LogicalDatastoreType.OPERATIONAL, + DataChangeScope.SUBTREE); + } + + /** + * Invoked when a flow condition has been created or updated. + * + * @param ectx A {@link FlowCondChange} instance which keeps changes to + * the configuration. + * @param path Path to the flow condition. + * @param vfc A {@link VtnFlowCondition} instance. + * @param created {@code true} means that the given flow condition has + * been newly created. + */ + private void onUpdated(FlowCondChange ectx, + InstanceIdentifier path, + VtnFlowCondition vfc, boolean created) { + VTNFlowCondition vfcond = VTNFlowCondition.create(vfc); + if (vfcond == null) { + LOG.warn("Ignore broken {} event: path={}, value={}", + (created) ? "creation" : "update", path, vfc); + } else { + ectx.addUpdated(vfcond, created); + } + } + + // DataStoreListener + + /** + * {@inheritDoc} + */ + @Override + protected FlowCondChange enterEvent( + AsyncDataChangeEvent, DataObject> ev) { + return new FlowCondChange(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void exitEvent(FlowCondChange ectx) { + ectx.apply(LOG); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onCreated(FlowCondChange ectx, + InstanceIdentifier key, + VtnFlowCondition value) { + // Do nothing if the specified event was caused by the initial setup. + Set loaded = loadedConditions; + if (loaded != null) { + String name = FlowCondUtils.getName(key); + if (name != null && loaded.remove(name)) { + if (loaded.isEmpty()) { + LOG.debug("All loaded flow conditions have been notified."); + loadedConditions = null; + } + return; + } + } + + onUpdated(ectx, key, value, true); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onUpdated(FlowCondChange ectx, + InstanceIdentifier key, + VtnFlowCondition oldValue, + VtnFlowCondition newValue) { + onUpdated(ectx, key, newValue, false); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onRemoved(FlowCondChange ectx, + InstanceIdentifier key, + VtnFlowCondition value) { + String name = FlowCondUtils.getName(key); + if (name == null) { + LOG.warn("Ignore broken removal event: path={}, value={}", + key, value); + } else { + ectx.addRemoved(name); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected InstanceIdentifier getWildcardPath() { + return InstanceIdentifier.builder(VtnFlowConditions.class). + child(VtnFlowCondition.class).build(); + } + + /** + * {@inheritDoc} + */ + @Override + protected Logger getLogger() { + return LOG; + } + + /** + * {@inheritDoc} + */ + @Override + protected Set getRequiredEvents() { + return null; + } + + // VTNSubSystem + + /** + * {@inheritDoc} + */ + @Override + public VTNFuture initConfig(boolean master) { + TxTask task = (master) + ? new FlowCondLoadTask() : new FlowCondSaveTask(); + return vtnProvider.post(task); + } + + /** + * {@inheritDoc} + */ + @Override + public void initRpcServices(RpcProviderRegistry rpcReg, + CompositeAutoCloseable regs) { + regs.add(rpcReg. + addRpcImplementation(VtnFlowConditionService.class, this)); + } + + // VtnFlowConditionService + + /** + * Create or modify the flow condition. + * + *
    + *
  • + * If the flow condition specified by the name does not exist, a new + * flow condition will be associated with the specified name. + *
  • + *
  • + * If the flow condition specifie dby the name already exists, + * it will be modified as specified the RPC input. + *
  • + *
+ * + * @param input Input of the RPC. + * @return A {@link Future} associated with the RPC task. + */ + @Override + public Future> setFlowCondition( + SetFlowConditionInput input) { + try { + // Create a task that updates the configuration. + SetFlowConditionTask task = SetFlowConditionTask.create(input); + VTNFuture taskFuture = vtnProvider.postSync(task); + return new RpcFuture( + taskFuture, task); + } catch (Exception e) { + return RpcUtils.getErrorBuilder(SetFlowConditionOutput.class, e). + buildFuture(); + } + } + + /** + * Remove the flow condition specified by the name. + * + * @param input Input of the RPC. + * @return A {@link Future} associated with the RPC task. + */ + @Override + public Future> removeFlowCondition( + RemoveFlowConditionInput input) { + try { + // Create a task that removes the specified flow condition. + RemoveFlowConditionTask task = + RemoveFlowConditionTask.create(input); + VTNFuture taskFuture = vtnProvider.postSync(task); + return new RpcFuture(taskFuture, task); + } catch (Exception e) { + return RpcUtils.getErrorBuilder(Void.class, e).buildFuture(); + } + } + + /** + * Configure a flow match condition into the flow condition specified + * by the flow condition name and match index. + * + * @param input Input of the RPC. + * @return A {@link Future} associated with the RPC task. + */ + @Override + public Future> setFlowConditionMatch( + SetFlowConditionMatchInput input) { + try { + // Create a task that updates the flow matches in the given + // flow condition. + SetFlowMatchTask task = SetFlowMatchTask.create(input); + VTNFuture> taskFuture = + vtnProvider.postSync(task); + return new RpcFuture, SetFlowConditionMatchOutput>( + taskFuture, task); + } catch (Exception e) { + return RpcUtils.getErrorBuilder( + SetFlowConditionMatchOutput.class, e).buildFuture(); + } + } + + /** + * Remove the flow match condition specified by the flow condition name + * and match index. + * + * @param input Input of the RPC. + * @return A {@link Future} associated with the RPC task. + */ + @Override + public Future> removeFlowConditionMatch( + RemoveFlowConditionMatchInput input) { + try { + // Create a task that removes flow matches in the given + // flow condition. + RemoveFlowMatchTask task = RemoveFlowMatchTask.create(input); + VTNFuture> taskFuture = + vtnProvider.postSync(task); + return new RpcFuture, RemoveFlowConditionMatchOutput>( + taskFuture, task); + } catch (Exception e) { + return RpcUtils.getErrorBuilder( + RemoveFlowConditionMatchOutput.class, e).buildFuture(); + } + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowConditionTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowConditionTask.java new file mode 100644 index 00000000..fb2994c6 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowConditionTask.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.TxContext; +import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcOutputGenerator; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcUtils; +import org.opendaylight.vtn.manager.internal.util.tx.DeleteDataTask; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; + +/** + * {@code RemoveFlowConditionTask} describes the MD-SAL datastore transaction + * task that deletes the specified flow condition configuration. + * + * @see #create(RemoveFlowConditionInput) + */ +public final class RemoveFlowConditionTask + extends DeleteDataTask + implements RpcOutputGenerator { + /** + * Create a new task that removes the specified flow condition. + * + * @param input A {@link RemoveFlowConditionInput} instance. + * @return A {@link RemoveFlowConditionTask} associated with the task that + * removes the given flow condition. + * @throws RpcException + * The given input contains invalid value. + */ + public static RemoveFlowConditionTask create(RemoveFlowConditionInput input) + throws RpcException { + if (input == null) { + throw RpcUtils.getNullInputException(); + } + + InstanceIdentifier path = + FlowCondUtils.getIdentifier(input.getName()); + return new RemoveFlowConditionTask(path); + } + + /** + * Construct a new instance. + * + * @param path Path to the flow condition to be removed. + */ + private RemoveFlowConditionTask(InstanceIdentifier path) { + super(LogicalDatastoreType.OPERATIONAL, path); + } + + // DeleteDataTask + + /** + * {@inheritDoc} + */ + @Override + protected void onStarted(TxContext ctx, VtnFlowCondition current) + throws VTNException { + if (current == null) { + // The target flow condition is not present. + String name = FlowCondUtils.getName(getTargetPath()); + throw FlowCondUtils.getNotFoundException(name); + } + } + + // TxTask + + /** + * {@inheritDoc} + */ + @Override + public void onSuccess(VTNManagerProvider provider, VtnUpdateType result) { + // REVISIT: Select flow entries affected by the change. + addBackgroundTasks(provider.removeFlows(null)); + } + + // RpcOutputGenerator + + /** + * {@inheritDoc} + */ + @Override + public Class getOutputType() { + return Void.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Void createOutput(VtnUpdateType result) { + return null; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowMatchTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowMatchTask.java new file mode 100644 index 00000000..5f7eeacb --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveFlowMatchTask.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.TxContext; +import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcOutputGenerator; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcUtils; +import org.opendaylight.vtn.manager.internal.util.tx.CompositeTxTask; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.RemoveFlowConditionMatchOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.remove.flow.condition.match.output.RemoveMatchResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.remove.flow.condition.match.output.RemoveMatchResultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; + +/** + * {@code RemoveFlowMatchTask} describes the MD-SAL datastore transaction task + * that deletes all the specified flow match configurations in the flow + * condition configuration. + * + * @see #create(RemoveFlowConditionMatchInput) + */ +public final class RemoveFlowMatchTask + extends CompositeTxTask + implements RpcOutputGenerator, + RemoveFlowConditionMatchOutput> { + /** + * The name of the target flow condition. + */ + private final VnodeName nodeName; + + /** + * Construct a new task that removes all the given flow match + * configurations from the given flow condition. + * + * @param input A {@link RemoveFlowConditionMatchInput} instance. + * @return A {@link RemoveFlowMatchTask} instance associated with the task + * that removes the given flow match configuration. + * @throws RpcException + * The given input contains invalid value. + */ + public static RemoveFlowMatchTask create( + RemoveFlowConditionMatchInput input) throws RpcException { + if (input == null) { + throw RpcUtils.getNullInputException(); + } + + VnodeName vname = FlowCondUtils.getVnodeName(input.getName()); + List indexList = input.getMatchIndex(); + if (indexList == null || indexList.isEmpty()) { + throw FlowCondUtils.getMatchIndexMissingException(); + } + + Map taskMap = new HashMap<>(); + for (Integer index: indexList) { + if (!taskMap.containsKey(index)) { + taskMap.put(index, new RemoveMatchTask(vname, index)); + } + } + + List taskList = new ArrayList<>(taskMap.values()); + return new RemoveFlowMatchTask(vname, taskList); + } + + /** + * Construct a new instance. + * + * @param vname A {@link VnodeName} instance that contains the name of the + * target flow condition. + * @param tasks A list of tasks that delete flow match configuration. + */ + private RemoveFlowMatchTask(VnodeName vname, List tasks) { + super(tasks); + nodeName = vname; + } + + // CompositeTxTask + + /** + * {@inheritDoc} + */ + @Override + protected void onStarted(TxContext ctx) throws VTNException { + // Ensure that the target flow condition is present. + ReadWriteTransaction tx = ctx.getReadWriteTransaction(); + FlowCondUtils.checkPresent(tx, nodeName); + } + + // TxTask + + /** + * {@inheritDoc} + */ + @Override + public void onSuccess(VTNManagerProvider provider, + List result) { + for (VtnUpdateType status: result) { + if (status != null) { + // REVISIT: Select flow entries affected by the change. + addBackgroundTasks(provider.removeFlows(null)); + break; + } + } + } + + // RpcOutputGenerator + + /** + * {@inheritDoc} + */ + @Override + public Class getOutputType() { + return RemoveFlowConditionMatchOutput.class; + } + + /** + * {@inheritDoc} + */ + @Override + public RemoveFlowConditionMatchOutput createOutput( + List result) { + List list = new ArrayList<>(); + Iterator taskIterator = getSubTasks().iterator(); + for (VtnUpdateType status: result) { + RemoveMatchTask task = taskIterator.next(); + RemoveMatchResult res = new RemoveMatchResultBuilder(). + setIndex(task.getIndex()).setStatus(status).build(); + list.add(res); + } + + return new RemoveFlowConditionMatchOutputBuilder(). + setRemoveMatchResult(list).build(); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveMatchTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveMatchTask.java new file mode 100644 index 00000000..aea29af8 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/RemoveMatchTask.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; +import org.opendaylight.vtn.manager.internal.util.tx.DeleteDataTask; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * {@code RemoveMatchTask} describes the MD-SAL datastore transaction task that + * deletes the flow match configuration associated with the given index in the + * flow condition. + * + *

+ * A task corresponding to this task is used as a sub task for + * {@link RemoveFlowMatchTask}. + *

+ * + * @see RemoveFlowMatchTask + */ +public final class RemoveMatchTask extends DeleteDataTask { + /** + * The index that specifies the flow match to be removed. + */ + private final Integer index; + + /** + * Construct a new instance. + * + * @param vname A {@link VnodeName} instance that contains the name of the + * target flow condition. + * @param idx An {@link Integer} instance which specifies the flow match + * in the given flow condition. + * @throws RpcException + * The given match index is invalid. + */ + RemoveMatchTask(VnodeName vname, Integer idx) throws RpcException { + super(LogicalDatastoreType.OPERATIONAL, + FlowCondUtils.getIdentifier(vname, idx)); + index = idx; + } + + /** + * Return the index number for the target flow match. + * + * @return An {@link Integer} instance which represents the index number + * for the target flow match. + */ + public Integer getIndex() { + return index; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowConditionTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowConditionTask.java new file mode 100644 index 00000000..f1801979 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowConditionTask.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.TxContext; +import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowCondition; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcOutputGenerator; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcUtils; +import org.opendaylight.vtn.manager.internal.util.tx.PutDataTask; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateOperationType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; + +/** + * {@code SetFlowConditionTask} describes the MD-SAL datastore transaction + * task that creates or updates the specified flow condition configuration. + * + * @see #create(SetFlowConditionInput) + */ +public final class SetFlowConditionTask extends PutDataTask + implements RpcOutputGenerator { + /** + * The name of the target flow condition. + */ + private final String name; + + /** + * Set {@code true} if the target flow condition is required to be present. + */ + private final boolean present; + + /** + * Construct a new task that creates or updates the specified flow + * condition configuration. + * + * @param input A {@link SetFlowConditionInput} instance. + * @return A {@link SetFlowConditionTask} instance associated with the + * task that set the given flow condition configuration. + * @throws RpcException + * The given input contains invalid value. + */ + public static SetFlowConditionTask create(SetFlowConditionInput input) + throws RpcException { + // Verify the given input. + if (input == null) { + throw RpcUtils.getNullInputException(); + } + + VtnUpdateOperationType op = input.getOperation(); + if (VtnUpdateOperationType.REMOVE.equals(op)) { + throw RpcUtils.getInvalidOperationException(op); + } + + VTNFlowCondition vfcond = new VTNFlowCondition(input); + boolean repl = VtnUpdateOperationType.SET.equals(op); + + // Create a task. + String name = vfcond.getIdentifier(); + InstanceIdentifier path = vfcond.getPath(); + VtnFlowCondition vfc = vfcond.toVtnFlowConditionBuilder().build(); + boolean present = Boolean.TRUE.equals(input.isPresent()); + return new SetFlowConditionTask(name, path, vfc, repl, present); + } + + /** + * Construct a new instance. + * + * @param nm The name of the target flow condition. + * @param path Path to the target flow condition. + * @param vfc A {@link VtnFlowCondition} instance. + * @param repl If {@code true}, the target object will be replaced with + * the given object. Otherwise the given object will be + * merged with the target object. + * @param pr {@code true} means that the target flow condition is + * required to be present. + */ + private SetFlowConditionTask(String nm, + InstanceIdentifier path, + VtnFlowCondition vfc, boolean repl, + boolean pr) { + super(LogicalDatastoreType.OPERATIONAL, path, vfc, repl); + name = nm; + present = pr; + } + + // PutDataTask + + /** + * Determine whether missing parent nodes should be created or not. + * + *

+ * This method always return true in order to create the root container + * for the flow condition if missing. + *

+ * + * @return {@code true}. + */ + @Override + protected boolean fixMissingParents() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + protected void onStarted(TxContext ctx, VtnFlowCondition current) + throws VTNException { + if (current == null && present) { + // The target flow condition is not present. + throw FlowCondUtils.getNotFoundException(name); + } + } + + // TxTask + + /** + * {@inheritDoc} + */ + @Override + public void onSuccess(VTNManagerProvider provider, VtnUpdateType result) { + if (result != null) { + // REVISIT: Select flow entries affected by the change. + addBackgroundTasks(provider.removeFlows(null)); + } + } + + // RpcOutputGenerator + + /** + * {@inheritDoc} + */ + @Override + public Class getOutputType() { + return SetFlowConditionOutput.class; + } + + /** + * {@inheritDoc} + */ + @Override + public SetFlowConditionOutput createOutput(VtnUpdateType result) { + return new SetFlowConditionOutputBuilder().setStatus(result).build(); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowMatchTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowMatchTask.java new file mode 100644 index 00000000..c51166e6 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetFlowMatchTask.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.TxContext; +import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondUtils; +import org.opendaylight.vtn.manager.internal.util.flow.cond.VTNFlowMatch; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcOutputGenerator; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcUtils; +import org.opendaylight.vtn.manager.internal.util.tx.CompositeTxTask; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionMatchOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.input.FlowMatchList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.output.SetMatchResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.output.SetMatchResultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; + +/** + * {@code SetFlowMatchTask} describes the MD-SAL datastore transaction task + * that set all the specified flow match configurations into the flow condition + * configuration. + * + * @see #create(SetFlowConditionMatchInput) + */ +public final class SetFlowMatchTask + extends CompositeTxTask + implements RpcOutputGenerator, + SetFlowConditionMatchOutput> { + /** + * The name of the target flow condition. + */ + private final VnodeName nodeName; + + /** + * Construct a new task that set all the given flow match configurations + * into the given flow condition. + * + * @param input A {@link SetFlowConditionMatchInput} instance. + * @return A {@link SetFlowMatchTask} instance associated with the task + * that set the given flow match configuration. + * @throws RpcException + * The given input contains invalid value. + */ + public static SetFlowMatchTask create(SetFlowConditionMatchInput input) + throws RpcException { + if (input == null) { + throw RpcUtils.getNullInputException(); + } + + VnodeName vname = FlowCondUtils.getVnodeName(input.getName()); + List vmatches = input.getFlowMatchList(); + if (vmatches == null || vmatches.isEmpty()) { + throw RpcException.getMissingArgumentException( + "At least one flow match must be specified."); + } + + List taskList = new ArrayList<>(); + Set indices = new HashSet<>(); + for (FlowMatchList fml: vmatches) { + VTNFlowMatch vfmatch = new VTNFlowMatch(fml); + Integer index = vfmatch.getIdentifier(); + FlowCondUtils.verifyMatchIndex(indices, index); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(vname, index); + VtnFlowMatch vfm = vfmatch.toVtnFlowMatchBuilder().build(); + taskList.add(new SetMatchTask(path, vfm)); + } + + return new SetFlowMatchTask(vname, taskList); + } + + /** + * Construct a new instance. + * + * @param vname A {@link VnodeName} instance that contains the name of the + * target flow condition. + * @param tasks A list of tasks that set flow match configuration. + */ + private SetFlowMatchTask(VnodeName vname, List tasks) { + super(tasks); + nodeName = vname; + } + + // CompositeTxTask + + /** + * {@inheritDoc} + */ + @Override + protected void onStarted(TxContext ctx) throws VTNException { + // Ensure that the target flow condition is present. + ReadWriteTransaction tx = ctx.getReadWriteTransaction(); + FlowCondUtils.checkPresent(tx, nodeName); + } + + // TxTask + + /** + * {@inheritDoc} + */ + @Override + public void onSuccess(VTNManagerProvider provider, + List result) { + for (VtnUpdateType status: result) { + if (status != null) { + // REVISIT: Select flow entries affected by the change. + addBackgroundTasks(provider.removeFlows(null)); + break; + } + } + } + + // RpcOutputGenerator + + /** + * {@inheritDoc} + */ + @Override + public Class getOutputType() { + return SetFlowConditionMatchOutput.class; + } + + /** + * {@inheritDoc} + */ + @Override + public SetFlowConditionMatchOutput createOutput( + List result) { + List list = new ArrayList<>(); + Iterator taskIterator = getSubTasks().iterator(); + for (VtnUpdateType status: result) { + SetMatchTask task = taskIterator.next(); + SetMatchResult res = new SetMatchResultBuilder(). + setIndex(task.getIndex()).setStatus(status).build(); + list.add(res); + } + + return new SetFlowConditionMatchOutputBuilder(). + setSetMatchResult(list).build(); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetMatchTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetMatchTask.java new file mode 100644 index 00000000..ed78782b --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/flow/cond/SetMatchTask.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.flow.cond; + +import org.opendaylight.vtn.manager.internal.util.tx.PutDataTask; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; + +/** + * {@code SetMatchTask} describes the MD-SAL datastore transaction task that + * associated the flow match with the specified index in a flow condition. + * + *

+ * A task corresponding to this task is used as a sub task for + * {@link SetFlowMatchTask}. + *

+ * + * @see SetFlowMatchTask + */ +public final class SetMatchTask extends PutDataTask { + /** + * Construct a new instance. + * + * @param path Path to the target flow match. + * @param vfm A {@link VtnFlowMatch} instance to be set. + */ + SetMatchTask(InstanceIdentifier path, VtnFlowMatch vfm) { + super(LogicalDatastoreType.OPERATIONAL, path, vfm, true); + } + + /** + * Return the target match index. + * + * @return A {@link Integer} instance that represents the target match + * index. + */ + public Integer getIndex() { + return getDataObject().getIndex(); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/CachedPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/CachedPacket.java index 93401497..d9ff44da 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/CachedPacket.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/CachedPacket.java @@ -14,9 +14,9 @@ import java.util.Set; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; import org.opendaylight.controller.sal.match.Match; -import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.packet.Packet; /** @@ -45,10 +45,10 @@ public interface CachedPacket extends Cloneable { *

* * @param match A {@link Match} instance. - * @param fields A set of {@link MatchType} instances corresponding to + * @param fields A set of {@link FlowMatchType} instances corresponding to * match fields to be tested. */ - void setMatch(Match match, Set fields); + void setMatch(Match match, Set fields); /** * Finalize modification to the packet. diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacket.java index 5a360745..4147e9a5 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacket.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacket.java @@ -15,6 +15,8 @@ import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.util.NumberUtils; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; import org.opendaylight.controller.sal.action.SetDlDst; import org.opendaylight.controller.sal.action.SetDlSrc; @@ -29,17 +31,12 @@ import org.opendaylight.controller.sal.packet.Packet; * {@code EtherPacket} class implements a cache for a {@link Ethernet} * instance including VLAN tag. */ -public final class EtherPacket implements CachedPacket { - /** - * A pseudo MAC address which represents the MAC address is not specified. - */ - private static final long MAC_NONE = -1L; - +public final class EtherPacket implements CachedPacket, EtherHeader { /** * A pseudo VLAN priority which represents the VLAN priority is not * specified. */ - private static final byte VLANPRI_NONE = -1; + private static final short VLANPRI_NONE = -1; /** * An {@link Ethernet} instance. @@ -81,34 +78,24 @@ public final class EtherPacket implements CachedPacket { */ private static final class Values implements Cloneable { /** - * A byte array which represents the source MAC address. + * The source MAC address. */ - private byte[] sourceAddress; + private EtherAddress sourceAddress; /** - * A byte array which represents the destination MAC address. + * The destination MAC address. */ - private byte[] destinationAddress; - - /** - * A long value which represents the source MAC address. - */ - private long sourceMac = MAC_NONE; - - /** - * A long value which represents the destination MAC address. - */ - private long destinationMac = MAC_NONE; + private EtherAddress destinationAddress; /** * The VLAN ID. */ - private short vlan; + private int vlan; /** * The VLAN priority. */ - private byte vlanPriority = VLANPRI_NONE; + private short vlanPriority = VLANPRI_NONE; /** * Constructor. @@ -120,64 +107,41 @@ public final class EtherPacket implements CachedPacket { } /** - * Return the source MAC address as a byte array. + * Return the source MAC address . * - * @return The source MAC address. + * @return An {@link EtherAddress} instance. * {@code null} is returned if not configured. */ - private byte[] getSourceAddress() { + private EtherAddress getSourceAddress() { return sourceAddress; } /** * Set the source MAC address. * - * @param addr A byte array that represents the source MAC address. + * @param addr An {@link EtherAddress} instance. */ - private void setSourceAddress(byte[] addr) { - sourceAddress = addr.clone(); - sourceMac = EtherAddress.toLong(sourceAddress); + private void setSourceAddress(EtherAddress addr) { + sourceAddress = addr; } /** - * Return the destination MAC address as a byte array. + * Return the destination MAC address. * - * @return The destination MAC address. + * @return An {@link EtherAddress} instance. * {@code null} is returned if not configured. */ - private byte[] getDestinationAddress() { + private EtherAddress getDestinationAddress() { return destinationAddress; } /** * Set the destination MAC address. * - * @param addr A byte array that represents the destination - * MAC address. + * @param addr An {@link EtherAddress} instance. */ - private void setDestinationAddress(byte[] addr) { - destinationAddress = addr.clone(); - destinationMac = EtherAddress.toLong(destinationAddress); - } - - /** - * Return the source MAC address as a long integer. - * - * @return The source MAC address. - * {@link EtherPacket#MAC_NONE} is returned if not configured. - */ - private long getSourceMacAddress() { - return sourceMac; - } - - /** - * Return the destination MAC address as a long integer. - * - * @return The destination MAC address. - * {@link EtherPacket#MAC_NONE} is returned if not configured. - */ - private long getDestinationMacAddress() { - return destinationMac; + private void setDestinationAddress(EtherAddress addr) { + destinationAddress = addr; } /** @@ -185,7 +149,7 @@ public final class EtherPacket implements CachedPacket { * * @return A VLAN ID. */ - private short getVlan() { + private int getVlan() { return vlan; } @@ -194,7 +158,7 @@ public final class EtherPacket implements CachedPacket { * * @param vid A VLAN ID. */ - private void setVlan(short vid) { + private void setVlan(int vid) { vlan = vid; } @@ -205,7 +169,7 @@ public final class EtherPacket implements CachedPacket { * {@link EtherPacket#VLANPRI_NONE} is returned if not * configured. */ - private byte getVlanPriority() { + private short getVlanPriority() { return vlanPriority; } @@ -214,7 +178,7 @@ public final class EtherPacket implements CachedPacket { * * @param pri A VLAN priority. */ - private void setVlanPriority(byte pri) { + private void setVlanPriority(short pri) { vlanPriority = pri; } @@ -230,13 +194,14 @@ public final class EtherPacket implements CachedPacket { */ private void fill(Ethernet ether, IEEE8021Q tag) { if (sourceAddress == null) { - setSourceAddress(ether.getSourceMACAddress()); + sourceAddress = new EtherAddress(ether.getSourceMACAddress()); } if (destinationAddress == null) { - setDestinationAddress(ether.getDestinationMACAddress()); + destinationAddress = + new EtherAddress(ether.getDestinationMACAddress()); } if (vlanPriority == VLANPRI_NONE && tag != null) { - vlanPriority = tag.getPcp(); + vlanPriority = (short)NumberUtils.getUnsigned(tag.getPcp()); } } @@ -278,7 +243,7 @@ public final class EtherPacket implements CachedPacket { } else { ethType = ether.getEtherType(); vlanTag = null; - vid = MatchType.DL_VLAN_NONE; + vid = VLAN_NONE; } values = new Values(vid); @@ -287,99 +252,6 @@ public final class EtherPacket implements CachedPacket { rawPayload = parent.getRawPayload(); } - /** - * Return the source MAC address as a byte array. - * - * @return The source MAC address. - */ - public byte[] getSourceAddress() { - Values v = getValues(); - byte[] addr = v.getSourceAddress(); - if (addr == null) { - addr = packet.getSourceMACAddress(); - v.setSourceAddress(addr); - } - - return addr; - } - - /** - * Set the source MAC address. - * - * @param addr A byte array that represents the source MAC address. - */ - public void setSourceAddress(byte[] addr) { - getModifiedValues().setSourceAddress(addr); - } - - /** - * Return the destination MAC address as a byte array. - * - * @return The destination MAC address. - */ - public byte[] getDestinationAddress() { - Values v = getValues(); - byte[] addr = v.getDestinationAddress(); - if (addr == null) { - addr = packet.getDestinationMACAddress(); - v.setDestinationAddress(addr); - } - - return addr; - } - - /** - * Set the source MAC address. - * - * @param addr A byte array that represents the source MAC address. - */ - public void setDestinationAddress(byte[] addr) { - getModifiedValues().setDestinationAddress(addr); - } - - /** - * Return the source MAC address as a long integer. - * - * @return The source MAC address. - */ - public long getSourceMacAddress() { - Values v = getValues(); - long mac = v.getSourceMacAddress(); - if (v.getSourceAddress() == null) { - byte[] addr = packet.getSourceMACAddress(); - v.setSourceAddress(addr); - mac = v.getSourceMacAddress(); - } - - return mac; - } - - /** - * Return the destination MAC address as a long integer. - * - * @return The destination MAC address. - */ - public long getDestinationMacAddress() { - Values v = getValues(); - long mac = v.getDestinationMacAddress(); - if (v.getDestinationAddress() == null) { - byte[] addr = packet.getDestinationMACAddress(); - v.setDestinationAddress(addr); - mac = v.getDestinationMacAddress(); - } - - return mac; - } - - /** - * Return the Ethernet type. - * - * @return An integer value which represents the Ethernet type. - */ - public int getEtherType() { - return etherType; - } - /** * Return the VLAN ID in the original Ethernet frame. * @@ -387,59 +259,10 @@ public final class EtherPacket implements CachedPacket { * Zero is returned if no VLAN tag was found in the original * Ethernet frame. */ - public short getOriginalVlan() { + public int getOriginalVlan() { return values.getVlan(); } - /** - * Return the VLAN ID. - * - * @return A short value which represents the VLAN ID. - * Zero is returned if no VLAN tag was found in the Ethernet - * frame. - */ - public short getVlan() { - // VLAN ID is always cached. - return getValues().getVlan(); - } - - /** - * Set the VLAN ID. - * - * @param vid A VLAN ID. - */ - public void setVlan(short vid) { - getModifiedValues().setVlan(vid); - } - - /** - * Return the VLAN priority. - * - * @return A byte value which represents the VLAN priority. - * A negative value is returned if no VLAN tag was found in - * the Ethernet frame and no VLAN priority is set by the call of - * {@link #setVlanPriority(byte)}. - */ - public byte getVlanPriority() { - Values v = getValues(); - byte pri = v.getVlanPriority(); - if (pri == VLANPRI_NONE && vlanTag != null) { - pri = vlanTag.getPcp(); - v.setVlanPriority(pri); - } - - return pri; - } - - /** - * Set the VLAN priority. - * - * @param pri A VLAN priority. - */ - public void setVlanPriority(byte pri) { - getModifiedValues().setVlanPriority(pri); - } - /** * Return the VLAN tag in the Ethernet frame. * @@ -537,43 +360,41 @@ public final class EtherPacket implements CachedPacket { *

* * @param match A {@link Match} instance. - * @param fields A set of {@link MatchType} instances corresponding to + * @param fields A set of {@link FlowMatchType} instances corresponding to * match fields to be tested. */ @Override - public void setMatch(Match match, Set fields) { + public void setMatch(Match match, Set fields) { Values v = values; v.fill(packet, vlanTag); // VLAN ID field is mandatory. // Note that this code expects MatchType.DL_VLAN_NONE is zero. - short vid = v.getVlan(); - match.setField(MatchType.DL_VLAN, vid); + int vid = v.getVlan(); + match.setField(MatchType.DL_VLAN, (short)vid); - MatchType type = MatchType.DL_SRC; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.DL_SRC)) { // Test source MAC address. - match.setField(type, v.getSourceAddress()); + match.setField(MatchType.DL_SRC, v.getSourceAddress().getBytes()); } - type = MatchType.DL_DST; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.DL_DST)) { // Test destination MAC address. - match.setField(type, v.getDestinationAddress()); + match.setField(MatchType.DL_DST, + v.getDestinationAddress().getBytes()); } // Test VLAN priority only if this packet has a VLAN tag. - if (vid != MatchType.DL_VLAN_NONE) { - type = MatchType.DL_VLAN_PR; - if (fields.contains(type)) { - match.setField(type, v.getVlanPriority()); + if (vid != VLAN_NONE) { + if (fields.contains(FlowMatchType.DL_VLAN_PCP)) { + match.setField(MatchType.DL_VLAN_PR, + (byte)v.getVlanPriority()); } } - type = MatchType.DL_TYPE; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.DL_TYPE)) { // Test Ethernet type. - match.setField(type, (short)etherType); + match.setField(MatchType.DL_TYPE, (short)etherType); } } @@ -587,38 +408,38 @@ public final class EtherPacket implements CachedPacket { // VLAN tag from scratch. boolean mod = false; if (modifiedValues != null) { - if (values.getSourceMacAddress() != - modifiedValues.getSourceMacAddress()) { + EtherAddress src = modifiedValues.getSourceAddress(); + if (!src.equals(values.getSourceAddress())) { // Source MAC address was modified. mod = true; - } else if (pctx.hasMatchField(MatchType.DL_SRC)) { + } else if (pctx.hasMatchField(FlowMatchType.DL_SRC)) { // Source MAC address is not modified, and it will be specified // in flow match. So we don't need to configure SET_DL_SRC // action. pctx.removeFilterAction(SetDlSrc.class); } - if (values.getDestinationMacAddress() != - modifiedValues.getDestinationMacAddress()) { + EtherAddress dst = modifiedValues.getDestinationAddress(); + if (!dst.equals(values.getDestinationAddress())) { // Destination MAC address was modified. mod = true; - } else if (pctx.hasMatchField(MatchType.DL_DST)) { + } else if (pctx.hasMatchField(FlowMatchType.DL_DST)) { // Destination MAC address is not modified, and it will be // specified in flow match. So we don't need to configure // SET_DL_DST action. pctx.removeFilterAction(SetDlDst.class); } - short vlan = modifiedValues.getVlan(); - if (vlan == MatchType.DL_VLAN_NONE) { + int vlan = modifiedValues.getVlan(); + if (vlan == VLAN_NONE) { // SET_VLAN_PCP should never be applied to untagged frame. pctx.removeFilterAction(SetVlanPcp.class); } else { - byte pri = modifiedValues.getVlanPriority(); + short pri = modifiedValues.getVlanPriority(); if (values.getVlanPriority() != pri) { // VLAN priority was modified. mod = true; - } else if (pctx.hasMatchField(MatchType.DL_VLAN_PR)) { + } else if (pctx.hasMatchField(FlowMatchType.DL_VLAN_PCP)) { // VLAN priority is not modified, and it will be specified // in flow match. So we don't need to configure // SET_VLAN_PCP action. @@ -658,4 +479,121 @@ public final class EtherPacket implements CachedPacket { throw new IllegalStateException("clone() failed", e); } } + + // EtherHeader + + /** + * {@inheritDoc} + */ + @Override + public EtherAddress getSourceAddress() { + Values v = getValues(); + EtherAddress addr = v.getSourceAddress(); + if (addr == null) { + addr = new EtherAddress(packet.getSourceMACAddress()); + v.setSourceAddress(addr); + } + + return addr; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSourceAddress(EtherAddress mac) { + getModifiedValues().setSourceAddress(mac); + } + + /** + * {@inheritDoc} + */ + @Override + public EtherAddress getDestinationAddress() { + Values v = getValues(); + EtherAddress addr = v.getDestinationAddress(); + if (addr == null) { + addr = new EtherAddress(packet.getDestinationMACAddress()); + v.setDestinationAddress(addr); + } + + return addr; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDestinationAddress(EtherAddress mac) { + getModifiedValues().setDestinationAddress(mac); + } + + /** + * {@inheritDoc} + */ + @Override + public int getEtherType() { + return etherType; + } + + /** + * {@inheritDoc} + */ + @Override + public int getVlanId() { + // VLAN ID is always cached. + return getValues().getVlan(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setVlanId(int vid) { + getModifiedValues().setVlan(vid); + } + + /** + * {@inheritDoc} + */ + @Override + public short getVlanPriority() { + Values v = getValues(); + short pri = v.getVlanPriority(); + if (pri == VLANPRI_NONE && vlanTag != null) { + pri = (short)NumberUtils.getUnsigned(vlanTag.getPcp()); + v.setVlanPriority(pri); + } + + return pri; + } + + /** + * {@inheritDoc} + */ + @Override + public void setVlanPriority(short pcp) { + getModifiedValues().setVlanPriority(pcp); + } + + // ProtocolHeader + + /** + * {@inheritDoc} + */ + @Override + public void setDescription(StringBuilder builder) { + EtherAddress src = getSourceAddress(); + EtherAddress dst = getDestinationAddress(); + builder.append("Ether[src=").append(src.getText()). + append(",dst=").append(dst.getText()). + append(",type=0x").append(Integer.toHexString(etherType)); + + int vid = getVlanId(); + if (vid != VLAN_NONE) { + builder.append(",vlan={id=").append(vid). + append(",pcp=").append((int)getVlanPriority()).append('}'); + } + builder.append(']'); + } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacket.java index 88357f7c..e44a745e 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacket.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacket.java @@ -17,6 +17,8 @@ import org.opendaylight.vtn.manager.util.NumberUtils; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.IcmpHeader; import org.opendaylight.controller.sal.action.SetTpDst; import org.opendaylight.controller.sal.action.SetTpSrc; @@ -27,7 +29,7 @@ import org.opendaylight.controller.sal.packet.ICMP; /** * {@code IcmpPacket} class implements a cache for an {@link ICMP} instance. */ -public final class IcmpPacket implements L4Packet { +public final class IcmpPacket implements L4Packet, IcmpHeader { /** * A pseudo short value which indicates the byte value is not specified. */ @@ -178,58 +180,6 @@ public final class IcmpPacket implements L4Packet { packet = icmp; } - /** - * Return the ICMP type. - * - * @return A short integer value which indicates the ICMP type. - */ - public short getType() { - Values v = getValues(); - short type = v.getType(); - if (type == VALUE_NONE) { - byte b = packet.getType(); - type = v.setType(b); - } - - return type; - } - - /** - * Set the ICMP type. - * - * @param type A short integer value which indicates the ICMP type. - */ - public void setType(short type) { - Values v = getModifiedValues(); - v.setType(type); - } - - /** - * Return the ICMP code. - * - * @return A short integer value which indicates the ICMP code. - */ - public short getCode() { - Values v = getValues(); - short code = v.getCode(); - if (code == VALUE_NONE) { - byte b = packet.getCode(); - code = v.setCode(b); - } - - return code; - } - - /** - * Set the ICMP code. - * - * @param code A short integer value which indicates the ICMP code. - */ - public void setCode(short code) { - Values v = getModifiedValues(); - v.setCode(code); - } - /** * Return a {@link Values} instance that keeps current values for * ICMP header fields. @@ -298,24 +248,22 @@ public final class IcmpPacket implements L4Packet { *

* * @param match A {@link Match} instance. - * @param fields A set of {@link MatchType} instances corresponding to + * @param fields A set of {@link FlowMatchType} instances corresponding to * match fields to be tested. */ @Override - public void setMatch(Match match, Set fields) { + public void setMatch(Match match, Set fields) { Values v = values; v.fill(packet); - MatchType mt = MatchType.TP_SRC; - if (fields.contains(mt)) { + if (fields.contains(FlowMatchType.ICMP_TYPE)) { // Test ICMP type. - match.setField(mt, v.getType()); + match.setField(MatchType.TP_SRC, v.getType()); } - mt = MatchType.TP_DST; - if (fields.contains(mt)) { + if (fields.contains(FlowMatchType.ICMP_CODE)) { // Test ICMP code. - match.setField(mt, v.getCode()); + match.setField(MatchType.TP_DST, v.getCode()); } } @@ -329,8 +277,8 @@ public final class IcmpPacket implements L4Packet { if (modifiedValues != null) { // At least one flow action that modifies ICMP header is // configured. - pctx.addMatchField(MatchType.DL_TYPE); - pctx.addMatchField(MatchType.NW_PROTO); + pctx.addMatchField(FlowMatchType.DL_TYPE); + pctx.addMatchField(FlowMatchType.IP_PROTO); short type = modifiedValues.getType(); if (values.getType() != type) { @@ -338,7 +286,7 @@ public final class IcmpPacket implements L4Packet { icmp = getPacketForWrite(); icmp.setType((byte)type); mod = true; - } else if (pctx.hasMatchField(MatchType.TP_SRC)) { + } else if (pctx.hasMatchField(FlowMatchType.ICMP_TYPE)) { // ICMP type in the original packet is unchanged and it will be // specified in flow match. So we don't need to configure // SET_TP_SRC action. @@ -353,7 +301,7 @@ public final class IcmpPacket implements L4Packet { } icmp.setCode((byte)code); mod = true; - } else if (pctx.hasMatchField(MatchType.TP_DST)) { + } else if (pctx.hasMatchField(FlowMatchType.ICMP_CODE)) { // ICMP code in the original packet is unchanged and it will be // specified in flow match. So we don't need to configure // SET_TP_DST action. @@ -404,4 +352,68 @@ public final class IcmpPacket implements L4Packet { public boolean updateChecksum(Inet4Packet ipv4) { return false; } + + // IcmpHeader + + /** + * {@inheritDoc} + */ + @Override + public short getIcmpType() { + Values v = getValues(); + short type = v.getType(); + if (type == VALUE_NONE) { + byte b = packet.getType(); + type = v.setType(b); + } + + return type; + } + + /** + * {@inheritDoc} + */ + @Override + public void setIcmpType(short type) { + Values v = getModifiedValues(); + v.setType(type); + } + + /** + * {@inheritDoc} + */ + @Override + public short getIcmpCode() { + Values v = getValues(); + short code = v.getCode(); + if (code == VALUE_NONE) { + byte b = packet.getCode(); + code = v.setCode(b); + } + + return code; + } + + /** + * {@inheritDoc} + */ + @Override + public void setIcmpCode(short code) { + Values v = getModifiedValues(); + v.setCode(code); + } + + + // ProtocolHeader + + /** + * {@inheritDoc} + */ + @Override + public void setDescription(StringBuilder builder) { + int type = (int)getIcmpType(); + int code = (int)getIcmpCode(); + builder.append("ICMP[type=").append(type). + append(",code=").append(code).append(']'); + } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4Packet.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4Packet.java index 7cd573f5..0f6ded42 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4Packet.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4Packet.java @@ -13,10 +13,14 @@ import java.net.InetAddress; import java.util.Set; import org.opendaylight.vtn.manager.VTNException; +import org.opendaylight.vtn.manager.util.Ip4Network; +import org.opendaylight.vtn.manager.util.IpNetwork; import org.opendaylight.vtn.manager.util.NumberUtils; import org.opendaylight.vtn.manager.internal.PacketContext; import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; import org.opendaylight.controller.sal.action.SetNwDst; import org.opendaylight.controller.sal.action.SetNwSrc; @@ -28,7 +32,7 @@ import org.opendaylight.controller.sal.packet.IPv4; /** * {@code Inet4Packet} class implements a cache for an {@link IPv4} instance. */ -public final class Inet4Packet implements CachedPacket { +public final class Inet4Packet implements CachedPacket, InetHeader { /** * A pseudo IP protocol number which indicates the IP protocol number is * not specified. @@ -38,7 +42,7 @@ public final class Inet4Packet implements CachedPacket { /** * A pseudo DSCP value which indicates the DSCP value is not specified. */ - private static final byte DSCP_NONE = -1; + private static final short DSCP_NONE = -1; /** * Byte offset to the source address in a pseudo IPv4 header used for @@ -100,31 +104,19 @@ public final class Inet4Packet implements CachedPacket { */ private static final class Values implements Cloneable { /** - * An integer value which indicates the source IP address. + * The source IP address. */ - private int sourceAddress; + private Ip4Network sourceAddress; /** - * An integer value which indicates the destination IP address. + * The destination IP address. */ - private int destinationAddress; - - /** - * An {@link InetAddress} instance which indicates the source IP - * address. - */ - private InetAddress sourceInetAddress; - - /** - * An {@link InetAddress} instance which indicates the destination IP - * address. - */ - private InetAddress destinationInetAddress; + private Ip4Network destinationAddress; /** * The DSCP field value in the IPv4 packet. */ - private byte dscp = DSCP_NONE; + private short dscp = DSCP_NONE; /** * Constructor. @@ -135,115 +127,62 @@ public final class Inet4Packet implements CachedPacket { /** * Return the source IP address. * - * @return An integer value which represents the source IP address. - * Note that the returned value is unspecified if - * {@link #getSourceInetAddress()} returns {@code null}. - */ - private int getSourceAddress() { - return sourceAddress; - } - - /** - * Return the source IP address. - * - * @return An {@link InetAddress} instance which represents the + * @return An {@link Ip4Network} instance which represents the * source IP address. - * {@code null} is returned if not configured. + * {@code null} is returned if not configured. */ - private InetAddress getSourceInetAddress() { - return sourceInetAddress; + private Ip4Network getSourceAddress() { + return sourceAddress; } /** * Set the source IP address. * - * @param addr An {@link InetAddress} instance which represents the + * @param addr An {@link Ip4Network} instance which represents the * source IPv4 address. */ - private void setSourceAddress(InetAddress addr) { - sourceAddress = MiscUtils.toInteger(addr); - sourceInetAddress = addr; - } - - /** - * Set the source IP address. - * - * @param addr An integer value which represents the source IPv4 - * address. - * @return An {@link InetAddress} instance which represents the - * given IP address. - */ - private InetAddress setSourceAddress(int addr) { + private void setSourceAddress(Ip4Network addr) { sourceAddress = addr; - sourceInetAddress = MiscUtils.toInetAddress(addr); - return sourceInetAddress; - } - - /** - * Return the destination IP address. - * - * @return An integer value which represents the destination IP - * address. - * Note that the returned value is unspecified if - * {@link #getDestinationInetAddress()} returns {@code null}. - */ - private int getDestinationAddress() { - return destinationAddress; } /** * Return the destination IP address. * - * @return An {@link InetAddress} instance which represents the + * @return An {@link Ip4Network} instance which represents the * destination IP address. - * {@code null} is returned if not configured. + * {@code null} is returned if not configured. */ - private InetAddress getDestinationInetAddress() { - return destinationInetAddress; + private Ip4Network getDestinationAddress() { + return destinationAddress; } /** * Set the destination IP address. * - * @param addr An {@link InetAddress} instance which represents the + * @param addr An {@link Ip4Network} instance which represents the * destination IPv4 address. */ - private void setDestinationAddress(InetAddress addr) { - destinationAddress = MiscUtils.toInteger(addr); - destinationInetAddress = addr; - } - - /** - * Set the destination IP address. - * - * @param addr An integer value which represents the destination IPv4 - * address. - * @return An {@link InetAddress} instance which represents the - * given IP address. - */ - private InetAddress setDestinationAddress(int addr) { + private void setDestinationAddress(Ip4Network addr) { destinationAddress = addr; - destinationInetAddress = MiscUtils.toInetAddress(addr); - return destinationInetAddress; } /** * Return the DSCP field value. * - * @return A byte value which indicates the DSCP field value. + * @return A short value which indicates the DSCP field value. * {@link Inet4Packet#DSCP_NONE} is returned if not * configured. */ - private byte getDscp() { + private short getDscp() { return dscp; } /** * Set the DSCP field value. * - * @param value A byte value which indicates the DSCP field value. + * @param value A short value which indicates the DSCP field value. */ - private void setDscp(byte value) { + private void setDscp(short value) { dscp = value; } @@ -257,11 +196,12 @@ public final class Inet4Packet implements CachedPacket { * @param ipv4 An {@link IPv4} instance. */ private void fill(IPv4 ipv4) { - if (sourceInetAddress == null) { - setSourceAddress(ipv4.getSourceAddress()); + if (sourceAddress == null) { + sourceAddress = new Ip4Network(ipv4.getSourceAddress()); } - if (destinationInetAddress == null) { - setDestinationAddress(ipv4.getDestinationAddress()); + if (destinationAddress == null) { + destinationAddress = + new Ip4Network(ipv4.getDestinationAddress()); } if (dscp == DSCP_NONE) { dscp = ipv4.getDiffServ(); @@ -293,137 +233,6 @@ public final class Inet4Packet implements CachedPacket { packet = ipv4; } - /** - * Return the source IP address. - * - * @return An integer value which represents the source IP address. - */ - public int getSourceAddress() { - Values v = getValues(); - int addr; - if (v.getSourceInetAddress() == null) { - addr = packet.getSourceAddress(); - v.setSourceAddress(addr); - } else { - addr = v.getSourceAddress(); - } - - return addr; - } - - /** - * Return the source IP address. - * - * @return An {@link InetAddress} instance which represents the source - * IP address. - */ - public InetAddress getSourceInetAddress() { - Values v = getValues(); - InetAddress addr = v.getSourceInetAddress(); - if (addr == null) { - int address = packet.getSourceAddress(); - addr = v.setSourceAddress(address); - } - - return addr; - } - - /** - * Set the source IP address. - * - * @param addr An {@link InetAddress} instance which represents the - * source IPv4 address. - */ - public void setSourceAddress(InetAddress addr) { - Values v = getModifiedValues(); - v.setSourceAddress(addr); - } - - /** - * Return the destination IP address. - * - * @return An integer value which represents the destination IP address. - */ - public int getDestinationAddress() { - Values v = getValues(); - int addr; - if (v.getDestinationInetAddress() == null) { - addr = packet.getDestinationAddress(); - v.setDestinationAddress(addr); - } else { - addr = v.getDestinationAddress(); - } - - return addr; - } - - /** - * Return the destination IP address. - * - * @return An {@link InetAddress} instance which represents the - * destination IP address. - */ - public InetAddress getDestinationInetAddress() { - Values v = getValues(); - InetAddress addr = v.getDestinationInetAddress(); - if (addr == null) { - int address = packet.getDestinationAddress(); - addr = v.setDestinationAddress(address); - } - - return addr; - } - - /** - * Set the destination IP address. - * - * @param addr An {@link InetAddress} instance which represents the - * destination IPv4 address. - */ - public void setDestinationAddress(InetAddress addr) { - Values v = getModifiedValues(); - v.setDestinationAddress(addr); - } - - /** - * Return the IP protocol number. - * - * @return A short integer value which indicates the IP protocol number. - */ - public short getProtocol() { - if (protocol == PROTO_NONE) { - protocol = (short)NumberUtils.getUnsigned(packet.getProtocol()); - } - - return protocol; - } - - /** - * Return the DSCP field value. - * - * @return A byte value which indicates the DSCP field value. - */ - public byte getDscp() { - Values v = getValues(); - byte dscp = v.getDscp(); - if (dscp == DSCP_NONE) { - dscp = packet.getDiffServ(); - v.setDscp(dscp); - } - - return dscp; - } - - /** - * Set the DSCP field value. - * - * @param dscp A byte value which indicates the DSCP field value. - */ - public void setDscp(byte dscp) { - Values v = getModifiedValues(); - v.setDscp(dscp); - } - /** * Determine whether the source or destination address is modified or not. * @@ -435,10 +244,15 @@ public final class Inet4Packet implements CachedPacket { return false; } - return (values.getSourceAddress() != - modifiedValues.getSourceAddress() || - values.getDestinationAddress() != - modifiedValues.getDestinationAddress()); + Ip4Network oldIp = values.getSourceAddress(); + Ip4Network newIp = modifiedValues.getSourceAddress(); + if (oldIp.getAddress() != newIp.getAddress()) { + return true; + } + + oldIp = values.getDestinationAddress(); + newIp = modifiedValues.getDestinationAddress(); + return (oldIp.getAddress() != newIp.getAddress()); } /** @@ -451,8 +265,8 @@ public final class Inet4Packet implements CachedPacket { public byte[] getHeaderForChecksum(byte proto, short len) { byte[] header = new byte[CKSUM_HEADER_SIZE]; - int src = getSourceAddress(); - int dst = getDestinationAddress(); + int src = getSourceAddress().getAddress(); + int dst = getDestinationAddress().getAddress(); NumberUtils.setInt(header, CKSUM_OFF_SRC, src); NumberUtils.setInt(header, CKSUM_OFF_DST, dst); header[CKSUM_OFF_PROTO] = proto; @@ -529,36 +343,34 @@ public final class Inet4Packet implements CachedPacket { *

* * @param match A {@link Match} instance. - * @param fields A set of {@link MatchType} instances corresponding to + * @param fields A set of {@link FlowMatchType} instances corresponding to * match fields to be tested. */ @Override - public void setMatch(Match match, Set fields) { + public void setMatch(Match match, Set fields) { Values v = values; v.fill(packet); - MatchType type = MatchType.NW_SRC; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.IP_SRC)) { // Test source IP address. - match.setField(type, v.getSourceInetAddress()); + match.setField(MatchType.NW_SRC, + v.getSourceAddress().getInetAddress()); } - type = MatchType.NW_DST; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.IP_DST)) { // Test destination IP address. - match.setField(type, v.getDestinationInetAddress()); + match.setField(MatchType.NW_DST, + v.getDestinationAddress().getInetAddress()); } - type = MatchType.NW_PROTO; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.IP_PROTO)) { // Test IP protocol number. - match.setField(type, (byte)getProtocol()); + match.setField(MatchType.NW_PROTO, (byte)getProtocol()); } - type = MatchType.NW_TOS; - if (fields.contains(type)) { + if (fields.contains(FlowMatchType.IP_DSCP)) { // Test DSCP field. - match.setField(type, v.getDscp()); + match.setField(MatchType.NW_TOS, (byte)v.getDscp()); } } @@ -572,47 +384,49 @@ public final class Inet4Packet implements CachedPacket { if (modifiedValues != null) { // At least one flow action that modifies IPv4 header is // configured. - pctx.addMatchField(MatchType.DL_TYPE); + pctx.addMatchField(FlowMatchType.DL_TYPE); - if (values.getSourceAddress() != - modifiedValues.getSourceAddress()) { + Ip4Network oldIp = values.getSourceAddress(); + Ip4Network newIp = modifiedValues.getSourceAddress(); + if (oldIp.getAddress() != newIp.getAddress()) { // Source address was modified. - InetAddress iaddr = modifiedValues.getSourceInetAddress(); + InetAddress iaddr = newIp.getInetAddress(); ipv4 = getPacketForWrite(); ipv4.setSourceAddress(iaddr); mod = true; - } else if (pctx.hasMatchField(MatchType.NW_SRC)) { + } else if (pctx.hasMatchField(FlowMatchType.IP_SRC)) { // Source IP address in the original packet is unchanged and // it will be specified in flow match. So we don't need to // configure SET_NW_SRC action. pctx.removeFilterAction(SetNwSrc.class); } - if (values.getDestinationAddress() != - modifiedValues.getDestinationAddress()) { + oldIp = values.getDestinationAddress(); + newIp = modifiedValues.getDestinationAddress(); + if (oldIp.getAddress() != newIp.getAddress()) { // Destination address was modified. - InetAddress iaddr = modifiedValues.getDestinationInetAddress(); + InetAddress iaddr = newIp.getInetAddress(); if (ipv4 == null) { ipv4 = getPacketForWrite(); } ipv4.setDestinationAddress(iaddr); mod = true; - } else if (pctx.hasMatchField(MatchType.NW_DST)) { + } else if (pctx.hasMatchField(FlowMatchType.IP_DST)) { // Destination IP address in the original packet is unchanged // and it will be specified in flow match. So we don't need to // configure SET_NW_DST action. pctx.removeFilterAction(SetNwDst.class); } - byte dscp = modifiedValues.getDscp(); + short dscp = modifiedValues.getDscp(); if (values.getDscp() != dscp) { // DSCP field was modified. if (ipv4 == null) { ipv4 = getPacketForWrite(); } - ipv4.setDiffServ(dscp); + ipv4.setDiffServ((byte)dscp); mod = true; - } else if (pctx.hasMatchField(MatchType.NW_TOS)) { + } else if (pctx.hasMatchField(FlowMatchType.IP_DSCP)) { // DSCP value in the original packet is unchanged and it will // be specified in flow match. So we don't need to configure // SET_NW_TOS action. @@ -645,4 +459,109 @@ public final class Inet4Packet implements CachedPacket { throw new IllegalStateException("clone() failed", e); } } + + // InetHeader + + /** + * {@inheritDoc} + */ + @Override + public Ip4Network getSourceAddress() { + Values v = getValues(); + Ip4Network ipn = v.getSourceAddress(); + if (ipn == null) { + ipn = new Ip4Network(packet.getSourceAddress()); + v.setSourceAddress(ipn); + } + + return ipn; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSourceAddress(IpNetwork ipn) { + Ip4Network ip4 = Ip4Network.toIp4Address(ipn); + Values v = getModifiedValues(); + v.setSourceAddress(ip4); + } + + /** + * {@inheritDoc} + */ + @Override + public Ip4Network getDestinationAddress() { + Values v = getValues(); + Ip4Network ipn = v.getDestinationAddress(); + if (ipn == null) { + ipn = new Ip4Network(packet.getDestinationAddress()); + v.setDestinationAddress(ipn); + } + + return ipn; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDestinationAddress(IpNetwork ipn) { + Ip4Network ip4 = Ip4Network.toIp4Address(ipn); + Values v = getModifiedValues(); + v.setDestinationAddress(ip4); + } + + /** + * {@inheritDoc} + */ + @Override + public short getProtocol() { + if (protocol == PROTO_NONE) { + protocol = (short)NumberUtils.getUnsigned(packet.getProtocol()); + } + + return protocol; + } + + /** + * {@inheritDoc} + */ + @Override + public short getDscp() { + Values v = getValues(); + short dscp = v.getDscp(); + if (dscp == DSCP_NONE) { + dscp = (short)NumberUtils.getUnsigned(packet.getDiffServ()); + v.setDscp(dscp); + } + + return dscp; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDscp(short dscp) { + Values v = getModifiedValues(); + v.setDscp(dscp); + } + + // ProtocolHeader + + /** + * {@inheritDoc} + */ + @Override + public void setDescription(StringBuilder builder) { + Ip4Network src = getSourceAddress(); + Ip4Network dst = getDestinationAddress(); + int proto = (int)getProtocol(); + int dscp = (int)getDscp(); + builder.append("Inet4[src=").append(src.getText()). + append(",dst=").append(dst.getText()). + append(",proto=").append(proto). + append(",dscp=").append(dscp).append(']'); + } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/L4Packet.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/L4Packet.java index 27902547..4ffc9e4e 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/L4Packet.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/L4Packet.java @@ -11,11 +11,13 @@ package org.opendaylight.vtn.manager.internal.packet.cache; import org.opendaylight.vtn.manager.VTNException; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; + /** * {@code L4Packet} defines interfaces that implements cache for layer 4 * protocol header. */ -public interface L4Packet extends CachedPacket { +public interface L4Packet extends CachedPacket, Layer4Header { /** * Calculate the checksum of the packet, and set the computed checksum * into a {@link org.opendaylight.controller.sal.packet.Packet} instance diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/PortProtoPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/PortProtoPacket.java index 265f6605..78c76088 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/PortProtoPacket.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/PortProtoPacket.java @@ -15,6 +15,8 @@ import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.util.NumberUtils; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4PortHeader; import org.opendaylight.controller.sal.action.SetTpDst; import org.opendaylight.controller.sal.action.SetTpSrc; @@ -28,7 +30,8 @@ import org.opendaylight.controller.sal.packet.Packet; * * @param Type of packet. */ -public abstract class PortProtoPacket implements L4Packet { +public abstract class PortProtoPacket + implements L4Packet, Layer4PortHeader { /** * A pseudo port number which indicates the port number is not specified. */ @@ -280,58 +283,6 @@ public abstract class PortProtoPacket implements L4Packet { protected PortProtoPacket() { } - /** - * Return the source port number. - * - * @return An integer value which represents the source port number. - */ - public final int getSourcePort() { - Values v = getValues(); - int port = v.getSourcePort(); - if (port == PORT_NONE) { - short p = getRawSourcePort(); - port = v.setSourcePort(p); - } - - return port; - } - - /** - * Set the source port number. - * - * @param port An integer value which indicates the source port. - */ - public final void setSourcePort(int port) { - Values v = getModifiedValues(); - v.setSourcePort(port); - } - - /** - * Return the destination port number. - * - * @return An integer value which represents the destination port number. - */ - public final int getDestinationPort() { - Values v = getValues(); - int port = v.getDestinationPort(); - if (port == PORT_NONE) { - short p = getRawDestinationPort(); - port = v.setDestinationPort(p); - } - - return port; - } - - /** - * Set the destination port number. - * - * @param port An integer value which indicates the destination port. - */ - public final void setDestinationPort(int port) { - Values v = getModifiedValues(); - v.setDestinationPort(port); - } - /** * Return a {@link Packet} instance to set modified values. * @@ -387,6 +338,27 @@ public abstract class PortProtoPacket implements L4Packet { */ protected abstract T getPacketForWrite(boolean doCopy) throws VTNException; + /** + * Return the name of the protocol. + * + * @return The protocol name. + */ + protected abstract String getProtocolName(); + + /** + * Return a flow match type corresponding to the source port. + * + * @return A {@link FlowMatchType} instance. + */ + public abstract FlowMatchType getSourceMatchType(); + + /** + * Return a flow match type corresponding to the destination port. + * + * @return A {@link FlowMatchType} instance. + */ + public abstract FlowMatchType getDestinationMatchType(); + /** * Return a {@link Values} instance that keeps current values for * protocol header fields. @@ -423,24 +395,22 @@ public abstract class PortProtoPacket implements L4Packet { *

* * @param match A {@link Match} instance. - * @param fields A set of {@link MatchType} instances corresponding to + * @param fields A set of {@link FlowMatchType} instances corresponding to * match fields to be tested. */ @Override - public final void setMatch(Match match, Set fields) { + public final void setMatch(Match match, Set fields) { Values v = values; v.fill(this); - MatchType type = MatchType.TP_SRC; - if (fields.contains(type)) { + if (fields.contains(getSourceMatchType())) { // Test source port number. - match.setField(type, (short)v.getSourcePort()); + match.setField(MatchType.TP_SRC, (short)v.getSourcePort()); } - type = MatchType.TP_DST; - if (fields.contains(type)) { + if (fields.contains(getDestinationMatchType())) { // Test destination port number. - match.setField(type, (short)v.getDestinationPort()); + match.setField(MatchType.TP_DST, (short)v.getDestinationPort()); } } @@ -454,8 +424,8 @@ public abstract class PortProtoPacket implements L4Packet { if (modifiedValues != null) { // At least one flow action that modifies TCP or UDP header is // configured. - pctx.addMatchField(MatchType.DL_TYPE); - pctx.addMatchField(MatchType.NW_PROTO); + pctx.addMatchField(FlowMatchType.DL_TYPE); + pctx.addMatchField(FlowMatchType.IP_PROTO); int src = modifiedValues.getSourcePort(); if (values.getSourcePort() != src) { @@ -463,7 +433,7 @@ public abstract class PortProtoPacket implements L4Packet { pkt = getPacketForWrite(); setRawSourcePort(pkt, (short)src); mod = true; - } else if (pctx.hasMatchField(MatchType.TP_SRC)) { + } else if (pctx.hasMatchField(getSourceMatchType())) { // Source port in the original packet is unchanged and it will // be specified in flow match. So we don't need to configure // SET_TP_SRC action. @@ -478,7 +448,7 @@ public abstract class PortProtoPacket implements L4Packet { } setRawDestinationPort(pkt, (short)dst); mod = true; - } else if (pctx.hasMatchField(MatchType.TP_DST)) { + } else if (pctx.hasMatchField(getDestinationMatchType())) { // Destination port in the original packet is unchanged and // it will be specified in flow match. So we don't need to // configure SET_TP_DST action. @@ -511,4 +481,68 @@ public abstract class PortProtoPacket implements L4Packet { throw new IllegalStateException("clone() failed", e); } } + + // Layer4PortHeader + + /** + * {@inheritDoc} + */ + @Override + public final int getSourcePort() { + Values v = getValues(); + int port = v.getSourcePort(); + if (port == PORT_NONE) { + short p = getRawSourcePort(); + port = v.setSourcePort(p); + } + + return port; + } + + /** + * {@inheritDoc} + */ + @Override + public final void setSourcePort(int port) { + Values v = getModifiedValues(); + v.setSourcePort(port); + } + + /** + * {@inheritDoc} + */ + @Override + public final int getDestinationPort() { + Values v = getValues(); + int port = v.getDestinationPort(); + if (port == PORT_NONE) { + short p = getRawDestinationPort(); + port = v.setDestinationPort(p); + } + + return port; + } + + /** + * {@inheritDoc} + */ + @Override + public final void setDestinationPort(int port) { + Values v = getModifiedValues(); + v.setDestinationPort(port); + } + + // ProtocolHeader + + /** + * {@inheritDoc} + */ + @Override + public void setDescription(StringBuilder builder) { + int src = getSourcePort(); + int dst = getDestinationPort(); + builder.append(getProtocolName()). + append("[src=").append(src). + append(",dst=").append(dst).append(']'); + } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacket.java index 515ec752..cefc8816 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacket.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacket.java @@ -12,13 +12,16 @@ package org.opendaylight.vtn.manager.internal.packet.cache; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.TcpHeader; import org.opendaylight.controller.sal.packet.TCP; /** * {@code TcpPacket} class implements a cache for a {@link TCP} instance. */ -public final class TcpPacket extends PortProtoPacket { +public final class TcpPacket extends PortProtoPacket + implements TcpHeader { /** * Byte offset to the checksum field in TCP header. */ @@ -105,6 +108,36 @@ public final class TcpPacket extends PortProtoPacket { return pkt; } + /** + * Return the name of the protocol. + * + * @return {@code "TCP"}. + */ + @Override + protected String getProtocolName() { + return "TCP"; + } + + /** + * Return a flow match type corresponding to the source port. + * + * @return {@link FlowMatchType#TCP_SRC}. + */ + @Override + public FlowMatchType getSourceMatchType() { + return FlowMatchType.TCP_SRC; + } + + /** + * Return a flow match type corresponding to the destination port. + * + * @return {@link FlowMatchType#TCP_DST}. + */ + @Override + public FlowMatchType getDestinationMatchType() { + return FlowMatchType.TCP_DST; + } + // L4Packet /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacket.java index 4d453cd1..a3d22348 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacket.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacket.java @@ -12,13 +12,16 @@ package org.opendaylight.vtn.manager.internal.packet.cache; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.UdpHeader; import org.opendaylight.controller.sal.packet.UDP; /** * {@code UdpPacket} class implements a cache for a {@link UDP} instance. */ -public final class UdpPacket extends PortProtoPacket { +public final class UdpPacket extends PortProtoPacket + implements UdpHeader { /** * Byte offset to the checksum field in UDP header. */ @@ -108,6 +111,36 @@ public final class UdpPacket extends PortProtoPacket { return pkt; } + /** + * Return the name of the protocol. + * + * @return {@code "UDP"}. + */ + @Override + protected String getProtocolName() { + return "UDP"; + } + + /** + * Return a flow match type corresponding to the source port. + * + * @return {@link FlowMatchType#UDP_SRC}. + */ + @Override + public FlowMatchType getSourceMatchType() { + return FlowMatchType.UDP_SRC; + } + + /** + * Return a flow match type corresponding to the destination port. + * + * @return {@link FlowMatchType#UDP_DST}. + */ + @Override + public FlowMatchType getDestinationMatchType() { + return FlowMatchType.UDP_DST; + } + // L4Packet /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/SubSystemRegistry.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/SubSystemRegistry.java new file mode 100644 index 00000000..722b15c7 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/SubSystemRegistry.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.provider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.opendaylight.vtn.manager.internal.VTNSubSystem; +import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; + +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; + +/** + * {@code SubSystemRegistry} keeps instances that manage subsystems in the + * VTN Manager. + * + *

+ * Each subsystem manager is represented by {@link VTNSubSystem} interface, + * and it is indexed by its class. + *

+ */ +public final class SubSystemRegistry { + /** + * Logger instance. + */ + private static final Logger LOG = + LoggerFactory.getLogger(SubSystemRegistry.class); + + /** + * Pairs of subsystem provider classes and instances. + */ + private final AtomicReference, VTNSubSystem>> providers = + new AtomicReference<>(); + + /** + * Registrations of RPC services provided by subsystems. + */ + private final CompositeAutoCloseable rpcServices = + new CompositeAutoCloseable(LOG); + + public SubSystemRegistry() { + Map, VTNSubSystem> map = + new LinkedHashMap<>(); + providers.set(map); + } + + /** + * Add the given configuration provider into this set. + * + * @param obj A {@link VTNSubSystem} instance. + * @param The type of configuration provider. + * @return This instance. + */ + public SubSystemRegistry add(T obj) { + Map, VTNSubSystem> map = + providers.get(); + Class type = obj.getClass(); + map.put(type, obj); + if (LOG.isDebugEnabled()) { + LOG.debug("New subsystem: {}", type.getSimpleName()); + } + + return this; + } + + /** + * Return the configuration provider indexed by the given class. + * + * @param type A class which indicates the type of the configuration + * provider. + * @param The type of the configuration provider. + * @return An instance of the specified configuration provider or + * {@code null}. + */ + public T get(Class type) { + Map, VTNSubSystem> map = + providers.get(); + if (map != null) { + VTNSubSystem vss = map.get(type); + if (type.isInstance(vss)) { + return type.cast(vss); + } + } + + return null; + } + + /** + * Post a MD-SAL datastore transaction task that initializes the + * configuration. + * + * @param master {@code true} if the local node is the configuration + * provider. + * @return A list of {@link VTNFuture} instances associated with + * background tasks that initialize the configuration. + */ + public List> initConfig(boolean master) { + Map, VTNSubSystem> map = + providers.get(); + List> futures = new ArrayList<>(); + for (VTNSubSystem vss: map.values()) { + if (LOG.isDebugEnabled()) { + LOG.debug("Initializing configuration: {}", + vss.getClass().getSimpleName()); + } + + VTNFuture f = vss.initConfig(master); + if (f != null) { + futures.add(f); + } + } + + return futures; + } + + /** + * Initialize RPC services provided by subsystems. + * + * @param rpcReg A {@link RpcProviderRegistry} service instance. + */ + public void initRpcServices(RpcProviderRegistry rpcReg) { + Map, VTNSubSystem> map = + providers.get(); + for (VTNSubSystem vss: map.values()) { + if (LOG.isDebugEnabled()) { + LOG.debug("Initializing RPC: {}", + vss.getClass().getSimpleName()); + } + vss.initRpcServices(rpcReg, rpcServices); + } + } + + /** + * Determine whether the subsystem registry is already closed. + * + * @return {@code true} only if the subsystem registry is already closed. + */ + public boolean isClosed() { + return (providers.get() == null); + } + + /** + * Determine whether RPC services are closed or not. + * + * @return {@code true} only if RPC services are already closed. + */ + public boolean isRpcClosed() { + return rpcServices.isClosed(); + } + + /** + * Close RPC services. + */ + public void closeRpc() { + rpcServices.close(); + } + + /** + * Close all subsystems. + * + * @return {@code true} only if all registered subsystems have been + * actually closed. + */ + public boolean close() { + closeRpc(); + + Map, VTNSubSystem> map = + providers.getAndSet(null); + if (map == null) { + return false; + } + + // Close subsystems in reverse order of registration. + List list = new ArrayList<>(map.values()); + int size = list.size(); + for (ListIterator it = list.listIterator(size); + it.hasPrevious();) { + VTNSubSystem vss = it.previous(); + try { + vss.close(); + } catch (Exception e) { + String msg = MiscUtils.joinColon( + vss.getClass().getSimpleName(), + "Failed to close provider."); + LOG.error(msg, e); + } + } + + return true; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/VTNManagerProviderImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/VTNManagerProviderImpl.java index 1f9a005e..a605d2c8 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/VTNManagerProviderImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/VTNManagerProviderImpl.java @@ -25,19 +25,19 @@ import com.google.common.util.concurrent.ListenableFuture; import org.opendaylight.vtn.manager.VTNException; +import org.opendaylight.vtn.manager.internal.FlowSelector; import org.opendaylight.vtn.manager.internal.RouteResolver; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.TxTask; import org.opendaylight.vtn.manager.internal.VTNConfig; -import org.opendaylight.vtn.manager.internal.VTNFlowMatch; import org.opendaylight.vtn.manager.internal.VTNManagerImpl; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.config.VTNConfigImpl; import org.opendaylight.vtn.manager.internal.config.VTNConfigManager; +import org.opendaylight.vtn.manager.internal.flow.cond.FlowCondManager; import org.opendaylight.vtn.manager.internal.inventory.VTNInventoryManager; import org.opendaylight.vtn.manager.internal.packet.VTNPacketService; import org.opendaylight.vtn.manager.internal.routing.VTNRoutingManager; -import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; import org.opendaylight.vtn.manager.internal.util.SalPort; import org.opendaylight.vtn.manager.internal.util.concurrent.CanceledFuture; import org.opendaylight.vtn.manager.internal.util.concurrent.FutureCallbackTask; @@ -111,11 +111,6 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { */ private final AtomicReference inventoryManager; - /** - * VTN packet routing manager. - */ - private final AtomicReference routingManager; - /** * VTN packet service. */ @@ -137,10 +132,9 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { private final AtomicReference globalTimer; /** - * Registrations of RPC services provided by the VTN Manager. + * Registry for internal subsystems. */ - private final CompositeAutoCloseable rpcServices = - new CompositeAutoCloseable(LOG); + private final SubSystemRegistry subSystems = new SubSystemRegistry(); /** * AD-SAL VTN Manager service. @@ -171,20 +165,27 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { globalQueue = new AtomicReference(globq); VTNConfigManager cfm = new VTNConfigManager(this); configManager = new AtomicReference(cfm); - boolean configProvider = cfm.isConfigProvider(); + boolean master = cfm.isConfigProvider(); VTNInventoryManager vim = new VTNInventoryManager(this); inventoryManager = new AtomicReference(vim); - List> futures = new ArrayList<>(); - VTNRoutingManager rtm = new VTNRoutingManager(this); - routingManager = new AtomicReference(rtm); - futures.add(rtm.initConfig(configProvider)); + // Initialize internal subsystems. + try { + subSystems.add(new VTNRoutingManager(this)). + add(new FlowCondManager(this)); + } catch (RuntimeException e) { + LOG.error("Failed to initialize subsystem.", e); + subSystems.close(); + throw e; + } + + // Resume configurations. + List> futures = subSystems.initConfig(master); VTNPacketService psv = new VTNPacketService(this, nsv); vim.addListener(psv); packetService = new AtomicReference(psv); - globq.start(); // Wait for completion of initialization. @@ -195,14 +196,16 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { } catch (Exception e) { String msg = "Failed to initialize VTN Manager provider."; LOG.error(msg, e); + subSystems.close(); throw new IllegalStateException(msg, e); } // Register RPC services. try { - rtm.initRpcServices(rpcReg, rpcServices); + subSystems.initRpcServices(rpcReg); } catch (RuntimeException e) { - rpcServices.close(); + LOG.error("Failed to initialize RPC service.", e); + subSystems.close(); throw e; } @@ -232,7 +235,7 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { return false; } - if (rpcServices.isClosed()) { + if (subSystems.isClosed()) { return false; } @@ -251,7 +254,7 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { vim.addListener(mgr); } - VTNRoutingManager rtm = routingManager.get(); + VTNRoutingManager rtm = subSystems.get(VTNRoutingManager.class); if (rtm != null) { rtm.addListener(mgr); } @@ -280,6 +283,9 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { if (vim != null) { vim.shutdown(); } + + // Stop RPC services. + subSystems.closeRpc(); } /** @@ -368,7 +374,7 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { */ @Override public RouteResolver getRouteResolver(int id) { - VTNRoutingManager rtm = routingManager.get(); + VTNRoutingManager rtm = subSystems.get(VTNRoutingManager.class); return (rtm == null) ? null : rtm.getRouteResolver(id); } @@ -376,17 +382,31 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { * {@inheritDoc} */ @Override - public List> removeFlows(VTNFlowMatch fmatch) { + public List> removeFlows(FlowSelector selector) { VTNManagerImpl mgr = vtnManager.get(); if (mgr != null) { List> list = new ArrayList<>(); - list.addAll(mgr.removeFlows(fmatch)); + list.addAll(mgr.removeFlows(selector)); return list; } return Collections.>emptyList(); } + /** + * {@inheritDoc} + */ + @Override + public VTNFuture removeFlows(String tname, FlowSelector selector) { + VTNFuture task = null; + VTNManagerImpl mgr = vtnManager.get(); + if (mgr != null) { + task = mgr.removeFlows(tname, selector); + } + + return task; + } + /** * {@inheritDoc} */ @@ -409,7 +429,7 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { @Override public T getVtnRpcService(Class type) throws VTNException { - if (rpcServices.isClosed()) { + if (subSystems.isRpcClosed()) { String msg = "VTN service is already closed."; throw new VTNException(StatusCode.NOSERVICE, msg); } @@ -450,13 +470,9 @@ public final class VTNManagerProviderImpl implements VTNManagerProvider { @Override public void close() { shutdown(); - rpcServices.close(); globalExecutor.shutdown(); - VTNRoutingManager rtm = routingManager.getAndSet(null); - if (rtm != null) { - rtm.close(); - + if (subSystems.close()) { VTNInventoryManager vim = inventoryManager.getAndSet(null); if (vim != null) { vim.close(); diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyChange.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyChange.java index 9f79a36b..36620dd1 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyChange.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyChange.java @@ -18,7 +18,6 @@ import org.slf4j.Logger; import org.opendaylight.vtn.manager.PathPolicy; -import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.XmlConfigFile; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyUtils; @@ -26,7 +25,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vt /** * {@code PathPolicyChange} describes changes to the path policy configuration. - * path policy. * *

* Note that this class is not synchronized. @@ -70,12 +68,10 @@ final class PathPolicyChange { /** * Apply changes to the path policy configuration. * - * @param provider A VTN Manager provider service. - * @param topo A {@link TopologyGraph} instance. - * @param logger A {@link Logger} instance. + * @param topo A {@link TopologyGraph} instance. + * @param logger A {@link Logger} instance. */ - public void apply(VTNManagerProvider provider, TopologyGraph topo, - Logger logger) { + public void apply(TopologyGraph topo, Logger logger) { XmlConfigFile.Type ftype = XmlConfigFile.Type.PATHPOLICY; for (Map.Entry entry: updatedPolicies.entrySet()) { diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyListener.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyListener.java index d9db0b38..28600369 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyListener.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyListener.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,14 +59,14 @@ final class PathPolicyListener LoggerFactory.getLogger(PathPolicyListener.class); /** - * VTN Manager provider service. + * A graph that keeps network topology. */ - private final VTNManagerProvider vtnProvider; + private final TopologyGraph topology; /** - * A graph that keeps network topology. + * A set of path policy IDs laoded by {@link PathPolicyLoadTask}. */ - private final TopologyGraph topology; + private Set loadedPolicies; /** * MD-SAL transaction task to load path policy configuration. @@ -80,17 +81,21 @@ final class PathPolicyListener */ @Override public VtnPathPolicies execute(TxContext ctx) throws VTNException { + loadedPolicies = null; + Set loaded = new ConcurrentSkipListSet<>(); + // Load configuration from file. XmlConfigFile.Type ftype = XmlConfigFile.Type.PATHPOLICY; List vlist = new ArrayList<>(); for (String key: XmlConfigFile.getKeys(ftype)) { PathPolicy pp = XmlConfigFile.load( - XmlConfigFile.Type.PATHPOLICY, key, PathPolicy.class); + ftype, key, PathPolicy.class); if (pp != null) { try { VtnPathPolicy vpp = new PathPolicyConfigBuilder.Data(). set(pp).getBuilder().build(); vlist.add(vpp); + loaded.add(pp.getPolicyId()); } catch (VTNException e) { String msg = MiscUtils.joinColon( "Ignore invalid path policy configuration", @@ -99,6 +104,7 @@ final class PathPolicyListener } } } + VtnPathPoliciesBuilder builder = new VtnPathPoliciesBuilder(); if (!vlist.isEmpty()) { builder.setVtnPathPolicy(vlist); @@ -113,6 +119,9 @@ final class PathPolicyListener VtnPathPolicies policies = builder.build(); tx.put(oper, path, policies, true); + if (!loaded.isEmpty()) { + loadedPolicies = loaded; + } return policies; } @@ -174,6 +183,7 @@ final class PathPolicyListener VtnPathPoliciesBuilder builder = new VtnPathPoliciesBuilder(); policies = builder.build(); tx.put(oper, path, builder.build(), true); + created = true; } else { List vlist = policies.getVtnPathPolicy(); if (vlist != null) { @@ -220,7 +230,6 @@ final class PathPolicyListener */ PathPolicyListener(VTNManagerProvider provider, TopologyGraph topo) { super(VtnPathPolicy.class); - vtnProvider = provider; topology = topo; registerListener(provider.getDataBroker(), LogicalDatastoreType.OPERATIONAL, @@ -230,14 +239,15 @@ final class PathPolicyListener /** * Post a MD-SAL transaction task to initialize configuration. * - * @param master {@code true} if the local node is the configuration - * provider. + * @param provider VTN Manager provider service. + * @param master {@code true} if the local node is the configuration + * provider. * @return A {@link VTNFuture} instance. */ - VTNFuture initConfig(boolean master) { + VTNFuture initConfig(VTNManagerProvider provider, boolean master) { TxTask task = (master) ? new PathPolicyLoadTask() : new PathPolicySaveTask(); - return vtnProvider.post(task); + return provider.post(task); } /** @@ -273,7 +283,7 @@ final class PathPolicyListener */ @Override protected void exitEvent(PathPolicyChange ectx) { - ectx.apply(vtnProvider, topology, LOG); + ectx.apply(topology, LOG); } /** @@ -288,7 +298,15 @@ final class PathPolicyListener LOG.warn("Ignore broken creation event: path={}, value={}", key, value); } else { - ectx.addUpdated(id, value); + // Do nothing if the specified event was caused by the initial + // setup. + Set loaded = loadedPolicies; + if (loaded == null || !loaded.remove(id)) { + ectx.addUpdated(id, value); + } else if (loaded.isEmpty()) { + LOG.debug("All loaded path policies have been notified."); + loadedPolicies = null; + } } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyRpcContext.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyRpcContext.java index 7e74b01a..83d1f2e3 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyRpcContext.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/PathPolicyRpcContext.java @@ -9,7 +9,7 @@ package org.opendaylight.vtn.manager.internal.routing; -import org.opendaylight.vtn.manager.internal.PathPolicyFlowMatch; +import org.opendaylight.vtn.manager.internal.PathPolicyFlowSelector; /** * {@code PathPolicyRpcContext} describes a runtime context for updating @@ -69,12 +69,12 @@ final class PathPolicyRpcContext { } /** - * Return a {@link PathPolicyFlowMatch} instance that selects flow entries - * corresponding to the target path policy. + * Return a {@link PathPolicyFlowSelector} instance that selects flow + * entries corresponding to the target path policy. * - * @return A {@link PathPolicyFlowMatch} instance. + * @return A {@link PathPolicyFlowSelector} instance. */ - PathPolicyFlowMatch getFlowMatch() { - return new PathPolicyFlowMatch(policyId.intValue()); + PathPolicyFlowSelector getFlowSelector() { + return new PathPolicyFlowSelector(policyId.intValue()); } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathCostTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathCostTask.java index 79aa2866..25274d97 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathCostTask.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathCostTask.java @@ -17,7 +17,7 @@ import java.util.Map; import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.internal.PathPolicyFlowMatch; +import org.opendaylight.vtn.manager.internal.PathPolicyFlowSelector; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyUtils; @@ -139,8 +139,8 @@ public final class RemovePathCostTask for (VtnUpdateType status: result) { if (status != null) { // Remove all flow entries affected by the target path policy. - PathPolicyFlowMatch fmatch = context.getFlowMatch(); - addBackgroundTasks(provider.removeFlows(fmatch)); + PathPolicyFlowSelector selector = context.getFlowSelector(); + addBackgroundTasks(provider.removeFlows(selector)); context.onUpdated(); break; diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathPolicyTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathPolicyTask.java index e123130b..0b5448a1 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathPolicyTask.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/RemovePathPolicyTask.java @@ -11,7 +11,7 @@ package org.opendaylight.vtn.manager.internal.routing; import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.internal.PathPolicyFlowMatch; +import org.opendaylight.vtn.manager.internal.PathPolicyFlowSelector; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyUtils; @@ -100,8 +100,8 @@ public final class RemovePathPolicyTask extends DeleteDataTask @Override public void onSuccess(VTNManagerProvider provider, VtnUpdateType result) { // Remove all flow entries affected by the target path policy. - PathPolicyFlowMatch fmatch = context.getFlowMatch(); - addBackgroundTasks(provider.removeFlows(fmatch)); + PathPolicyFlowSelector selector = context.getFlowSelector(); + addBackgroundTasks(provider.removeFlows(selector)); context.onUpdated(); } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathCostTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathCostTask.java index 5b730689..16fec5d7 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathCostTask.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathCostTask.java @@ -17,7 +17,7 @@ import java.util.Set; import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.internal.PathPolicyFlowMatch; +import org.opendaylight.vtn.manager.internal.PathPolicyFlowSelector; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathCostConfigBuilder; @@ -135,8 +135,8 @@ public final class SetPathCostTask for (VtnUpdateType status: result) { if (status != null) { // Remove all flow entries affected by the target path policy. - PathPolicyFlowMatch fmatch = context.getFlowMatch(); - addBackgroundTasks(provider.removeFlows(fmatch)); + PathPolicyFlowSelector selector = context.getFlowSelector(); + addBackgroundTasks(provider.removeFlows(selector)); context.onUpdated(); break; diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathPolicyTask.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathPolicyTask.java index ae785abf..7d6aee4c 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathPolicyTask.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/SetPathPolicyTask.java @@ -11,7 +11,7 @@ package org.opendaylight.vtn.manager.internal.routing; import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.internal.PathPolicyFlowMatch; +import org.opendaylight.vtn.manager.internal.PathPolicyFlowSelector; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyConfigBuilder; @@ -53,7 +53,6 @@ public final class SetPathPolicyTask extends PutDataTask /** * Set {@code true} if the target path policy is required to be present. - * be present. */ private final boolean present; @@ -134,8 +133,6 @@ public final class SetPathPolicyTask extends PutDataTask return true; } - // PutDataTask - /** * {@inheritDoc} */ @@ -158,18 +155,18 @@ public final class SetPathPolicyTask extends PutDataTask @Override public void onSuccess(VTNManagerProvider provider, VtnUpdateType result) { if (result != null) { - PathPolicyFlowMatch fmatch; + PathPolicyFlowSelector selector; if (VtnUpdateType.CREATED.equals(result)) { // We need to remove all flow entries because a new path policy // may affect existing flow entries. - fmatch = null; + selector = null; } else { // Remove all flow entries affected by the target path policy. - fmatch = context.getFlowMatch(); + selector = context.getFlowSelector(); } // Remove flow entries affected by the update. - addBackgroundTasks(provider.removeFlows(fmatch)); + addBackgroundTasks(provider.removeFlows(selector)); context.onUpdated(); } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java index 483c6399..852f779e 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java @@ -23,6 +23,7 @@ import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.internal.RouteResolver; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.VTNSubSystem; import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; import org.opendaylight.vtn.manager.internal.util.DataStoreListener; import org.opendaylight.vtn.manager.internal.util.DataStoreUtils; @@ -63,7 +64,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpda */ public final class VTNRoutingManager extends DataStoreListener - implements VtnPathPolicyService { + implements VTNSubSystem, VtnPathPolicyService { /** * Logger instance. */ @@ -130,30 +131,6 @@ public final class VTNRoutingManager } } - /** - * Post a MD-SAL transaction task to initialize configuration. - * - * @param master {@code true} if the local node is the configuration - * provider. - * @return A {@link VTNFuture} instance. - */ - public VTNFuture initConfig(boolean master) { - return pathPolicyListener.initConfig(master); - } - - /** - * Create RPC implementations. - * - * @param rpcReg A {@link RpcProviderRegistry} service instance. - * @param regs A {@link CompositeAutoCloseable} instance to store - * RPC registration. - */ - public void initRpcServices(RpcProviderRegistry rpcReg, - CompositeAutoCloseable regs) { - regs.add(rpcReg. - addRpcImplementation(VtnPathPolicyService.class, this)); - } - /** * Add the given VTN routing listener. * @@ -317,6 +294,26 @@ public final class VTNRoutingManager return REQUIRED_EVENTS; } + // VTNConfigProvider + + /** + * {@inheritDoc} + */ + @Override + public VTNFuture initConfig(boolean master) { + return pathPolicyListener.initConfig(vtnProvider, master); + } + + /** + * {@inheritDoc} + */ + @Override + public void initRpcServices(RpcProviderRegistry rpcReg, + CompositeAutoCloseable regs) { + regs.add(rpcReg. + addRpcImplementation(VtnPathPolicyService.class, this)); + } + // VtnPathPolicyService /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/MiscUtils.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/MiscUtils.java index f4284100..74b2904e 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/MiscUtils.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/MiscUtils.java @@ -12,8 +12,6 @@ package org.opendaylight.vtn.manager.internal.util; import java.net.Inet4Address; import java.net.InetAddress; import java.util.Collection; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.slf4j.Logger; @@ -29,6 +27,7 @@ import org.opendaylight.controller.sal.packet.Packet; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; /** @@ -36,17 +35,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpda * methods. */ public final class MiscUtils { - /** - * Maximum length of the resource name. - */ - private static final int RESOURCE_NAME_MAXLEN = 31; - - /** - * Regular expression that matches valid resource name. - */ - private static final Pattern RESOURCE_NAME_REGEX = - Pattern.compile("^\\p{Alnum}[\\p{Alnum}_]*$"); - /** * Private constructor that protects this class from instantiating. */ @@ -67,10 +55,11 @@ public final class MiscUtils { * * @param desc Brief description of the resource. * @param name The name of the resource. - * @throws VTNException The specified name is invalid. + * @return A {@link VnodeName} instance that contains the given name. + * @throws RpcException The specified name is invalid. */ - public static void checkName(String desc, String name) - throws VTNException { + public static VnodeName checkName(String desc, String name) + throws RpcException { if (name == null) { throw getNullArgumentException(desc + " name"); } @@ -80,17 +69,29 @@ public final class MiscUtils { desc + " name cannot be empty"); } - int len = name.length(); - if (len > RESOURCE_NAME_MAXLEN) { - throw RpcException.getBadArgumentException( - desc + " name is too long"); + try { + return new VnodeName(name); + } catch (RuntimeException e) { + String msg = desc + " name is invalid"; + RpcException re = RpcException.getBadArgumentException(msg); + re.initCause(e); + throw re; } + } - Matcher m = RESOURCE_NAME_REGEX.matcher(name); - if (!m.matches()) { - throw RpcException.getBadArgumentException( - desc + " name contains invalid character"); - } + /** + * Check the specified resource name. + * + * @param desc Brief description of the resource. + * @param vname A {@link VnodeName} instance. + * @return Return the string configured in {@code vname}. + * @throws RpcException The specified name is invalid. + */ + public static String checkName(String desc, VnodeName vname) + throws RpcException { + String name = (vname == null) ? null : vname.getValue(); + checkName(desc, name); + return name; } /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/ProtocolUtils.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/ProtocolUtils.java index 4233f2bb..ccb144a3 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/ProtocolUtils.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/ProtocolUtils.java @@ -9,10 +9,16 @@ package org.opendaylight.vtn.manager.internal.util; -import org.opendaylight.vtn.manager.VTNException; - import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp; + /** * {@code ProtocolUtils} class is a collection of utilities for network * protocol handling. @@ -21,7 +27,7 @@ public final class ProtocolUtils { /** * Mask value which represents valid bits in an ethernet type. */ - public static final int MASK_ETHER_TYPE = 0xffff; + public static final long MASK_ETHER_TYPE = 0xffffL; /** * The number of bits in a valid VLAN ID. @@ -36,13 +42,18 @@ public final class ProtocolUtils { /** * A mask value which represents valid bits in an VLAN priority. */ - private static final byte MASK_VLAN_PRI = 0x7; + private static final short MASK_VLAN_PRI = 0x7; + + /** + * A mask value which represents valid bits in an IP protocol number. + */ + private static final short MASK_IP_PROTO = 0xff; /** * A mask value which represents valid bits in an DSCP value for * IP protocol. */ - private static final byte MASK_IP_DSCP = 0x3f; + private static final short MASK_IP_DSCP = 0x3f; /** * A mask value which represents valid bits in ICMP type and code. @@ -64,21 +75,60 @@ public final class ProtocolUtils { * Check the given ethernet type. * * @param type The ethernet type to be checked. - * @throws VTNException The given ethernet type is invalid. + * @throws RpcException The given ethernet type is invalid. */ - public static void checkEtherType(int type) throws VTNException { - if ((type & ~MASK_ETHER_TYPE) != 0) { + public static void checkEtherType(int type) throws RpcException { + if (((long)type & ~MASK_ETHER_TYPE) != 0) { throw invalidEtherType((long)type); } } /** - * Return a {@link VTNException} that notifies an invalid ethernet type. + * Return the ethernet type in the given {@link EtherType} instance. + * + * @param etype An {@link EtherType} instance. + * @return An {@link Integer} instance if the ethernet type is present + * in the given {@link EtherType} instance. + * Otherwise {@code null}. + * @throws RpcException The given ethernet type is invalid. + */ + public static Integer getEtherType(EtherType etype) throws RpcException { + if (etype != null) { + Long value = etype.getValue(); + if (value != null) { + long type = value.longValue(); + if ((type & ~MASK_ETHER_TYPE) != 0) { + throw invalidEtherType(type); + } + + return Integer.valueOf((int)type); + } + } + + return null; + } + + /** + * Return the ethernet type in the given {@link EthernetType} instance. + * + * @param etype An {@link EthernetType} instance. + * @return An {@link Integer} instance if the ethernet type is present + * in the given {@link EthernetType} instance. + * Otherwise {@code null}. + * @throws RpcException The given ethernet type is invalid. + */ + public static Integer getEtherType(EthernetType etype) + throws RpcException { + return (etype == null) ? null : getEtherType(etype.getType()); + } + + /** + * Return a {@link RpcException} that notifies an invalid ethernet type. * * @param type The invalid ethernet type. - * @return A {@link VTNException}. + * @return A {@link RpcException}. */ - private static VTNException invalidEtherType(long type) { + private static RpcException invalidEtherType(long type) { String msg = "Invalid Ethernet type: " + type; return RpcException.getBadArgumentException(msg); } @@ -87,15 +137,62 @@ public final class ProtocolUtils { * Check the specified VLAN ID. * * @param vlan VLAN ID. - * @throws VTNException The specified VLAN ID is invalid. + * @throws RpcException The specified VLAN ID is invalid. + */ + public static void checkVlan(short vlan) throws RpcException { + if (((long)vlan & ~MASK_VLAN_ID) != 0L) { + throw invalidVlanId((int)vlan); + } + } + + /** + * Check the specified VLAN ID. + * + * @param vlan VLAN ID. + * @throws RpcException The specified VLAN ID is invalid. */ - public static void checkVlan(short vlan) throws VTNException { + public static void checkVlan(int vlan) throws RpcException { if (((long)vlan & ~MASK_VLAN_ID) != 0L) { - String msg = "Invalid VLAN ID: " + vlan; - throw RpcException.getBadArgumentException(msg); + throw invalidVlanId(vlan); } } + /** + * Return the VLAN ID in the given {@link VlanId} instance. + * + * @param vid A {@link VlanId} instance. + * @return An {@link Integer} instance if the VLAN ID is present in the + * given {@link VlanId} instance. + * Otherwise {@code null}. + * @throws RpcException The given VLAN ID is invalid. + */ + public static Integer getVlanId(VlanId vid) throws RpcException { + Integer value = null; + if (vid != null) { + value = vid.getValue(); + if (value != null) { + // This check can be removed when RESTCONF implements the + // restriction check. + long vlan = value.longValue(); + if ((vlan & ~MASK_VLAN_ID) != 0) { + throw invalidVlanId(vlan); + } + } + } + + return value; + } + + /** + * Return a {@link RpcException} that notifies an invalid VLAN ID. + * + * @param vid The invalid VLAN ID. + * @return A {@link RpcException}. + */ + private static RpcException invalidVlanId(long vid) { + return RpcException.getBadArgumentException("Invalid VLAN ID: " + vid); + } + /** * Determine whether the specified VLAN priority value is valid or not. * @@ -103,7 +200,68 @@ public final class ProtocolUtils { * @return {@code true} only if the given VLAN priority is valid. */ public static boolean isVlanPriorityValid(byte pri) { - return ((pri & ~MASK_VLAN_PRI) == 0); + return (((short)pri & ~MASK_VLAN_PRI) == 0); + } + + /** + * Check the specified VLAN priority. + * + * @param pri A VLAN priority. + * @throws RpcException The specified VLAN priority is invalid. + */ + public static void checkVlanPriority(short pri) throws RpcException { + if ((pri & ~MASK_VLAN_PRI) != 0) { + throw RpcException.getBadArgumentException( + "Invalid VLAN priority: " + pri); + } + } + + /** + * Return the VLAN priority in the given {@link VlanPcp} instance. + * + * @param pcp A {@link VlanPcp} instance. + * @return An {@link Short} instance if the VLAN priority is present in + * the given {@link VlanPcp} instance. + * Otherwise {@code null}. + * @throws RpcException The given VLAN priority is invalid. + */ + public static Short getVlanPriority(VlanPcp pcp) throws RpcException { + Short value = null; + if (pcp != null) { + value = pcp.getValue(); + if (value != null) { + // This check can be removed when RESTCONF implements the + // restriction check. + short pri = value.shortValue(); + checkVlanPriority(pri); + } + } + + return value; + } + + /** + * Check the specified IP protocol number. + * + * @param proto An IP protocol number. + * @throws RpcException The specified IP protocol number is invalid. + */ + public static void checkIpProtocol(short proto) throws RpcException { + if ((proto & ~MASK_IP_PROTO) != 0) { + throw invalidIpProtocol(proto); + } + } + + /** + * Return a {@link RpcException} that notifies an invalid IP protocol + * number. + * + * @param proto The invalid IP protocol number. + * @return A {@link RpcException}. + */ + private static RpcException invalidIpProtocol(short proto) { + return RpcException.getBadArgumentException( + "Invalid IP protocol number: " + proto); } /** @@ -113,7 +271,54 @@ public final class ProtocolUtils { * @return {@code true} only if the given DSCP value is valid. */ public static boolean isDscpValid(byte dscp) { - return ((dscp & ~MASK_IP_DSCP) == 0); + return (((short)dscp & ~MASK_IP_DSCP) == 0); + } + + /** + * Check the specified IP DSCP field value. + * + * @param dscp An IP DSCP field value. + * @throws RpcException The specified IP DSCP value is invalid. + */ + public static void checkIpDscp(short dscp) throws RpcException { + if ((dscp & ~MASK_IP_DSCP) != 0) { + throw invalidIpDscp(dscp); + } + } + + /** + * Return the IP DSCP field value configured in the given {@link Dscp} + * instance. + * + * @param dscp A {@link Dscp} instance. + * @return A {@link Short} instance if the DSCP value is present in the + * given {@link Dscp} instance. + * Otherwise {@code null}. + * @throws RpcException The given DSCP value is invalid. + */ + public static Short getIpDscp(Dscp dscp) throws RpcException { + Short value = null; + if (dscp != null) { + value = dscp.getValue(); + if (value != null) { + // This check can be removed when RESTCONF implements the + // restriction check. + checkIpDscp(value.shortValue()); + } + } + + return value; + } + + /** + * Return a {@link RpcException} that notifies an invalid IP DSCP value. + * + * @param dscp The invalid IP DSCP value. + * @return A {@link RpcException}. + */ + private static RpcException invalidIpDscp(short dscp) { + return RpcException.getBadArgumentException( + "Invalid IP DSCP field value: " + dscp); } /** @@ -126,6 +331,22 @@ public final class ProtocolUtils { return ((value & ~MASK_ICMP_VALUE) == 0); } + /** + * Check the specified ICMP type or code value. + * + * @param value An ICMP type or code. + * @param desc A brief description about the given value. + * @throws RpcException The specified value is invalid. + */ + public static void checkIcmpValue(Short value, String desc) + throws RpcException { + if (value != null && !isIcmpValueValid(value.shortValue())) { + StringBuilder builder = new StringBuilder("Invalid ICMP "). + append(desc).append(": ").append(value); + throw RpcException.getBadArgumentException(builder.toString()); + } + } + /** * Determine whether the specified port number of transport layer protocol * is valid or not. @@ -136,4 +357,51 @@ public final class ProtocolUtils { public static boolean isPortNumberValid(int port) { return ((port & ~MASK_TP_PORT) == 0); } + + /** + * Check the specified port number of IP transport layer protocol. + * + * @param port A port number. + * @throws RpcException The specified port number is invalid. + */ + public static void checkPortNumber(int port) throws RpcException { + if (!isPortNumberValid(port)) { + throw invalidPortNumber(port); + } + } + + /** + * Return the port number configured in the given {@link PortNumber} + * instance. + * + * @param port A {@link PortNumber} instance. + * @return An {@link Integer} instance if the port number is present in + * the given {@link PortNumber} instance. + * Otherwise {@code null}. + * @throws RpcException The given port number is invalid. + */ + public static Integer getPortNumber(PortNumber port) throws RpcException { + Integer value = null; + if (port != null) { + value = port.getValue(); + if (value != null) { + // This check can be removed when RESTCONF implements the + // restriction check. + checkPortNumber(value.intValue()); + } + } + + return value; + } + + /** + * Return a {@link RpcException} that notifies an invalid port number. + * + * @param port The invalid port number. + * @return A {@link RpcException}. + */ + private static RpcException invalidPortNumber(int port) { + return RpcException.getBadArgumentException( + "Invalid port number: " + port); + } } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/XmlConfigFile.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/XmlConfigFile.java index 8f66be85..ea12736c 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/XmlConfigFile.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/XmlConfigFile.java @@ -61,9 +61,14 @@ public final class XmlConfigFile { CONFIG, /** - * Indicates the path policy configuration. + * Indicates the configuration for the path policy. */ - PATHPOLICY; + PATHPOLICY, + + /** + * Indicates the configuration for the flow condition. + */ + FLOWCOND; } /** diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReader.java new file mode 100644 index 00000000..b9b7a147 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReader.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.Map; +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.util.DataStoreUtils; + +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; + +/** + * Helper class to read flow conditions using the given MD-SAL datastore + * transaction. + * + *

+ * Note that this class is not synchronized. + *

+ */ +public final class FlowCondReader { + /** + * Logger instance. + */ + private static final Logger LOG = + LoggerFactory.getLogger(FlowCondReader.class); + + /** + * Cached flow conditions. + */ + private final Map conditionCache = + new HashMap<>(); + + /** + * Read transaction. + */ + private final ReadTransaction readTx; + + /** + * Construct a new instance. + * + * @param rtx A {@link ReadTransaction} instance. + */ + public FlowCondReader(ReadTransaction rtx) { + readTx = rtx; + } + + /** + * Return read transaction. + * + * @return A {@link ReadTransaction} instance. + */ + public ReadTransaction getReadTransaction() { + return readTx; + } + + /** + * Get the flow condition specified by the name. + * + * @param name The name of the flow condition. + * @return A {@link VTNFlowCondition} instance if found. + * {@code null} if not found. + */ + public VTNFlowCondition get(String name) { + VTNFlowCondition vfcond = conditionCache.get(name); + if (vfcond == null && !conditionCache.containsKey(name)) { + try { + vfcond = read(name); + } catch (VTNException e) { + LOG.warn(name + ": Ignore unreadable flow condition.", e); + vfcond = null; + } + conditionCache.put(name, vfcond); + } + + return vfcond; + } + + /** + * Read the flow condition specified by the name. + * + * @param name The name of the flow condition. + * @return A {@link VTNFlowCondition} instance if found. + * {@code null} if not found. + * @throws VTNException + * Failed to read flow condition. + */ + private VTNFlowCondition read(String name) throws VTNException { + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + Optional opt = + DataStoreUtils.read(readTx, oper, path); + return (opt.isPresent()) ? new VTNFlowCondition(opt.get()) : null; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtils.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtils.java new file mode 100644 index 00000000..a7861b1f --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtils.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import com.google.common.base.Optional; + +import org.opendaylight.vtn.manager.VTNException; + +import org.opendaylight.vtn.manager.internal.util.DataStoreUtils; +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * {@code FlowCondUtils} class is a collection of utility class methods + * for flow condition. + */ +public final class FlowCondUtils { + /** + * A brief description about flow condition. + */ + private static final String DESC_FLOW_COND = "Flow condition"; + + /** + * Private constructor that protects this class from instantiating. + */ + private FlowCondUtils() {} + + /** + * Return a new {@link RpcException} that indicates the specified flow + * condition is not present. + * + * @param name The name of the flow condition. + * @return An {@link RpcException}. + */ + public static RpcException getNotFoundException(String name) { + return getNotFoundException(name, null); + } + + /** + * Return a new {@link RpcException} that indicates the specified flow + * condition is not present. + * + * @param name The name of the flow condition. + * @param cause A {@link Throwable} which indicates the cause of error. + * @return An {@link RpcException}. + */ + public static RpcException getNotFoundException(String name, + Throwable cause) { + String msg = + MiscUtils.joinColon(name, "Flow condition does not exist."); + return RpcException.getNotFoundException(msg, cause); + } + + /** + * Return a new {@link RpcException} that indicates the flow match index + * is missing. + * + * @return An {@link RpcException}. + */ + public static RpcException getMatchIndexMissingException() { + return MiscUtils.getNullArgumentException("Match index"); + } + + /** + * Verify the name of the flow condition. + * + * @param name The name of the flow condition. + * @return A {@link VnodeName} instance that contains the given name. + * @throws RpcException The specified name is invalid. + */ + public static VnodeName checkName(String name) throws RpcException { + return MiscUtils.checkName(DESC_FLOW_COND, name); + } + + /** + * Verify the name of the flow condition. + * + * @param vname A {@link VnodeName} instance. + * @return Return the string in {@code vname}. + * @throws RpcException The specified name is invalid. + */ + public static String checkName(VnodeName vname) throws RpcException { + return MiscUtils.checkName(DESC_FLOW_COND, vname); + } + + /** + * Create the instance identifier for the flow condition specified by the + * given name. + * + *

+ * This method is used to retrieve existing flow condition. + *

+ * + * @param name The name of the flow condition. + * @return An {@link InstanceIdentifier} instance. + * @throws RpcException + * The given flow condition name is invalid. + */ + public static InstanceIdentifier getIdentifier( + String name) throws RpcException { + return getIdentifier(getVnodeName(name)); + } + + /** + * Create the instance identifier for the flow condition specified by the + * given name. + * + * @param vname A {@link VnodeName} instance that contains the name of + * the flow condition. + * @return An {@link InstanceIdentifier} instance. + */ + public static InstanceIdentifier getIdentifier( + VnodeName vname) { + return InstanceIdentifier.builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, new VtnFlowConditionKey(vname)). + build(); + } + + /** + * Create the instance identifier for the flow match specified by the + * given flow condition name and match index. + * + *

+ * This method is used to retrieve flow match in existing flow condition. + *

+ * + * @param name The name of the flow condition. + * @param index The index assigned to the flow match in a flow condition. + * @return An {@link InstanceIdentifier} instance. + * @throws RpcException + * The given flow condition name or match index is invalid. + */ + public static InstanceIdentifier getIdentifier( + String name, Integer index) throws RpcException { + return getIdentifier(getVnodeName(name), index); + } + + /** + * Create the instance identifier for the flow match specified by the + * given flow condition name and match index. + * + *

+ * This method is used to retrieve flow match in existing flow condition. + *

+ * + * @param vname A {@link VnodeName} instance that contains the name of + * the flow condition. + * @param index The index assigned to the flow match in a flow condition. + * @return An {@link InstanceIdentifier} instance. + * @throws RpcException + * The given flow condition name or match index is invalid. + */ + public static InstanceIdentifier getIdentifier( + VnodeName vname, Integer index) throws RpcException { + if (index == null) { + throw getMatchIndexMissingException(); + } + + return InstanceIdentifier.builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, new VtnFlowConditionKey(vname)). + child(VtnFlowMatch.class, new VtnFlowMatchKey(index)).build(); + } + + /** + * Return a {@link VnodeName} instance that contains the given flow + * condition name. + * + *

+ * This method is used to retrieve existing flow condition. + *

+ * + * @param name The name of the flow condition. + * @return A {@link VnodeName} instance that contains the given name. + * @throws RpcException The specified name is invalid. + */ + public static VnodeName getVnodeName(String name) throws RpcException { + try { + return MiscUtils.checkName(DESC_FLOW_COND, name); + } catch (RpcException e) { + if (e.getErrorTag() == RpcErrorTag.BAD_ELEMENT) { + // The specified flow condition should not be present because + // the given name is invalid. + throw getNotFoundException(name, e); + } + throw e; + } + } + + /** + * Return the name of the flow condition configured in the given + * instance identifier. + * + * @param path An {@link InstanceIdentifier} instance. + * @return The name of the flow condition if found. + * {@code null} if not found. + */ + public static String getName(InstanceIdentifier path) { + VtnFlowConditionKey key = + path.firstKeyOf(VtnFlowCondition.class, VtnFlowConditionKey.class); + if (key == null) { + return null; + } + + VnodeName vname = key.getName(); + return (vname == null) ? null : vname.getValue(); + } + + /** + * Ensure that there is no duplicate match index in the match list. + * + * @param set A set of match indices. + * @param index An index to be tested. + * @throws RpcException An error occurred. + */ + public static void verifyMatchIndex(Set set, Integer index) + throws RpcException { + if (!set.add(index)) { + String msg = "Duplicate match index: " + index; + throw RpcException.getBadArgumentException(msg); + } + } + + /** + * Verify the given index number for a flow match in a flow condition. + * + * @param index A match index to be verified. + * @throws RpcException + * The given match index is invalid. + */ + public static void verifyMatchIndex(Integer index) throws RpcException { + if (index == null) { + throw getMatchIndexMissingException(); + } + + try { + new VtnFlowMatchBuilder().setIndex(index); + } catch (RuntimeException e) { + String msg = "Invalid match index: " + index; + RpcException re = RpcException.getBadArgumentException(msg); + re.initCause(e); + throw re; + } + } + + /** + * Determine whether the specified flow condition is present or not. + * + * @param rtx A {@link ReadTransaction} instance associated with the + * read transaction for the MD-SAL datastore. + * @param vname A {@lnk VnodeName} instance that contains the name of the + * target flow condition. + * @throws RpcException + * The specified flow condition is not present. + * @throws VTNException + * Failed to read the MD-SAL datastore. + */ + public static void checkPresent(ReadTransaction rtx, VnodeName vname) + throws VTNException { + InstanceIdentifier path = getIdentifier(vname); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + Optional opt = DataStoreUtils.read(rtx, oper, path); + if (!opt.isPresent()) { + throw getNotFoundException(vname.getValue()); + } + } + + /** + * Read all the flow conditions from the MD-SAL datastore. + * + * @param rtx A {@link ReadTransaction} instance. + * @return A list of {@link VTNFlowCondition} instances. + * @throws VTNException An error occurred. + */ + public static List readFlowConditions(ReadTransaction rtx) + throws VTNException { + InstanceIdentifier path = + InstanceIdentifier.create(VtnFlowConditions.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + Optional opt = DataStoreUtils.read(rtx, oper, path); + List vlist = null; + if (opt.isPresent()) { + vlist = opt.get().getVtnFlowCondition(); + } + if (vlist == null || vlist.isEmpty()) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(vlist.size()); + for (VtnFlowCondition vfc: vlist) { + list.add(new VTNFlowCondition(vfc)); + } + + return list; + } + + /** + * Read the flow condition specified by the given name from the MD-SAL + * datastore. + * + * @param rtx A {@link ReadTransaction} instance. + * @param name The name of the flow condition. + * @return A {@link VTNFlowCondition} instance. + * @throws VTNException An error occurred. + */ + public static VTNFlowCondition readFlowCondition(ReadTransaction rtx, + String name) + throws VTNException { + InstanceIdentifier path = getIdentifier(name); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + Optional opt = DataStoreUtils.read(rtx, oper, path); + if (opt.isPresent()) { + return new VTNFlowCondition(opt.get()); + } + + throw getNotFoundException(name); + } + + /** + * Read the flow match specified by the given index in the given flow + * condition from the MD-SAL datastore. + * + * @param rtx A {@link ReadTransaction} instance. + * @param name The name of the flow condition. + * @param idx The match index that specifies the flow match in the + * flow condition. + * @return A {@link VTNFlowMatch} instance. + * {@code null} is returned if no flow match is associated + * with the given match index in the flow condition. + * @throws VTNException An error occurred. + */ + public static VTNFlowMatch readFlowMatch(ReadTransaction rtx, String name, + int idx) throws VTNException { + VnodeName vname = getVnodeName(name); + InstanceIdentifier path = getIdentifier(vname, idx); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + Optional opt = DataStoreUtils.read(rtx, oper, path); + if (opt.isPresent()) { + return new VTNFlowMatch(opt.get()); + } + + // Check to see if the flow condition is present. + checkPresent(rtx, vname); + + return null; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowCondition.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowCondition.java new file mode 100644 index 00000000..c44b5987 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowCondition.java @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.opendaylight.vtn.manager.flow.cond.FlowCondition; +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.util.VTNIdentifiable; +import org.opendaylight.vtn.manager.util.VTNIdentifiableComparator; + +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchContext; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowCondConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * {@code VTNFlowCondition} describes configuration for a flow condition. + */ +@XmlRootElement(name = "vtn-flow-condition") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNFlowCondition implements VTNIdentifiable { + /** + * Logger instance. + */ + private static final Logger LOG = + LoggerFactory.getLogger(VTNFlowCondition.class); + + /** + * The name of the flow condition. + */ + @XmlElement(required = true) + private String name; + + /** + * A list of {@link VTNFlowMatch} instances sorted by match index. + */ + @XmlElementWrapper(name = "vtn-flow-matches") + @XmlElement(name = "vtn-flow-match") + private List matches; + + /** + * A {@link VnodeName} instance that contains the name of this flow + * condition. + */ + private VnodeName nodeName; + + /** + * {@code MatchInitializer} initializes the list of {@link VTNFlowMatch} + * instances. + * + * @param The type of object to be used to create a + * {@link VTNFlowMatch} instance. + */ + private abstract static class MatchInitializer { + /** + * Initialize the list of {@link VTNFlowMatch} instances. + * + * @param srcList A list of objects used to create a list of + * {@link VTNFlowMatch} instances. + * @return A list of {@link VTNFlowMatch} instance. + * @throws RpcException An error occurred. + */ + protected final List initialize(List srcList) + throws RpcException { + if (srcList == null || srcList.isEmpty()) { + return Collections.emptyList(); + } + + // Ensure that all match indices are unique. + List list = newList(srcList); + Set indices = new HashSet<>(); + for (T obj: srcList) { + VTNFlowMatch vfmatch = convert(obj); + Integer index = vfmatch.getIdentifier(); + FlowCondUtils.verifyMatchIndex(indices, index); + add(list, vfmatch); + } + + // Sort matches by index. + VTNIdentifiableComparator comparator = + new VTNIdentifiableComparator<>(Integer.class); + Collections.sort(list, comparator); + + return list; + } + + /** + * Convert the given object into a {@link VTNFlowMatch} instance. + * + * @param obj An object to be converted. + * @return A {@link VTNFlowMatch} instance. + * @throws RpcException An error occurred. + */ + protected abstract VTNFlowMatch convert(T obj) throws RpcException; + + /** + * Return a new list of {@link VTNFlowMatch} instances. + * + * @param srcList A list of objects used to create a list of + * {@link VTNFlowMatch} instances. + * @return A list of {@link VTNFlowMatch} instance. + */ + protected abstract List newList(List srcList); + + /** + * Add the given {@link VTNFlowMatch} instance into the tail of the + * given list. + * + * @param list A list of {@link VTNFlowMatch} instances. + * @param vfmatch A {@link VTNFlowMatch} instance to be added. + */ + protected abstract void add(List list, + VTNFlowMatch vfmatch); + } + + /** + * {@code MatchVerifier} verifies the given list of {@link VTNFlowMatch} + * instances. + */ + private static final class MatchVerifier + extends MatchInitializer { + /** + * Convert the given object into a {@link VTNFlowMatch} instance. + * + * @param vfmatch A {@link VTNFlowMatch} instance. + * @return {@code vfmatch}. + * @throws RpcException An error occurred. + */ + @Override + protected VTNFlowMatch convert(VTNFlowMatch vfmatch) + throws RpcException { + vfmatch.verify(); + return vfmatch; + } + + /** + * This method does nothing. + * + * @param srcList A list of {@link VTNFlowMatch} instances. + * @return {@code srcList} is always returned. + */ + @Override + protected List newList(List srcList) { + return srcList; + } + + /** + * This method does nothing. + * + * @param list Unused. + * @param vfmatch Unused. + */ + @Override + protected void add(List list, VTNFlowMatch vfmatch) { + } + } + + /** + * {@code MatchConverter} converts the given list into a list of + * {@link VTNFlowMatch} instances. + * + * @param The type of object to be used to create a + * {@link VTNFlowMatch} instance. + */ + private abstract static class MatchConverter + extends MatchInitializer { + /** + * {@inheritDoc} + */ + @Override + protected final List newList(List srcList) { + return new ArrayList(srcList.size()); + } + + /** + * {@inheritDoc} + */ + @Override + protected final void add(List list, + VTNFlowMatch vfmatch) { + list.add(vfmatch); + } + } + + /** + * {@code FlowMatchConverter} converts the given list of {@link FlowMatch} + * instances into a list of {@link VTNFlowMatch} instances. + */ + public static final class FlowMatchConverter + extends MatchConverter { + /** + * Convert the given {@link FlowMatch} instance into a + * {@link VTNFlowMatch} instance. + * + * @param fm A {@link FlowMatch} instance to be converted. + * @return A {@link VTNFlowMatch} instance. + * @throws RpcException An error occurred. + */ + protected VTNFlowMatch convert(FlowMatch fm) throws RpcException { + return new VTNFlowMatch(fm); + } + } + + /** + * {@code VtnFlowMatchConverter} converts the given list of + * {@link VtnFlowMatch} + * instances into a list of {@link VTNFlowMatch} instances. + */ + public static final class VtnFlowMatchConverter + extends MatchConverter { + /** + * Convert the given {@link VtnFlowMatch} instance into a + * {@link VTNFlowMatch} instance. + * + * @param vfm A {@link VtnFlowMatch} instance to be converted. + * @return A {@link VTNFlowMatch} instance. + * @throws RpcException An error occurred. + */ + protected VTNFlowMatch convert(VtnFlowMatch vfm) throws RpcException { + return new VTNFlowMatch(vfm); + } + } + + /** + * Convert the given {@link VtnFlowCondition} instance into a + * {@link VTNFlowCondition} instance. + * + * @param vfc A {@link VtnFlowCondition} instance to be converted. + * @return A {@link VTNFlowCondition} instance on success. + * {@code null} on failure. + */ + public static VTNFlowCondition create(VtnFlowCondition vfc) { + try { + return new VTNFlowCondition(vfc); + } catch (Exception e) { + LOG.warn("Ignore broken flow condition: " + vfc, e); + } + + return null; + } + + /** + * Private constructor only for JAXB. + */ + @SuppressWarnings("unused") + private VTNFlowCondition() { + } + + /** + * Construct a new instance from the given name and {@link FlowCondition} + * instance. + * + * @param nm The name of the flow condition. + * @param fcond A {@link FlowCondition} instance. + * @throws RpcException An error occurred. + */ + public VTNFlowCondition(String nm, FlowCondition fcond) + throws RpcException { + nodeName = FlowCondUtils.checkName(nm); + name = nm; + + List list = (fcond == null) + ? null : fcond.getMatches(); + matches = new FlowMatchConverter().initialize(list); + } + + /** + * Construct a new instance from the given {@link VtnFlowCondConfig} + * instance. + * + * @param vfconf A {@link VtnFlowCondConfig} instance. + * @throws RpcException An error occurred. + */ + public VTNFlowCondition(VtnFlowCondConfig vfconf) throws RpcException { + nodeName = vfconf.getName(); + name = FlowCondUtils.checkName(nodeName); + + List list = vfconf.getVtnFlowMatch(); + matches = new VtnFlowMatchConverter().initialize(list); + } + + /** + * Return a {@link FlowCondition} instance which represents this condition. + * + * @return A {@link FlowCondition} instance. + */ + public FlowCondition toFlowCondition() { + List list; + if (matches.isEmpty()) { + list = null; + } else { + list = new ArrayList(); + for (VTNFlowMatch vfmatch: matches) { + list.add(vfmatch.toFlowMatch()); + } + } + + return new FlowCondition(name, list); + } + + /** + * Return a {@link VtnFlowConditionBuilder} instance which contains the + * configuration configured in this instance. + * + * @return A {@link VtnFlowConditionBuilder} instance. + */ + public VtnFlowConditionBuilder toVtnFlowConditionBuilder() { + VtnFlowConditionBuilder builder = new VtnFlowConditionBuilder(). + setName(nodeName); + + List list; + if (matches != null && !matches.isEmpty()) { + list = new ArrayList(); + for (VTNFlowMatch vfmatch: matches) { + list.add(vfmatch.toVtnFlowMatchBuilder().build()); + } + builder.setVtnFlowMatch(list); + } + + return builder; + } + + /** + * Return a {@link SetFlowConditionInputBuilder} instance which contains + * the configuration configured in this instance. + * + * @return A {@link SetFlowConditionInputBuilder} instance. + */ + public SetFlowConditionInputBuilder toSetFlowConditionInputBuilder() { + VtnFlowConditionBuilder builder = toVtnFlowConditionBuilder(); + return new SetFlowConditionInputBuilder(builder.build()); + } + + /** + * Return the path to this flow condition. + * + * @return An {@link InstanceIdentifier} instance that represents the path + * to this flow condition. + */ + public InstanceIdentifier getPath() { + return InstanceIdentifier.builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, new VtnFlowConditionKey(nodeName)). + build(); + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + public void verify() throws RpcException { + nodeName = FlowCondUtils.checkName(name); + matches = new MatchVerifier().initialize(matches); + } + + /** + * Determine whether this flow condition matches the given packet header + * or not. + * + * @param ctx A {@link FlowMatchContext} instance. + * @return {@code true} if this flow condition matches the packet header + * specified by {@code ctx}. Otherwise {@code false}. + */ + public boolean match(FlowMatchContext ctx) { + boolean empty = matches.isEmpty(); + if (empty) { + traceMatch(ctx, "Matched an empty condition"); + return true; + } + + for (VTNFlowMatch vfmatch: matches) { + if (vfmatch.match(ctx)) { + traceMatch(ctx, "Matched the condition", vfmatch); + return true; + } else { + traceMatch(ctx, "Does not match", vfmatch); + } + } + + traceMatch(ctx, "Unmatched"); + return false; + } + + /** + * Record a trace log for the result of {@link #match(FlowMatchContext)}. + * + * @param ctx A {@link FlowMatchContext} instance. + * @param msg A message to be logged. + */ + private void traceMatch(FlowMatchContext ctx, String msg) { + if (LOG.isTraceEnabled()) { + LOG.trace("{}: {}: packet=[{}]", name, msg, + ctx.getHeaderDescription()); + } + } + + /** + * Record a trace log for the result of {@link #match(FlowMatchContext)}. + * + * @param ctx A {@link FlowMatchContext} instance. + * @param msg A message to be logged. + * @param vfmatch A {@link VTNFlowMatch} instance that matched the packet. + */ + private void traceMatch(FlowMatchContext ctx, String msg, + VTNFlowMatch vfmatch) { + if (LOG.isTraceEnabled()) { + LOG.trace("{}: {}: match=[{}], packet=[{}]", name, msg, + vfmatch.getConditionKey(), ctx.getHeaderDescription()); + } + } + + // VTNIdentifiable + + /** + * Return the identifier of this instance. + * + * @return The name of the flow condition. + */ + @Override + public String getIdentifier() { + return name; + } + + // Object + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNFlowCondition vfcond = (VTNFlowCondition)o; + return (Objects.equals(name, vfcond.name) && + Objects.equals(matches, vfcond.matches)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + return Objects.hash(name, matches); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatch.java new file mode 100644 index 00000000..2dcc463c --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatch.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSeeAlso; + +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.util.VTNIdentifiable; + +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.flow.match.VTNEtherMatch; +import org.opendaylight.vtn.manager.internal.util.flow.match.VTNInetMatch; +import org.opendaylight.vtn.manager.internal.util.flow.match.VTNLayer4Match; +import org.opendaylight.vtn.manager.internal.util.flow.match.VTNMatch; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowMatchConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.input.FlowMatchListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; + +/** + * {@code VTNFlowMatch} describes the condition to match against packtes + * in a flow condition. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-flow-match") +@XmlAccessorType(XmlAccessType.NONE) +@XmlSeeAlso(VTNMatch.class) +public class VTNFlowMatch extends VTNMatch + implements VTNIdentifiable { + /** + * An index value which identifies flow match in a flow condition. + */ + @XmlElement(required = true) + private Integer index; + + /** + * Private constructor only for JAXB. + */ + @SuppressWarnings("unused") + private VTNFlowMatch() { + } + + /** + * Construct a new flow match from the given {@link FlowMatch} instance. + * + * @param fmatch A {@link FlowMatch} instance. + * @throws RpcException + * {@code fmatch} contains invalid value. + */ + public VTNFlowMatch(FlowMatch fmatch) throws RpcException { + if (fmatch == null) { + throw MiscUtils.getNullArgumentException("Flow match"); + } + + index = fmatch.getIndex(); + FlowCondUtils.verifyMatchIndex(index); + set(fmatch); + } + + /** + * Construct a new flow match from the given {@link VtnFlowMatchConfig} + * instance. + * + * @param vfmatch A {@link VtnFlowMatchConfig} instance. + * @throws RpcException + * {@code vfmatch} contains invalid value. + */ + public VTNFlowMatch(VtnFlowMatchConfig vfmatch) throws RpcException { + if (vfmatch == null) { + throw MiscUtils.getNullArgumentException("VTN flow match"); + } + + index = vfmatch.getIndex(); + FlowCondUtils.verifyMatchIndex(index); + set(vfmatch); + } + + /** + * Return a {@link VtnFlowMatchBuilder} instance which contains the flow + * conditions configured in this instance. + * + * @return A {@link VtnFlowMatchBuilder} instance. + */ + public VtnFlowMatchBuilder toVtnFlowMatchBuilder() { + VtnFlowMatchBuilder builder = new VtnFlowMatchBuilder(). + setIndex(index); + VTNEtherMatch eth = getEtherMatch(); + if (eth != null) { + builder.setVtnEtherMatch(eth.toVtnEtherMatchBuilder().build()); + VTNInetMatch inet = getInetMatch(); + if (inet != null) { + builder.setVtnInetMatch(inet.toVtnInetMatchBuilder().build()); + VTNLayer4Match l4 = getLayer4Match(); + if (l4 != null) { + l4.setVtnMatch(builder); + } + } + } + + return builder; + } + + /** + * Return a {@link FlowMatchListBuilder} instance which contains the flow + * conditions configured in this instance. + * + * @return A {@link FlowMatchListBuilder} instance. + */ + public FlowMatchListBuilder toFlowMatchListBuilder() { + FlowMatchListBuilder builder = new FlowMatchListBuilder(). + setIndex(index); + builder.fieldsFrom(toVtnFlowMatchBuilder().build()); + return builder; + } + + // VTNMatch + + /** + * Return a {@link FlowMatch} instance which represents this condition. + * + * @return A {@link FlowMatch} instance. + */ + @Override + public FlowMatch toFlowMatch() { + return toFlowMatch(index); + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + @Override + public void verify() throws RpcException { + FlowCondUtils.verifyMatchIndex(index); + super.verify(); + } + + // VTNIdentifiable + + /** + * Return the index value assigned to this instance. + * + * @return An {@link Integer} instance which represents the index value + * assigned to this instance. {@code null} if not assigned. + */ + @Override + public Integer getIdentifier() { + return index; + } + + // Object + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!super.equals(o)) { + return false; + } + + VTNFlowMatch vfm = (VTNFlowMatch)o; + return Objects.equals(index, vfm.index); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + int h = super.hashCode(); + if (index != null) { + h *= index.hashCode(); + } + + return h; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/package-info.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/package-info.java new file mode 100644 index 00000000..80187f9d --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/cond/package-info.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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 + */ + +/** + * This package contains utility classes for flow condition management. + */ +@XmlJavaTypeAdapters({ + @XmlJavaTypeAdapter(value = ByteAdapter.class, type = Byte.class), + @XmlJavaTypeAdapter(value = ByteAdapter.class, type = byte.class), + @XmlJavaTypeAdapter(value = ShortAdapter.class, type = Short.class), + @XmlJavaTypeAdapter(value = ShortAdapter.class, type = short.class), + @XmlJavaTypeAdapter(value = IntegerAdapter.class, type = Integer.class), + @XmlJavaTypeAdapter(value = IntegerAdapter.class, type = int.class), + @XmlJavaTypeAdapter(value = LongAdapter.class, type = Long.class), + @XmlJavaTypeAdapter(value = LongAdapter.class, type = long.class), +}) +package org.opendaylight.vtn.manager.internal.util.flow.cond; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters; + +import org.opendaylight.vtn.manager.util.xml.adapters.ByteAdapter; +import org.opendaylight.vtn.manager.util.xml.adapters.IntegerAdapter; +import org.opendaylight.vtn.manager.util.xml.adapters.LongAdapter; +import org.opendaylight.vtn.manager.util.xml.adapters.ShortAdapter; diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchContext.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchContext.java new file mode 100644 index 00000000..3e6a5874 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchContext.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.internal.util.packet.PacketHeader; + +/** + * {@code FlowMatchContext} describes a context to build flow match. + */ +public interface FlowMatchContext extends PacketHeader { + /** + * Add a match field to be configured into a flow entry. + * + * @param type A match type to be added. + */ + void addMatchField(FlowMatchType type); + + /** + * Determine whether the given match field will be configured in a flow + * entry or not. + * + * @param type A match type to be tested. + * @return {@code true} only if the given match type will be configured + * in a flow entry. + */ + boolean hasMatchField(FlowMatchType type); + + /** + * Add match fields to be configured into an unicast flow entry. + */ + void addUnicastMatchFields(); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchType.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchType.java new file mode 100644 index 00000000..cbec3b5f --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchType.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Set; + +/** + * {@code FlowMatchType} describes the type of flow match field supported + * by the VTN Manager. + */ +public enum FlowMatchType { + /** + * Indicates the ingress switch port. + */ + IN_PORT, + + /** + * Indicates the source MAC address in ethernet header. + */ + DL_SRC, + + /** + * Indicates the destination MAC address in ethernet header. + */ + DL_DST, + + /** + * Indicates the ethernet type in ethernet header. + */ + DL_TYPE, + + /** + * Indicates the VLAN ID in IEEE 802.1Q VLAN tag. + */ + DL_VLAN, + + /** + * Indicates the VLAN priority value in IEEE 802.1Q VLAN tag. + */ + DL_VLAN_PCP, + + /** + * Indicates the source IP address in IP header. + */ + IP_SRC, + + /** + * Indicates the destination IP address in IP header. + */ + IP_DST, + + /** + * Indicates the IP protocol number in IP header. + */ + IP_PROTO, + + /** + * Indicates the IP DSCP value in IP header. + */ + IP_DSCP, + + /** + * Indicates the source port number in TCP header. + */ + TCP_SRC, + + /** + * Indicates the destination port number in TCP header. + */ + TCP_DST, + + /** + * Indicates the source port number in UDP header. + */ + UDP_SRC, + + /** + * Indicates the destination port number in UDP header. + */ + UDP_DST, + + /** + * Indicates the ICMP type in ICMP header. + */ + ICMP_TYPE, + + /** + * Indicates the ICMP code in ICMP header. + */ + ICMP_CODE; + + /** + * Flow match fields to be configured in every unicast flow entry. + */ + private static final FlowMatchType[] UNICAST_MATCHES = { + DL_SRC, DL_DST, + }; + + /** + * Add match fields mandatory for unicast flow entries to the given set. + * + * @param set A set to store match fields mandatory for unicast flow + * entry. + */ + public static void addUnicastTypes(Set set) { + for (FlowMatchType type: UNICAST_MATCHES) { + set.add(type); + } + } + + /** + * Return the number of match types mandatory for unicast flow entries + * in the given set. + * + * @param set A set of {@link FlowMatchType}. + * @return The number of match types mandatory for unicast flow entries. + */ + public static int getUnicastTypeCount(Set set) { + int count = 0; + for (FlowMatchType type: UNICAST_MATCHES) { + if (set.contains(type)) { + count++; + } + } + + return count; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatch.java new file mode 100644 index 00000000..955a1e9e --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatch.java @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; +import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.NumberUtils; + +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.sal.packet.address.EthernetAddress; +import org.opendaylight.controller.sal.utils.Status; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnEtherMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.EthernetMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.MacAddressFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.VlanMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestination; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSource; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp; + +/** + * {@code VTNEtherMatch} describes the condition for ethernet header to match + * against packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-ether-match") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNEtherMatch { + /** + * The source MAC address to match. + */ + @XmlElement(name = "source-address") + private EtherAddress sourceAddress; + + /** + * The destination MAC address to match. + */ + @XmlElement(name = "destination-address") + private EtherAddress destinationAddress; + + /** + * The ethernet type to match. + */ + @XmlElement(name = "ether-type") + private Integer etherType; + + /** + * The VLAN ID to match. + */ + @XmlElement(name = "vlan-id") + private Integer vlanId; + + /** + * The VLAN priority to match. + */ + @XmlElement(name = "vlan-pcp") + private Short vlanPriority; + + /** + * Create a new instance from the given MD-SAL flow match. + * + * @param match A MD-SAL flow match. + * @return A {@link VTNEtherMatch} instance or {@code null}. + * @throws NullPointerException + * {@code match} is {@code null}. + * @throws RpcException + * {@code match} contains invalid condition against Ethernet header. + */ + public static VTNEtherMatch create(Match match) throws RpcException { + EthernetMatchFields eth = match.getEthernetMatch(); + VlanMatchFields vlan = match.getVlanMatch(); + return (eth != null || vlan != null) + ? new VTNEtherMatch(eth, vlan) : null; + } + + /** + * Construct a new instance that matches every packet. + */ + public VTNEtherMatch() { + } + + /** + * Construct a new instance that matches the given Ethernet type. + * + * @param type An {@link Integer} instance whcih represents the ethernet + * type to match against packets. + * {@code null} matches every ethernet type. + */ + public VTNEtherMatch(Integer type) { + etherType = type; + } + + /** + * Construct a new instance from the given {@link EthernetMatch} instance. + * + * @param ematch An {@link EthernetMatch} instance. + * @throws NullPointerException + * {@code ematch} is {@code null}. + * @throws RpcException + * {@code ematch} contains invalid value. + */ + public VTNEtherMatch(EthernetMatch ematch) throws RpcException { + Status st = ematch.getValidationStatus(); + if (st != null) { + throw new RpcException(RpcErrorTag.BAD_ELEMENT, st); + } + + sourceAddress = EtherAddress.create(ematch.getSourceAddress()); + destinationAddress = + EtherAddress.create(ematch.getDestinationAddress()); + etherType = ematch.getType(); + vlanId = NumberUtils.toInteger(ematch.getVlan()); + vlanPriority = NumberUtils.toShort(ematch.getVlanPriority()); + verify(); + } + + /** + * Construct a new instance from the given {@link VtnEtherMatchFields}. + * + * @param vematch A {@link VtnEtherMatchFields} instance. + * @throws NullPointerException + * {@code vematch} is {@code null}. + * @throws RpcException + * {@code vematch} contains invalid value. + */ + public VTNEtherMatch(VtnEtherMatchFields vematch) throws RpcException { + sourceAddress = getMacAddress(vematch.getSourceAddress(), + VTNMatch.DESC_SRC); + destinationAddress = getMacAddress(vematch.getDestinationAddress(), + VTNMatch.DESC_DST); + etherType = ProtocolUtils.getEtherType(vematch.getEtherType()); + vlanId = ProtocolUtils.getVlanId(vematch.getVlanId()); + vlanPriority = ProtocolUtils.getVlanPriority(vematch.getVlanPcp()); + if (vlanPriority != null) { + checkVlanPriority(); + } + } + + /** + * Construct a new instance from the given {@link EthernetMatchFields} and + * {@link VlanMatchFields} instances. + * + * @param ematch A {@link EthernetMatchFields} instance. + * @param vmatch A {@link VlanMatchFields} instance. + * @throws RpcException + * {@code ematch} or {@code vmatch} contains invalid value. + */ + public VTNEtherMatch(EthernetMatchFields ematch, VlanMatchFields vmatch) + throws RpcException { + if (ematch != null) { + sourceAddress = getMacAddress(ematch.getEthernetSource(), + VTNMatch.DESC_SRC); + destinationAddress = getMacAddress(ematch.getEthernetDestination(), + VTNMatch.DESC_DST); + etherType = ProtocolUtils.getEtherType(ematch.getEthernetType()); + } + + if (vmatch != null) { + initVlanId(vmatch.getVlanId()); + vlanPriority = ProtocolUtils.getVlanPriority(vmatch.getVlanPcp()); + if (vlanPriority != null) { + checkVlanPriority(); + } + } + } + + /** + * Return the source MAC address to match against packets. + * + * @return An {@link EtherAddress} instance if the source MAC address + * is specified. {@code null} if not specified. + */ + public EtherAddress getSourceAddress() { + return sourceAddress; + } + + /** + * Return the destination MAC address to match against packets. + * + * @return An {@link EtherAddress} instance if the destination MAC address + * is specified. {@code null} if not specified. + */ + public EtherAddress getDestinationAddress() { + return destinationAddress; + } + + /** + * Return the ethernet type to match against packets. + * + * @return An {@link Integer} instance if the ethernet type is specified. + * {@code null} if not specified. + */ + public Integer getEtherType() { + return etherType; + } + + /** + * Set the ethernet type to match against packets. + * + * @param type An {@link Integer} instance whcih represents the ethernet + * type to match against packets. + * {@code null} matches every ethernet type. + * @throws RpcException + * The Ethernet type different from the given type is already configured + * in this instance. + */ + public void setEtherType(Integer type) throws RpcException { + if (etherType != null && !etherType.equals(type)) { + StringBuilder builder = + new StringBuilder("Ethernet type conflict: type=0x"); + builder.append(Integer.toHexString(etherType.intValue())). + append(", expected=0x"). + append(Integer.toHexString(type.intValue())); + String msg = builder.toString(); + throw RpcException.getBadArgumentException(msg); + } + etherType = type; + } + + /** + * Return the VLAN ID to match against packets. + * + * @return A {@link Integer} instance if the VLAN ID is specified. + * Note that {@link EtherHeader#VLAN_NONE} matches packets + * that have no VLAN tag. + * {@code null} if the VLAN ID is not specified. + */ + public Integer getVlanId() { + return vlanId; + } + + /** + * Return the VLAN priority to match against packets. + * + * @return A {@link Short} instance if the VLAN priority is specified. + * {@code null} if the VLAN priority is not specified. + */ + public Short getVlanPriority() { + return vlanPriority; + } + + /** + * Return an {@link EthernetMatch} instance which represents this + * condition. + * + * @return An {@link EthernetMatch} instance. + */ + public EthernetMatch toEthernetMatch() { + EthernetAddress src = (sourceAddress == null) + ? null : sourceAddress.getEthernetAddress(); + EthernetAddress dst = (destinationAddress == null) + ? null : destinationAddress.getEthernetAddress(); + Short vid = NumberUtils.toShort(vlanId); + Byte pri = NumberUtils.toByte(vlanPriority); + + return new EthernetMatch(src, dst, etherType, vid, pri); + } + + /** + * Return a {@link VtnEtherMatchBuilder} instance which contains the flow + * conditions configured in this instance. + * + * @return A {@link VtnEtherMatchBuilder} instance. + */ + public VtnEtherMatchBuilder toVtnEtherMatchBuilder() { + VtnEtherMatchBuilder builder = new VtnEtherMatchBuilder(); + if (sourceAddress != null) { + builder.setSourceAddress(sourceAddress.getMacAddress()); + } + if (destinationAddress != null) { + builder.setDestinationAddress(destinationAddress.getMacAddress()); + } + if (etherType != null) { + Long type = NumberUtils.toLong(etherType); + builder.setEtherType(new EtherType(type)); + } + if (vlanId != null) { + builder.setVlanId(new VlanId(vlanId)); + } + if (vlanPriority != null) { + builder.setVlanPcp(new VlanPcp(vlanPriority)); + } + + return builder; + } + + /** + * Configure the condition represented by this instance into the given + * MD-SAL flow match builder. + * + * @param builder A {@link MatchBuilder} instance. + */ + public void setMatch(MatchBuilder builder) { + EthernetMatchBuilder ematch = null; + if (sourceAddress != null) { + EthernetSource src = new EthernetSourceBuilder(). + setAddress(sourceAddress.getMacAddress()).build(); + ematch = create(ematch).setEthernetSource(src); + } + if (destinationAddress != null) { + EthernetDestination dst = new EthernetDestinationBuilder(). + setAddress(destinationAddress.getMacAddress()).build(); + ematch = create(ematch).setEthernetDestination(dst); + } + if (etherType != null) { + EthernetType etype = new EthernetTypeBuilder(). + setType(new EtherType(NumberUtils.toLong(etherType))).build(); + ematch = create(ematch).setEthernetType(etype); + } + if (ematch != null) { + builder.setEthernetMatch(ematch.build()); + } + + VlanMatchBuilder vmatch = null; + if (vlanId != null) { + VlanIdBuilder vidBuilder = new VlanIdBuilder(); + boolean present = (vlanId.intValue() != EtherHeader.VLAN_NONE); + vidBuilder.setVlanIdPresent(present).setVlanId(new VlanId(vlanId)); + vmatch = create(vmatch).setVlanId(vidBuilder.build()); + } + if (vlanPriority != null) { + vmatch = create(vmatch).setVlanPcp(new VlanPcp(vlanPriority)); + } + if (vmatch != null) { + builder.setVlanMatch(vmatch.build()); + } + } + + /** + * Determine whether the given Ethernet header matches the condition + * configured in this instance. + * + * @param ctx A {@link FlowMatchContext} instance. + * @return {@code true} only if the given Ethernet header matches all + * the conditions configured in this instance. + */ + public boolean match(FlowMatchContext ctx) { + EtherHeader eth = ctx.getEtherHeader(); + + // Check the source MAC address. + if (sourceAddress != null) { + ctx.addMatchField(FlowMatchType.DL_SRC); + if (sourceAddress.getAddress() != + eth.getSourceAddress().getAddress()) { + return false; + } + } + + // Check the destination address. + if (destinationAddress != null) { + ctx.addMatchField(FlowMatchType.DL_DST); + if (destinationAddress.getAddress() != + eth.getDestinationAddress().getAddress()) { + return false; + } + } + + // Check the ether type. + if (etherType != null) { + ctx.addMatchField(FlowMatchType.DL_TYPE); + if (etherType.intValue() != eth.getEtherType()) { + return false; + } + } + + // Check the VLAN ID. + // We don't need to set DL_VLAN into the FlowMatchContext because + // it is mandatory. + if (vlanId != null) { + if (vlanId.intValue() != eth.getVlanId()) { + return false; + } + + // Check the VLAN priority only if a VLAN ID is specified. + if (vlanPriority != null) { + ctx.addMatchField(FlowMatchType.DL_VLAN_PCP); + if (vlanPriority.shortValue() != eth.getVlanPriority()) { + return false; + } + } + } + + return true; + } + + /** + * Store strings used to construct flow condition key. + * + * @param builder A {@link StringBuilder} instance which contains strings + * used to construct flow condition key. + */ + public void setConditionKey(StringBuilder builder) { + String sep = (builder.length() == 0) + ? "" : VTNMatch.COND_KEY_SEPARATOR; + + if (sourceAddress != null) { + builder.append(sep).append(FlowMatchType.DL_SRC).append('='). + append(sourceAddress.getText()); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (destinationAddress != null) { + builder.append(sep).append(FlowMatchType.DL_DST).append('='). + append(destinationAddress.getText()); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (etherType != null) { + builder.append(sep).append(FlowMatchType.DL_TYPE).append('='). + append(etherType); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (vlanId != null) { + builder.append(sep).append(FlowMatchType.DL_VLAN).append('='). + append(vlanId); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (vlanPriority != null) { + builder.append(sep).append(FlowMatchType.DL_VLAN_PCP).append('='). + append(vlanPriority); + } + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + public void verify() throws RpcException { + if (etherType != null) { + ProtocolUtils.checkEtherType(etherType.intValue()); + } + if (vlanId != null) { + ProtocolUtils.checkVlan(vlanId.intValue()); + } + if (vlanPriority != null) { + ProtocolUtils.checkVlanPriority(vlanPriority.shortValue()); + checkVlanPriority(); + } + } + + /** + * Determine whether this instance does not specify any Ethernet header + * field or not. + * + * @return {@code true} only if this instance is empty. + */ + public boolean isEmpty() { + if (sourceAddress != null) { + return false; + } + + if (destinationAddress != null) { + return false; + } + + if (etherType != null) { + return false; + } + + if (vlanId != null) { + return false; + } + + return (vlanPriority == null); + } + + /** + * Return the MAC address in the given {@link MacAddress} instance. + * + * @param mac A {@link MacAddress} instance. + * @param desc A brief description about the given MAC address. + * @return An {@link EtherAddress} instance. + * @throws RpcException + * The given MAC address is invalid. + */ + private EtherAddress getMacAddress(MacAddress mac, String desc) + throws RpcException { + // Exception check can be removed when RESTCONF implements the + // restriction check. + try { + return EtherAddress.create(mac); + } catch (RuntimeException e) { + String msg = MiscUtils.joinColon(mac, e.getMessage()); + RpcException re = invalidMacAddress(msg, desc); + re.initCause(e); + throw re; + } + } + + /** + * Return the MAC address in the given {@link MacAddressFilter} instance. + * + * @param mf A {@link MacAddressFilter} instance. + * @param desc A brief description about the given MAC address. + * @return An {@link EtherAddress} instance. + * @throws RpcException + * The given MAC address is invalid. + */ + private EtherAddress getMacAddress(MacAddressFilter mf, String desc) + throws RpcException { + // Exception check can be removed when RESTCONF implements the + // restriction check. + try { + return EtherAddress.create(mf); + } catch (RuntimeException e) { + String msg = MiscUtils.joinColon(mf, e.getMessage()); + RpcException re = invalidMacAddress(msg, desc); + re.initCause(e); + throw re; + } + } + + /** + * Return an {@link RpcException} instance which notifies an invalid MAC + * address. + * + * @param obj An object which contains invalid MAC address. + * @param desc A brief description about the MAC address. + * @return An {@link RpcException} instance. + */ + private RpcException invalidMacAddress(Object obj, String desc) { + StringBuilder builder = new StringBuilder("Invalid "). + append(desc).append(" MAC address: ").append(obj); + return RpcException.getBadArgumentException(builder.toString()); + } + + /** + * Initialize the condition for VLAN ID from the given MD-SAL + * VLAN ID instance. + * + * @param vid A MD-SAL VLAN ID instance. + * @throws RpcException + * The given VLAN ID condition is invalid. + */ + private void initVlanId(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanId vid) + throws RpcException { + if (vid != null) { + if (Boolean.TRUE.equals(vid.isVlanIdPresent())) { + vlanId = ProtocolUtils.getVlanId(vid.getVlanId()); + if (vlanId == null || + vlanId.intValue() == EtherHeader.VLAN_NONE) { + String msg = "Unsupported VLAN ID match: " + vid; + throw RpcException.getBadArgumentException(msg); + } + } else { + vlanId = Integer.valueOf(EtherHeader.VLAN_NONE); + } + } + } + + /** + * Verify the VLAN priority value configured in this instance. + * + * @throws RpcException This instance contains invalid value. + */ + private void checkVlanPriority() throws RpcException { + if (vlanId == null || vlanId.intValue() <= EtherHeader.VLAN_NONE) { + String msg = "VLAN priority requires a valid VLAN ID."; + throw RpcException.getBadArgumentException(msg); + } + } + + /** + * Create an {@link EthernetMatchBuilder} instance. + * + * @param ematch An {@link EthernetMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code ematch} is {@code null}, this method creates a new + * {@link EthernetMatchBuilder} instance and returns it. + * Otherwise a {@link EthernetMatchBuilder} instance passed to + * {@code ematch} is returned. + */ + private EthernetMatchBuilder create(EthernetMatchBuilder ematch) { + return (ematch == null) ? new EthernetMatchBuilder() : ematch; + } + + /** + * Create a {@link VlanMatchBuilder} instance. + * + * @param vmatch An {@link VlanMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code vmatch} is {@code null}, this method creates a new + * {@link VlanMatchBuilder} instance and returns it. + * Otherwise a {@link VlanMatchBuilder} instance passed to + * {@code vmatch} is returned. + */ + private VlanMatchBuilder create(VlanMatchBuilder vmatch) { + return (vmatch == null) ? new VlanMatchBuilder() : vmatch; + } + + // Objects + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNEtherMatch em = (VTNEtherMatch)o; + return (Objects.equals(sourceAddress, em.sourceAddress) && + Objects.equals(destinationAddress, em.destinationAddress) && + Objects.equals(etherType, em.etherType) && + Objects.equals(vlanId, em.vlanId) && + Objects.equals(vlanPriority, em.vlanPriority)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + return Objects.hash(sourceAddress, destinationAddress, etherType, + vlanId, vlanPriority); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatch.java new file mode 100644 index 00000000..8c4303f7 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatch.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; + +import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; +import org.opendaylight.vtn.manager.internal.util.packet.IcmpHeader; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnIcmpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnIcmpMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Icmpv4MatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4MatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code VTNIcmpMatch} describes the condition for ICMP header to match + * against packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-icmp-match") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNIcmpMatch extends VTNLayer4Match { + /** + * The ICMP type to match against packets. + */ + @XmlElement(name = "type") + private Short icmpType; + + /** + * The ICMP code to match against packets. + */ + @XmlElement(name = "code") + private Short icmpCode; + + /** + * Construct a new instance that matches every ICMP packet. + */ + public VTNIcmpMatch() { + } + + /** + * Create a new instance from the given {@link IcmpMatch} instance. + * + * @param imatch An {@link IcmpMatch} instance. + * @throws NullPointerException + * {@code imatch} is {@code null}. + * @throws RpcException + * {@code imatch} contains invalid value. + */ + public VTNIcmpMatch(IcmpMatch imatch) throws RpcException { + icmpType = imatch.getType(); + icmpCode = imatch.getCode(); + verify(); + } + + /** + * Create a new instance from the given {@link VtnIcmpMatchFields} + * instance. + * + * @param vimatch An {@link VtnIcmpMatchFields} instance. + * @throws NullPointerException + * {@code vimatch} is {@code null}. + * @throws RpcException + * {@code vimatch} contains invalid value. + */ + public VTNIcmpMatch(VtnIcmpMatchFields vimatch) throws RpcException { + icmpType = vimatch.getType(); + icmpCode = vimatch.getCode(); + + // Below restriction check can be removed when RESTCONF implements the + // restriction check. + verify(); + } + + /** + * Create a new instance from the given {@link Icmpv4MatchFields} instance. + * + * @param imatch An {@link Icmpv4MatchFields} instance. + * @throws NullPointerException + * {@code imatch} is {@code null}. + * @throws RpcException + * {@code imatch} contains invalid value. + */ + public VTNIcmpMatch(Icmpv4MatchFields imatch) throws RpcException { + icmpType = imatch.getIcmpv4Type(); + icmpCode = imatch.getIcmpv4Code(); + + // Below restriction check can be removed when RESTCONF implements the + // restriction check. + verify(); + } + + /** + * Return the ICMP type to match against packets. + * + * @return A {@link Short} instance which indicates the ICMP type to + * match. {@code null} if the ICMP type is not specified. + */ + public Short getIcmpType() { + return icmpType; + } + + /** + * Return the ICMP code to match against packets. + * + * @return A {@link Short} instance which indicates the ICMP code to + * match. {@code null} if the ICMP code is not specified. + */ + public Short getIcmpCode() { + return icmpCode; + } + + /** + * Create an {@link VtnIcmpMatchBuilder} instance. + * + * @param vimatch An {@link VtnIcmpMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code vimatch} is {@code null}, this method creates a new + * {@link VtnIcmpMatchBuilder} instance and returns it. + * Otherwise a {@link VtnIcmpMatchBuilder} instance passed to + * {@code vimatch} is returned. + */ + private VtnIcmpMatchBuilder create(VtnIcmpMatchBuilder vimatch) { + return (vimatch == null) ? new VtnIcmpMatchBuilder() : vimatch; + } + + /** + * Create an {@link Icmpv4MatchBuilder} instance. + * + * @param imatch An {@link Icmpv4MatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code imatch} is {@code null}, this method creates a new + * {@link Icmpv4MatchBuilder} instance and returns it. + * Otherwise a {@link Icmpv4MatchBuilder} instance passed to + * {@code imatch} is returned. + */ + private Icmpv4MatchBuilder create(Icmpv4MatchBuilder imatch) { + return (imatch == null) ? new Icmpv4MatchBuilder() : imatch; + } + + /** + * Ensure that the given IP version is supported. + * + * @param ver An {@link IpVersion} instance which describes the + * IP version. + * @throws IllegalStateException + * {@code ver} is not {@link IpVersion#Ipv4}. + */ + private void checkIpVersion(IpVersion ver) { + if (IpVersion.Ipv4 != ver) { + // This should never happen. + throw new IllegalStateException("Unsupported IP version: " + ver); + } + } + + // VTNLayer4Match + + /** + * {@inheritDoc} + */ + @Override + public void verify() throws RpcException { + ProtocolUtils.checkIcmpValue(icmpType, "type"); + ProtocolUtils.checkIcmpValue(icmpCode, "code"); + } + + /** + * Return an IP protocol number assigned to this protocol. + * + * @param ver An {@link IpVersion} instance which describes the + * IP version. + * @return An IP protocol number. + * @throws IllegalStateException + * {@code ver} is not {@link IpVersion#Ipv4}. + */ + @Override + public short getInetProtocol(IpVersion ver) { + checkIpVersion(ver); + return IPProtocols.ICMP.shortValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public IcmpMatch toL4Match() { + return new IcmpMatch(icmpType, icmpCode); + } + + /** + * {@inheritDoc} + */ + @Override + public void setVtnMatch(VtnFlowMatchBuilder builder) { + VtnIcmpMatchBuilder vimatch = null; + if (icmpType != null) { + vimatch = create(vimatch).setType(icmpType); + } + + if (icmpCode != null) { + vimatch = create(vimatch).setCode(icmpCode); + } + + if (vimatch != null) { + builder.setVtnLayer4Match(vimatch.build()); + } + } + + /** + * Configure the condition represented by this instance into the given + * MD-SAL flow match builder. + * + * @param builder A {@link MatchBuilder} instance. + * @param ver An {@link IpVersion} instance which describes the + * IP version. + * @throws IllegalStateException + * {@code ver} is not {@link IpVersion#Ipv4}. + */ + @Override + public void setMatch(MatchBuilder builder, IpVersion ver) { + checkIpVersion(ver); + Icmpv4MatchBuilder imatch = null; + if (icmpType != null) { + imatch = create(imatch).setIcmpv4Type(icmpType); + } + + if (icmpCode != null) { + imatch = create(imatch).setIcmpv4Code(icmpCode); + } + + if (imatch != null) { + builder.setIcmpv4Match(imatch.build()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean match(FlowMatchContext ctx) { + Layer4Header l4 = ctx.getLayer4Header(); + if (!(l4 instanceof IcmpHeader)) { + return false; + } + + IcmpHeader icmp = (IcmpHeader)l4; + if (icmpType != null) { + ctx.addMatchField(FlowMatchType.ICMP_TYPE); + if (icmpType.shortValue() != icmp.getIcmpType()) { + return false; + } + } + + if (icmpCode != null) { + ctx.addMatchField(FlowMatchType.ICMP_CODE); + if (icmpCode.shortValue() != icmp.getIcmpCode()) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void setConditionKey(StringBuilder builder) { + String sep = (builder.length() == 0) + ? "" : VTNMatch.COND_KEY_SEPARATOR; + + if (icmpType != null) { + builder.append(sep).append(FlowMatchType.ICMP_TYPE).append('='). + append(icmpType); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (icmpCode != null) { + builder.append(sep).append(FlowMatchType.ICMP_CODE).append('='). + append(icmpCode); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + return (icmpType == null && icmpCode == null); + } + + // Objects + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNIcmpMatch im = (VTNIcmpMatch)o; + return (Objects.equals(icmpType, im.icmpType) && + Objects.equals(icmpCode, im.icmpCode)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + return Objects.hash(icmpType, icmpCode); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4Match.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4Match.java new file mode 100644 index 00000000..8d4a93e8 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4Match.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.net.InetAddress; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.Inet4Match; +import org.opendaylight.vtn.manager.util.Ip4Network; +import org.opendaylight.vtn.manager.util.IpNetwork; +import org.opendaylight.vtn.manager.util.NumberUtils; + +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.sal.utils.EtherTypes; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnInetMatchFields; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.IpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Ipv4MatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; + +/** + * {@code VTNInet4Match} describes the condition for IPv4 header to match + * against packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-inet4-match") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNInet4Match extends VTNInetMatch { + /** + * Construct a new instance that matches every IPv4 packet. + */ + public VTNInet4Match() { + } + + /** + * Construct a new instance that matches the given IP protocol. + * + * @param proto A {@link Short} instance which represents the IP protocol + * number to match against packets. + * {@code null} matches every IP protocol. + */ + public VTNInet4Match(Short proto) { + super(proto); + } + + /** + * Construct a new instance from the given {@link Inet4Match} instance. + * + * @param imatch An {@link Inet4Match} instance. + * @throws NullPointerException + * {@code imatch} is {@code null}. + * @throws RpcException + * {@code imatch} contains invalid value. + */ + public VTNInet4Match(Inet4Match imatch) throws RpcException { + super(imatch); + } + + /** + * Construct a new instance from the given {@link VtnInetMatchFields} + * instance. + * + * @param vimatch A {@link VtnInetMatchFields} instance. + * @throws NullPointerException + * {@code vimatch} is {@code null}. + * @throws RpcException + * {@code vimatch} contains invalid value. + */ + public VTNInet4Match(VtnInetMatchFields vimatch) throws RpcException { + super(vimatch); + } + + /** + * Construct a new instance from the given {@link IpMatchFields} and + * {@link Ipv4MatchFields} instances. + * + * @param imatch An {@link IpMatchFields} instance. + * @param i4match An {@link Ipv4MatchFields} instance. + * @throws RpcException + * {@code imatch} or {@code i4match} contains invalid value. + */ + public VTNInet4Match(IpMatchFields imatch, Ipv4MatchFields i4match) + throws RpcException { + super(imatch); + + if (i4match != null) { + Ip4Network ipn4 = getIp4Network(i4match.getIpv4Source(), + VTNMatch.DESC_SRC); + setSourceNetwork(ipn4); + ipn4 = getIp4Network(i4match.getIpv4Destination(), + VTNMatch.DESC_DST); + setDestinationNetwork(ipn4); + } + } + + /** + * Construct a new {@link Ip4Network} instance which represents the IPv4 + * network specified by the given {@link Ipv4Prefix} instance. + * + * @param ipp4 An {@link Ipv4Prefix} instance. + * @param desc A brief description about the specified IP network. + * @return An {@link Ip4Network} instance or {@code null}. + * @throws RpcException + * The given parameter is invalid. + */ + private Ip4Network getIp4Network(Ipv4Prefix ipp4, String desc) + throws RpcException { + if (ipp4 == null) { + return null; + } + String value = ipp4.getValue(); + if (value == null) { + return null; + } + + try { + return new Ip4Network(value); + } catch (RuntimeException e) { + String msg = MiscUtils.joinColon(ipp4, e.getMessage()); + RpcException re = invalidInetAddress(msg, desc); + re.initCause(e); + throw re; + } + } + + /** + * Create an {@link Ipv4MatchBuilder} instance. + * + * @param imatch An {@link Ipv4MatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code imatch} is {@code null}, this method creates a new + * {@link Ipv4MatchBuilder} instance and returns it. + * Otherwise a {@link Ipv4MatchBuilder} instance passed to + * {@code imatch} is returned. + */ + private Ipv4MatchBuilder create(Ipv4MatchBuilder imatch) { + return (imatch == null) ? new Ipv4MatchBuilder() : imatch; + } + + // VTNInetMatch + + /** + * {@inheritDoc} + */ + @Override + public void setMatch(MatchBuilder builder) { + super.setMatch(builder); + + Ipv4MatchBuilder imatch = null; + IpNetwork ipn = getSourceNetwork(); + if (ipn != null) { + IpPrefix ipp = ipn.getIpPrefix(); + imatch = create(imatch).setIpv4Source(ipp.getIpv4Prefix()); + } + + ipn = getDestinationNetwork(); + if (ipn != null) { + IpPrefix ipp = ipn.getIpPrefix(); + imatch = create(imatch).setIpv4Destination(ipp.getIpv4Prefix()); + } + + if (imatch != null) { + builder.setLayer3Match(imatch.build()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getEtherType() { + return EtherTypes.IPv4.intValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public Class getIpNetworkType() { + return Ip4Network.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Inet4Match toInetMatch() { + InetAddress srcAddr; + Short srcSuff; + IpNetwork ipn = getSourceNetwork(); + if (ipn == null) { + srcAddr = null; + srcSuff = null; + } else { + srcAddr = ipn.getInetAddress(); + srcSuff = (ipn.isAddress()) + ? null + : Short.valueOf((short)ipn.getPrefixLength()); + } + + InetAddress dstAddr; + Short dstSuff; + ipn = getDestinationNetwork(); + if (ipn == null) { + dstAddr = null; + dstSuff = null; + } else { + dstAddr = ipn.getInetAddress(); + dstSuff = (ipn.isAddress()) + ? null + : Short.valueOf((short)ipn.getPrefixLength()); + } + + Short proto = getProtocol(); + Byte d = NumberUtils.toByte(getDscp()); + return new Inet4Match(srcAddr, srcSuff, dstAddr, dstSuff, proto, d); + } + + /** + * Return An {@link IpVersion} instance which describes the IP version. + * + * @return {@link IpVersion#Ipv4}. + */ + public IpVersion getIpVersion() { + return IpVersion.Ipv4; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInetMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInetMatch.java new file mode 100644 index 00000000..958617bc --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInetMatch.java @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.net.InetAddress; +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSeeAlso; + +import org.opendaylight.vtn.manager.flow.cond.Inet4Match; +import org.opendaylight.vtn.manager.flow.cond.InetMatch; +import org.opendaylight.vtn.manager.util.Ip4Network; +import org.opendaylight.vtn.manager.util.IpNetwork; +import org.opendaylight.vtn.manager.util.NumberUtils; + +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.sal.utils.Status; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnInetMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.IpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Ipv4MatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code VTNInetMatch} describes the condition for IP header to match against + * packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-inet-match") +@XmlAccessorType(XmlAccessType.NONE) +@XmlSeeAlso(VTNInet4Match.class) +public abstract class VTNInetMatch { + /** + * The source IP network to match. + */ + @XmlElements({ + @XmlElement(name = "source-network-v4", type = Ip4Network.class) + }) + private IpNetwork sourceNetwork; + + /** + * The destination IP network to match. + */ + @XmlElements({ + @XmlElement(name = "destination-network-v4", type = Ip4Network.class) + }) + private IpNetwork destinationNetwork; + + /** + * An IP protocol number to match. + */ + @XmlElement + private Short protocol; + + /** + * A DSCP field value to match. + */ + @XmlElement + private Short dscp; + + /** + * Construct a new instance from the given {@link InetMatch} instance. + * + * @param imatch An {@link InetMatch} instance. + * @return A {@link VTNInetMatch} instance which represents the given + * {@link InetMatch} instance. Note that {@code null} is returned + * if {@code imatch} is {@code null}. + * @throws RpcException + * An invalid instance is specified to {@code imatch}. + */ + public static final VTNInetMatch create(InetMatch imatch) + throws RpcException { + if (imatch == null) { + return null; + } + if (imatch instanceof Inet4Match) { + return new VTNInet4Match((Inet4Match)imatch); + } + + // This should never hanppen. + String msg = "Unexpected inet match instance: " + imatch; + throw RpcException.getBadArgumentException(msg); + } + + /** + * Construct a new instance from the given pair of {@link VTNEtherMatch} + * and {@link VtnInetMatch} instances. + * + * @param eth A {@link VTNEtherMatch} instance. + * @param ip A {@link VtnInetMatch} instance. + * @return A {@link VTNInetMatch} instance or {@code null}. + * @throws RpcException + * The given condition is invalid. + */ + public static final VTNInetMatch create(VTNEtherMatch eth, VtnInetMatch ip) + throws RpcException { + // Currently only IPv4 is supported. + return (ip == null) ? null : new VTNInet4Match(ip); + } + + /** + * Create a new instance from the given MD-SAL flow match. + * + * @param match A MD-SAL flow match. + * @return A {@link VTNInetMatch} instance or {@code null}. + * @throws NullPointerException + * {@code match} is {@code null}. + * @throws RpcException + * {@code match} contains invalid condition against IP header. + */ + public static VTNInetMatch create(Match match) throws RpcException { + IpMatchFields ip = match.getIpMatch(); + Layer3Match l3 = match.getLayer3Match(); + if (l3 == null) { + if (ip == null) { + return null; + } + } else if (!(l3 instanceof Ipv4MatchFields)) { + String msg = "Unsupported layer 3 match: " + l3; + throw RpcException.getBadArgumentException(msg); + } + + return new VTNInet4Match(ip, (Ipv4MatchFields)l3); + } + + /** + * Construct a new instance that matches every IP packet. + */ + VTNInetMatch() { + } + + /** + * Construct a new instance that matches the given IP protocol. + * + * @param proto A {@link Short} instance which represents the IP protocol + * number to match against packets. + * {@code null} matches every IP protocol. + */ + VTNInetMatch(Short proto) { + protocol = proto; + } + + /** + * Construct a new instance from the given {@link InetMatch} instance. + * + * @param imatch An {@link InetMatch} instance. + * @throws NullPointerException + * {@code imatch} is {@code null}. + * @throws RpcException + * {@code imatch} contains invalid value. + */ + VTNInetMatch(InetMatch imatch) throws RpcException { + Status st = imatch.getValidationStatus(); + if (st != null) { + throw new RpcException(RpcErrorTag.BAD_ELEMENT, st); + } + + Class itype = getIpNetworkType(); + sourceNetwork = getIpNetwork(itype, imatch.getSourceAddress(), + imatch.getSourceSuffix(), + VTNMatch.DESC_SRC); + destinationNetwork = getIpNetwork( + itype, imatch.getDestinationAddress(), + imatch.getDestinationSuffix(), VTNMatch.DESC_DST); + protocol = imatch.getProtocol(); + dscp = NumberUtils.toShort(imatch.getDscp()); + verify(); + } + + /** + * Construct a new instance from the given {@link VtnInetMatchFields} + * instance. + * + * @param vimatch A {@link VtnInetMatchFields} instance. + * @throws NullPointerException + * {@code vimatch} is {@code null}. + * @throws RpcException + * {@code vimatch} contains invalid value. + */ + VTNInetMatch(VtnInetMatchFields vimatch) throws RpcException { + Class itype = getIpNetworkType(); + sourceNetwork = getIpNetwork(itype, vimatch.getSourceNetwork(), + VTNMatch.DESC_SRC); + destinationNetwork = getIpNetwork( + itype, vimatch.getDestinationNetwork(), VTNMatch.DESC_DST); + + // Below restriction check can be removed when RESTCONF implements the + // restriction check. + protocol = vimatch.getProtocol(); + if (protocol != null) { + ProtocolUtils.checkIpProtocol(protocol.shortValue()); + } + + dscp = ProtocolUtils.getIpDscp(vimatch.getDscp()); + } + + /** + * Construct a new instance from the given {@link IpMatchFields} instance. + * + * @param imatch An {@link IpMatchFields} instance. + * @throws RpcException + * {@code imatch} contains invalid value. + */ + VTNInetMatch(IpMatchFields imatch) throws RpcException { + if (imatch != null) { + // Below restriction check can be removed when RESTCONF implements + // the restriction check. + protocol = imatch.getIpProtocol(); + if (protocol != null) { + ProtocolUtils.checkIpProtocol(protocol.shortValue()); + } + dscp = ProtocolUtils.getIpDscp(imatch.getIpDscp()); + } + } + + /** + * Return the source IP network to match against packets. + * + * @return An {@link IpNetwork} instance if the source IP network is + * specified. {@code null} if not specified. + */ + public final IpNetwork getSourceNetwork() { + return sourceNetwork; + } + + /** + * Return the destination IP network to match against packets. + * + * @return An {@link IpNetwork} instance if the destination IP network is + * specified. {@code null} if not specified. + */ + public final IpNetwork getDestinationNetwork() { + return destinationNetwork; + } + + /** + * Return the IP protocol number to match against packets. + * + * @return A {@link Short} instance if the IP protocol number is + * specified. {@code null} if not specified. + */ + public final Short getProtocol() { + return protocol; + } + + /** + * Set the IP protocol number to match against packets. + * + * @param proto A {@link Short} instance which represents the IP protocol + * number to match against packets. + * {@code null} matches every IP protocol. + * @throws RpcException + * The IP protocol number different from the given number is already + * configured in this instance. + */ + public final void setProtocol(Short proto) throws RpcException { + if (protocol != null && !protocol.equals(proto)) { + String msg = new StringBuilder("IP protocol conflict: proto="). + append(protocol).append(", expected=").append(proto). + toString(); + throw RpcException.getBadArgumentException(msg); + } + protocol = proto; + } + + /** + * Return the IP DSCP field value to match against packets. + * + * @return A {@link Short} instance if the IP DSCP value is specified. + * {@code null} if not specified. + */ + public final Short getDscp() { + return dscp; + } + + /** + * Return a {@link VtnInetMatchBuilder} instance which contains the flow + * condition configured in this instance. + * + * @return A {@link VtnInetMatchBuilder} instance. + */ + public final VtnInetMatchBuilder toVtnInetMatchBuilder() { + VtnInetMatchBuilder builder = new VtnInetMatchBuilder(); + if (sourceNetwork != null) { + builder.setSourceNetwork(sourceNetwork.getIpPrefix()); + } + if (destinationNetwork != null) { + builder.setDestinationNetwork(destinationNetwork.getIpPrefix()); + } + if (dscp != null) { + builder.setDscp(new Dscp(dscp)); + } + + return builder.setProtocol(protocol); + } + + /** + * Configure the condition represented by this instance into the given + * MD-SAL flow match builder. + * + * @param builder A {@link MatchBuilder} instance. + */ + public void setMatch(MatchBuilder builder) { + IpMatchBuilder imatch = null; + if (protocol != null) { + imatch = create(imatch).setIpProtocol(protocol); + } + if (dscp != null) { + imatch = create(imatch).setIpDscp(new Dscp(dscp)); + } + + if (imatch != null) { + builder.setIpMatch(imatch.build()); + } + } + + /** + * Determine whether the given IP header matches the condition configured + * in this instance. + * + *

+ * The caller has to guarantee that the IP protocol version of the + * IP header matches this instance. + *

+ * + * @param ctx A {@link FlowMatchContext} instance. + * @return {@code true} only if the given packet header matches all + * the conditions configured in this instance. + */ + public final boolean match(FlowMatchContext ctx) { + InetHeader iph = ctx.getInetHeader(); + if (iph == null) { + return false; + } + + // Check the source IP address. + if (sourceNetwork != null) { + ctx.addMatchField(FlowMatchType.IP_SRC); + if (!sourceNetwork.contains(iph.getSourceAddress())) { + return false; + } + } + + // Check the destination IP address. + if (destinationNetwork != null) { + ctx.addMatchField(FlowMatchType.IP_DST); + if (!destinationNetwork.contains(iph.getDestinationAddress())) { + return false; + } + } + + // Check the IP protocol number. + if (protocol != null) { + ctx.addMatchField(FlowMatchType.IP_PROTO); + if (protocol.shortValue() != iph.getProtocol()) { + return false; + } + } + + // Check the IP DSCP value. + if (dscp != null) { + ctx.addMatchField(FlowMatchType.IP_DSCP); + if (dscp.shortValue() != iph.getDscp()) { + return false; + } + } + + return true; + } + + /** + * Store strings used to construct flow condition key. + * + * @param builder A {@link StringBuilder} instance which contains strings + * used to construct flow condition key. + */ + public final void setConditionKey(StringBuilder builder) { + String sep = (builder.length() == 0) + ? "" : VTNMatch.COND_KEY_SEPARATOR; + + if (sourceNetwork != null) { + builder.append(sep).append(FlowMatchType.IP_SRC).append('='). + append(sourceNetwork.getText()); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (destinationNetwork != null) { + builder.append(sep).append(FlowMatchType.IP_DST).append('='). + append(destinationNetwork.getText()); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (protocol != null) { + builder.append(sep).append(FlowMatchType.IP_PROTO).append('='). + append(protocol); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (dscp != null) { + builder.append(sep).append(FlowMatchType.IP_DSCP).append('='). + append(dscp); + } + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + public void verify() throws RpcException { + if (protocol != null) { + ProtocolUtils.checkIpProtocol(protocol.shortValue()); + } + if (dscp != null) { + ProtocolUtils.checkIpDscp(dscp.shortValue()); + } + } + + /** + * Determine whether this instance does not specify any IP header field + * or not. + * + * @return {@code true} only if this instance is empty. + */ + public final boolean isEmpty() { + return (sourceNetwork == null && destinationNetwork == null && + protocol == null && dscp == null); + } + + /** + * Set the source IP network to match against packets. + * + * @param ipn An {@link IpNetwork} instance which represents the source + * IP network to match against packets. + * {@code null} matches every source IP address. + * @throws IllegalArgumentException + * The given IP network does not match the IP protocol version. + */ + final void setSourceNetwork(IpNetwork ipn) { + checkIpNetwork(ipn); + sourceNetwork = ipn; + } + + /** + * Set the destination IP network to match against packets. + * + * @param ipn An {@link IpNetwork} instance which represents the + * destination IP network to match against packets. + * {@code null} matches every destination IP address. + * @throws IllegalArgumentException + * The given IP network does not match the IP protocol version. + */ + final void setDestinationNetwork(IpNetwork ipn) { + checkIpNetwork(ipn); + destinationNetwork = ipn; + } + + /** + * Return an {@link RpcException} instance which notifies an invalid + * IP address or CIDR prefix length. + * + * @param obj An object which contains invalid value. + * @param desc A brief description about the IP address. + * @return An {@link RpcException} instance. + */ + final RpcException invalidInetAddress(Object obj, String desc) { + StringBuilder builder = new StringBuilder("Invalid "). + append(desc).append(" IP address: ").append(obj); + return RpcException.getBadArgumentException(builder.toString()); + } + + /** + * Construct a new {@link IpNetwork} instance which represents the IP + * network specified by a pair of IP address and CIDR prefix length. + * + * @param type A class which specifies the type of {@link IpNetwork} + * instance. + * @param iaddr An {@link InetAddress} instance. + * @param length CIDR prefix length. + * @param desc A brief description about the specified IP network. + * @return An {@link IpNetwork} instance or {@code null}. + * @throws RpcException + * The given parameter is invalid. + */ + private IpNetwork getIpNetwork(Class type, + InetAddress iaddr, Short length, + String desc) throws RpcException { + int prefix = 0; + boolean zero = false; + try { + if (length != null) { + prefix = length.intValue(); + zero = (prefix == 0); + } + + IpNetwork ipn = IpNetwork.create(iaddr, prefix); + if (ipn != null) { + if (!type.isInstance(ipn)) { + throw new IllegalArgumentException( + "Unexpected IP address type"); + } + if (zero) { + // Reject zero prefix length to keep backward + // compatibility. + throw new IllegalArgumentException( + "Invalid prefix length: " + prefix); + } + } + + return ipn; + } catch (RuntimeException e) { + // iaddr should be a non-null value. + String msg = new StringBuilder(iaddr.getHostAddress()). + append(IpNetwork.CIDR_SEPARATOR).append(prefix).append(": "). + append(e.getMessage()).toString(); + RpcException re = invalidInetAddress(msg, desc); + re.initCause(e); + throw re; + } + } + + /** + * Construct a new {@link IpNetwork} instance which represents the IP + * network specified by the given {@link IpPrefix} instance. + * + * @param type A class which specifies the type of {@link IpNetwork} + * instance. + * @param ipp An {@link IpPrefix} instance. + * @param desc A brief description about the specified IP network. + * @return An {@link IpNetwork} instance or {@code null}. + * @throws RpcException + * The given parameter is invalid. + */ + private IpNetwork getIpNetwork(Class type, + IpPrefix ipp, String desc) + throws RpcException { + try { + IpNetwork ipn = IpNetwork.create(ipp); + if (ipn != null && !type.isInstance(ipn)) { + throw new IllegalArgumentException( + "Unexpected IP prefix type"); + } + + return ipn; + } catch (RuntimeException e) { + String msg = MiscUtils.joinColon(ipp, e.getMessage()); + RpcException re = invalidInetAddress(msg, desc); + re.initCause(e); + throw re; + } + } + + /** + * Verify that the given {@link IpNetwork} instance matches the IP protocol + * version corresponding to this instance. + * + * @param ipn An {@link IpNetwork} instance. + * @throws IllegalArgumentException + * Unexpected type of IP network is specified. + */ + private void checkIpNetwork(IpNetwork ipn) { + if (ipn != null && !getIpNetworkType().isInstance(ipn)) { + throw new IllegalArgumentException( + "Unexpected IP network type: " + ipn); + } + } + + /** + * Create an {@link IpMatchBuilder} instance. + * + * @param imatch An {@link IpMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code imatch} is {@code null}, this method creates a new + * {@link IpMatchBuilder} instance and returns it. + * Otherwise a {@link IpMatchBuilder} instance passed to + * {@code imatch} is returned. + */ + private IpMatchBuilder create(IpMatchBuilder imatch) { + return (imatch == null) ? new IpMatchBuilder() : imatch; + } + + /** + * Return an Ethernet type assigned to this IP protocol version. + * + * @return An Ethernet type. + */ + public abstract int getEtherType(); + + /** + * Return a class to represent an IP address. + * + * @return A class to represent an IP address. + */ + public abstract Class getIpNetworkType(); + + /** + * Return an {@link InetMatch} instance which represents this condition. + * + * @return An {@link InetMatch} instance. + */ + public abstract InetMatch toInetMatch(); + + /** + * Return An {@link IpVersion} instance which describes the IP version. + * + * @return An {@link IpVersion} instance. + */ + public abstract IpVersion getIpVersion(); + + // Objects + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public final boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNInetMatch im = (VTNInetMatch)o; + return (Objects.equals(sourceNetwork, im.sourceNetwork) && + Objects.equals(destinationNetwork, im.destinationNetwork) && + Objects.equals(protocol, im.protocol) && + Objects.equals(dscp, im.dscp)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public final int hashCode() { + return Objects.hash(getClass().getName(), sourceNetwork, + destinationNetwork, protocol, dscp); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4Match.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4Match.java new file mode 100644 index 00000000..957f65f5 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4Match.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSeeAlso; + +import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; +import org.opendaylight.vtn.manager.flow.cond.L4Match; +import org.opendaylight.vtn.manager.flow.cond.TcpMatch; +import org.opendaylight.vtn.manager.flow.cond.UdpMatch; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnIcmpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnTcpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnUdpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Icmpv4MatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code VTNLayer4Match} describes the condition for layer 4 protocol header + * to match against packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-layer4-match") +@XmlAccessorType(XmlAccessType.NONE) +@XmlSeeAlso({VTNTcpMatch.class, VTNUdpMatch.class, VTNIcmpMatch.class}) +public abstract class VTNLayer4Match { + /** + * Create a new instance from the given {@link L4Match} instance. + * + * @param l4 A {@link L4Match} instance. + * @return A {@link VTNLayer4Match} instance created from the given + * {@link L4Match} instance. Note that {@code null} is returned + * if {@code l4} is {@code null}. + * @throws RpcException + * The given {@link L4Match} instance is invalid. + */ + public static final VTNLayer4Match create(L4Match l4) throws RpcException { + if (l4 == null) { + return null; + } + if (l4 instanceof TcpMatch) { + return new VTNTcpMatch((TcpMatch)l4); + } + if (l4 instanceof UdpMatch) { + return new VTNUdpMatch((UdpMatch)l4); + } + if (l4 instanceof IcmpMatch) { + return new VTNIcmpMatch((IcmpMatch)l4); + } + + // This should never hanppen. + String msg = "Unexpected L4 match instance: " + l4; + throw RpcException.getBadArgumentException(msg); + } + + /** + * Create a new instance from the given {@link VtnLayer4Match} instance. + * + * @param vl4 A {@link VtnLayer4Match} instance. + * @return A {@link VTNLayer4Match} instance created from the given + * {@link VtnLayer4Match} instance. Note that {@code null} is + * returned if {@code vl4} is {@code null}. + * @throws RpcException + * The given {@link VtnLayer4Match} instance is invalid. + */ + public static final VTNLayer4Match create(VtnLayer4Match vl4) + throws RpcException { + if (vl4 == null) { + return null; + } + if (vl4 instanceof VtnTcpMatchFields) { + return new VTNTcpMatch((VtnTcpMatchFields)vl4); + } + if (vl4 instanceof VtnUdpMatchFields) { + return new VTNUdpMatch((VtnUdpMatchFields)vl4); + } + if (vl4 instanceof VtnIcmpMatchFields) { + return new VTNIcmpMatch((VtnIcmpMatchFields)vl4); + } + + // This should never hanppen. + String msg = "Unexpected VTN L4 match instance: " + vl4; + throw RpcException.getBadArgumentException(msg); + } + + /** + * Create a new instance from the given MD-SAL flow match. + * + * @param match A MD-SAL flow match. + * @return A {@link VTNLayer4Match} instance or {@code null}. + * @throws NullPointerException + * {@code match} is {@code null}. + * @throws RpcException + * {@code match} contains invalid condition against layer 4 protocol + * header. + */ + public static final VTNLayer4Match create(Match match) + throws RpcException { + Icmpv4MatchFields icmpv4 = match.getIcmpv4Match(); + if (icmpv4 != null) { + return new VTNIcmpMatch(icmpv4); + } + + Layer4Match l4 = match.getLayer4Match(); + if (l4 == null) { + return null; + } + if (l4 instanceof TcpMatchFields) { + return new VTNTcpMatch((TcpMatchFields)l4); + } + if (l4 instanceof UdpMatchFields) { + return new VTNUdpMatch((UdpMatchFields)l4); + } + + // This should never hanppen. + String msg = "Unsupported MD-SAL L4 match instance: " + l4; + throw RpcException.getBadArgumentException(msg); + } + + /** + * Construct a new instance that matches every layer 4 packet. + */ + VTNLayer4Match() { + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + public abstract void verify() throws RpcException; + + /** + * Return an IP protocol number assigned to this protocol. + * + * @param ver An {@link IpVersion} instance which describes the + * IP version. + * @return An IP protocol number. + * @throws IllegalStateException + * This layer 4 protocol is unavailable on the given IP version. + */ + public abstract short getInetProtocol(IpVersion ver); + + /** + * Return a {@link L4Match} instance which represents this condition. + * + * @return A {@link L4Match} instance. + */ + public abstract L4Match toL4Match(); + + /** + * Configure the condition represented by this instance into the given + * VTN flow match builder. + * + * @param builder A {@link VtnFlowMatchBuilder} instance. + */ + public abstract void setVtnMatch(VtnFlowMatchBuilder builder); + + /** + * Configure the condition represented by this instance into the given + * MD-SAL flow match builder. + * + * @param builder A {@link MatchBuilder} instance. + * @param ver An {@link IpVersion} instance which describes the + * IP version. + */ + public abstract void setMatch(MatchBuilder builder, IpVersion ver); + + /** + * Determine whether the given layer 4 protocol header matches the + * condition configured in this instance. + * + * @param ctx A {@link FlowMatchContext} instance. + * @return {@code true} only if the given header matches all the + * conditions configured in this instance. + */ + public abstract boolean match(FlowMatchContext ctx); + + /** + * Store strings used to construct flow condition key. + * + * @param builder A {@link StringBuilder} instance which contains strings + * used to construct flow condition key. + */ + public abstract void setConditionKey(StringBuilder builder); + + /** + * Determine whether this instance does not specify any header field + * or not. + * + * @return {@code true} only if this instance is empty. + */ + public abstract boolean isEmpty(); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4PortMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4PortMatch.java new file mode 100644 index 00000000..efece6c8 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNLayer4PortMatch.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSeeAlso; + +import org.opendaylight.vtn.manager.flow.cond.PortProtoMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4PortHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnPortRange; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; + +/** + * {@code VTNLayer4PortMatch} describes the condition for IP port numbers + * to match against packets. + * + *

+ * Note that this class is not synchronized. + *

+ * + * @param The type of packet header. + */ +@XmlRootElement(name = "vtn-layer4-port-match") +@XmlAccessorType(XmlAccessType.NONE) +@XmlSeeAlso({VTNTcpMatch.class, VTNUdpMatch.class}) +public abstract class VTNLayer4PortMatch + extends VTNLayer4Match { + /** + * The range of the source port number to match against packets. + */ + @XmlElement(name = "source-port") + private VTNPortRange sourcePort; + + /** + * The range of the destination port number to match against packets. + */ + @XmlElement(name = "destination-port") + private VTNPortRange destinationPort; + + /** + * Construct a new instance. + */ + VTNLayer4PortMatch() { + } + + /** + * Construct a new instance from the given {@link PortProtoMatch} instance. + * + * @param pmatch A {@link PortProtoMatch} instance. + * @throws NullPointerException + * {@code pmatch} is {@code null}. + * @throws RpcException + * {@code pmatch} contains invalid value. + */ + VTNLayer4PortMatch(PortProtoMatch pmatch) + throws RpcException { + sourcePort = VTNPortRange.create(pmatch.getSourcePort()); + destinationPort = VTNPortRange.create(pmatch.getDestinationPort()); + } + + /** + * Construct a new instance from the given pair of {@link VtnPortRange} + * instances. + * + * @param src A {@link VtnPortRange} instance which specifies the range + * of source port number. + * @param dst A {@link VtnPortRange} instance which specifies the range + * of destination port number. + * @throws RpcException + * {@code src} or {@code dst} contains invalid value. + */ + VTNLayer4PortMatch(VtnPortRange src, VtnPortRange dst) + throws RpcException { + sourcePort = VTNPortRange.create(src); + destinationPort = VTNPortRange.create(dst); + } + + /** + * Construct a new instance from the given pair of {@link PortNumber} + * instances. + * + * @param src A {@link PortNumber} instance which specifies the source + * port number. + * @param dst A {@link VtnPortRange} instance which specifies the + * destination port number. + * @throws RpcException + * {@code src} or {@code dst} contains invalid value. + */ + VTNLayer4PortMatch(PortNumber src, PortNumber dst) + throws RpcException { + sourcePort = VTNPortRange.create(src); + destinationPort = VTNPortRange.create(dst); + } + + /** + * Return the range of the source port number to match against packet. + * + * @return A {@link VTNPortRange} instance if the range of the source + * port number is specified. {@code null} if not specified. + */ + public final VTNPortRange getSourcePort() { + return sourcePort; + } + + /** + * Return the range of the destination port number to match against packet. + * + * @return A {@link VTNPortRange} instance if the range of the destination + * port number is specified. {@code null} if not specified. + */ + public final VTNPortRange getDestinationPort() { + return destinationPort; + } + + /** + * Return a class which represents the packet header type. + * + * @return A class associated with the packet header type. + */ + public abstract Class getHeaderType(); + + /** + * Return a flow match type corresponding to the source port. + * + * @return A {@link FlowMatchType} instance. + */ + public abstract FlowMatchType getSourceMatchType(); + + /** + * Return a flow match type corresponding to the destination port. + * + * @return A {@link FlowMatchType} instance. + */ + public abstract FlowMatchType getDestinationMatchType(); + + // VTNLayer4Match + + /** + * {@inheritDoc} + */ + @Override + public final void verify() throws RpcException { + if (sourcePort != null) { + sourcePort.verify(); + } + if (destinationPort != null) { + destinationPort.verify(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean match(FlowMatchContext ctx) { + Class type = getHeaderType(); + Layer4Header l4 = ctx.getLayer4Header(); + if (!type.isInstance(l4)) { + return false; + } + + H l4head = type.cast(l4); + if (sourcePort != null) { + ctx.addMatchField(getSourceMatchType()); + int port = l4head.getSourcePort(); + if (!sourcePort.match(port)) { + return false; + } + } + + if (destinationPort != null) { + ctx.addMatchField(getDestinationMatchType()); + int port = l4head.getDestinationPort(); + if (!destinationPort.match(port)) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public final void setConditionKey(StringBuilder builder) { + String sep = (builder.length() == 0) + ? "" : VTNMatch.COND_KEY_SEPARATOR; + + if (sourcePort != null) { + builder.append(sep).append(getSourceMatchType()).append('='); + sourcePort.setConditionKey(builder); + sep = VTNMatch.COND_KEY_SEPARATOR; + } + + if (destinationPort != null) { + builder.append(sep).append(getDestinationMatchType()).append('='); + destinationPort.setConditionKey(builder); + } + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isEmpty() { + return (sourcePort == null && destinationPort == null); + } + + // Objects + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public final boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNLayer4PortMatch l4 = (VTNLayer4PortMatch)o; + return (Objects.equals(sourcePort, l4.sourcePort) && + Objects.equals(destinationPort, l4.destinationPort)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public final int hashCode() { + return Objects.hash(getClass().getName(), sourcePort, destinationPort); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatch.java new file mode 100644 index 00000000..360f305c --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatch.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.flow.cond.InetMatch; +import org.opendaylight.vtn.manager.flow.cond.L4Match; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code VTNMatch} describes the condition to match against packtes. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-match") +@XmlAccessorType(XmlAccessType.NONE) +public class VTNMatch { + /** + * A separator used to construct flow condition key. + */ + public static final String COND_KEY_SEPARATOR = ","; + + /** + * A brief description about the source address. + */ + static final String DESC_SRC = "source"; + + /** + * A brief description about the destination address. + */ + static final String DESC_DST = "destination"; + + /** + * Conditions against Ethernet header. + */ + @XmlElement(name = "vtn-ether-match") + private VTNEtherMatch etherMatch; + + /** + * Conditions against IP header. + */ + @XmlElements({ + @XmlElement(name = "vtn-inet4-match", type = VTNInet4Match.class) + }) + private VTNInetMatch inetMatch; + + /** + * Conditions against layer 4 protocol header. + */ + @XmlElements({ + @XmlElement(name = "vtn-tcp-match", type = VTNTcpMatch.class), + @XmlElement(name = "vtn-udp-match", type = VTNUdpMatch.class), + @XmlElement(name = "vtn-icmp-match", type = VTNIcmpMatch.class), + }) + private VTNLayer4Match layer4Match; + + /** + * Create a new flow match that matches every packet. + */ + public VTNMatch() { + } + + /** + * Construct a new flow match from the given {@link Match} instance. + * + *

+ * Note that this constructor does not complete the condition specified + * by the given {@link Match} instance. + *

+ * + * @param match A {@link Match} instance. + * @throws RpcException + * {@code match} contains invalid value. + */ + public VTNMatch(Match match) throws RpcException { + if (match != null) { + etherMatch = VTNEtherMatch.create(match); + inetMatch = VTNInetMatch.create(match); + layer4Match = VTNLayer4Match.create(match); + } + } + + /** + * Set flow conditions configured in the given {@link FlowMatch} instance. + * + *

+ * This method completes the condition specified by the given + * {@link FlowMatch} instance. For instance, ethernet type is added + * if IP condition is configured in the given {@link FlowMatch} instance. + *

+ * + * @param fmatch A {@link FlowMatch} instance. + * @throws NullPointerException + * {@code fmatch} is {@code null}. + * @throws RpcException + * {@code fmatch} contains invalid value. + */ + public final void set(FlowMatch fmatch) throws RpcException { + EthernetMatch eth = fmatch.getEthernetMatch(); + InetMatch inet = fmatch.getInetMatch(); + L4Match l4 = fmatch.getLayer4Match(); + + etherMatch = (eth == null) ? null : new VTNEtherMatch(eth); + inetMatch = VTNInetMatch.create(inet); + layer4Match = VTNLayer4Match.create(l4); + complete(); + } + + /** + * Set flow conditions configured in the given {@link VtnMatchFields} + * instance. + * + *

+ * This method completes the condition specified by the given + * {@link VtnMatchFields} instance. For instance, ethernet type is added + * if IP condition is configured in the given {@link VtnMatchFields} + * instance. + *

+ * + * @param vmatch A {@link VtnMatchFields} instance. + * @throws NullPointerException + * {@code vmatch} is {@code null}. + * @throws RpcException + * {@code fmatch} contains invalid value. + */ + public final void set(VtnMatchFields vmatch) throws RpcException { + VtnEtherMatch eth = vmatch.getVtnEtherMatch(); + VtnInetMatch ip = vmatch.getVtnInetMatch(); + VtnLayer4Match l4 = vmatch.getVtnLayer4Match(); + + etherMatch = (eth == null) ? null : new VTNEtherMatch(eth); + inetMatch = VTNInetMatch.create(etherMatch, ip); + layer4Match = VTNLayer4Match.create(l4); + complete(); + } + + /** + * Return the condition against Ethernet header. + * + * @return A {@link VTNEtherMatch} instance. + * {@code null} if no condition is specified. + */ + public final VTNEtherMatch getEtherMatch() { + return etherMatch; + } + + /** + * Return the condition against IP header. + * + * @return A {@link VTNInetMatch} instance. + * {@code null} if no condition is specified. + */ + public final VTNInetMatch getInetMatch() { + return inetMatch; + } + + /** + * Return the condition against layer 4 protocol header. + * + * @return A {@link VTNLayer4Match} instance. + * {@code null} if no condition is specified. + */ + public final VTNLayer4Match getLayer4Match() { + return layer4Match; + } + + /** + * Return a {@link FlowMatch} instance which represents this condition. + * + * @return A {@link FlowMatch} instance. + */ + public FlowMatch toFlowMatch() { + return toFlowMatch(null); + } + + /** + * Return a {@link FlowMatch} instance which represents this condition. + * + * @param index A index to be assigned to {@code FlowMatch}. + * @return A {@link FlowMatch} instance. + */ + public final FlowMatch toFlowMatch(Integer index) { + EthernetMatch eth = null; + InetMatch inet = null; + L4Match l4 = null; + if (etherMatch != null) { + eth = etherMatch.toEthernetMatch(); + if (inetMatch != null) { + inet = inetMatch.toInetMatch(); + if (layer4Match != null) { + l4 = layer4Match.toL4Match(); + } + } + } + + return (index == null) + ? new FlowMatch(eth, inet, l4) + : new FlowMatch(index.intValue(), eth, inet, l4); + } + + /** + * Return a {@link MatchBuilder} instance which contains the flow + * conditions configured in this instance. + * + * @return A {@link MatchBuilder} instance. + */ + public final MatchBuilder toMatchBuilder() { + MatchBuilder builder = new MatchBuilder(); + if (etherMatch != null) { + etherMatch.setMatch(builder); + if (inetMatch != null) { + inetMatch.setMatch(builder); + if (layer4Match != null) { + layer4Match.setMatch(builder, inetMatch.getIpVersion()); + } + } + } + + return builder; + } + + /** + * Create a flow condition key that identifies this flow condition. + * + * @return A string which can be used to identify the flow match. + */ + public final String getConditionKey() { + StringBuilder builder = new StringBuilder(); + if (etherMatch != null) { + etherMatch.setConditionKey(builder); + if (inetMatch != null) { + inetMatch.setConditionKey(builder); + if (layer4Match != null) { + layer4Match.setConditionKey(builder); + } + } + } + + return builder.toString(); + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + public void verify() throws RpcException { + complete(); + + if (etherMatch != null) { + etherMatch.verify(); + if (inetMatch != null) { + inetMatch.verify(); + if (layer4Match != null) { + layer4Match.verify(); + } + } + } + } + + /** + * Complete the flow conditions. + * + * @throws RpcException + * This flow match contains inconsistent conditions. + */ + public final void complete() throws RpcException { + VTNEtherMatch ematch = etherMatch; + VTNInetMatch imatch = inetMatch; + + if (layer4Match != null) { + // IP protocol number must be specified. + // Defaults to IPv4 if IP match is not specified. + IpVersion ipver = (imatch == null) + ? IpVersion.Ipv4 + : imatch.getIpVersion(); + short p = layer4Match.getInetProtocol(ipver); + Short proto = Short.valueOf(p); + if (imatch == null) { + imatch = new VTNInet4Match(proto); + } else { + imatch.setProtocol(proto); + } + + if (layer4Match.isEmpty()) { + layer4Match = null; + } + } + + if (imatch != null) { + // Ethernet type must be specified. + Integer etype = Integer.valueOf(imatch.getEtherType()); + if (ematch == null) { + ematch = new VTNEtherMatch(etype); + } else { + ematch.setEtherType(etype); + } + + if (imatch.isEmpty()) { + imatch = null; + } + } + + if (ematch != null && ematch.isEmpty()) { + ematch = null; + } + + etherMatch = ematch; + inetMatch = imatch; + } + + /** + * Determine whether the given packet header matches the condition + * specified by this instance. + * + * @param ctx A {@link FlowMatchContext} instance. + * @return {@code true} only if the given packet header matches all + * the conditions configured in this instance. + */ + public final boolean match(FlowMatchContext ctx) { + // Test Ethernet header. + if (etherMatch == null) { + return true; + } + if (!etherMatch.match(ctx)) { + return false; + } + + // Test IP header. + if (inetMatch == null) { + return true; + } + if (!inetMatch.match(ctx)) { + return false; + } + + // Test layer 4 protocol header. + return (layer4Match == null || layer4Match.match(ctx)); + } + + // Objects + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNMatch vm = (VTNMatch)o; + return (Objects.equals(etherMatch, vm.etherMatch) && + Objects.equals(inetMatch, vm.inetMatch) && + Objects.equals(layer4Match, vm.layer4Match)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + return Objects.hash(getClass().getName(), etherMatch, inetMatch, + layer4Match); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRange.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRange.java new file mode 100644 index 00000000..c3339e0a --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRange.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; + +import org.opendaylight.vtn.manager.internal.util.MiscUtils; +import org.opendaylight.vtn.manager.internal.util.ProtocolUtils; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnPortRange; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; + +/** + * {@code VTNPortRange} describes the range of IP transport layer protocol + * such as TCP. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-port-range") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNPortRange { + /** + * The minimum value (inclusive) in the range of TCP/UDP port numbers + * to match against packets. + */ + @XmlElement(name = "port-from") + private Integer portFrom; + + /** + * The maximum value (inclusive) in the range of TCP/UDP port numbers + * to match against packets. + */ + @XmlElement(name = "port-to") + private Integer portTo; + + /** + * Construct a new instance from the given {@link PortMatch} instance. + * + * @param pmatch A {@link PortMatch} instance. + * @return A {@link VTNPortRange} instance if {@code pmatch} is not + * {@code null}. Otherwise {@code null}. + * @throws RpcException + * {@code pmatch} contains invalid value. + */ + public static VTNPortRange create(PortMatch pmatch) throws RpcException { + return (pmatch == null) ? null : new VTNPortRange(pmatch); + } + + /** + * Construct a new instance from the given {@link VtnPortRange} instance. + * + * @param range A {@link VtnPortRange} instance. + * @return A {@link VTNPortRange} instance if {@code pmatch} is not + * {@code null}. Otherwise {@code null}. + * @throws RpcException + * {@code range} contains invalid value. + */ + public static VTNPortRange create(VtnPortRange range) throws RpcException { + return (range == null) ? null : new VTNPortRange(range); + } + + /** + * Construct a new instance which specifies the given port number + * explicitly. + * + * @param port A {@link PortNumber} instance. + * @return A {@link VTNPortRange} instance if {@code port} is not + * {@code null}. Otherwise {@code null}. + * @throws RpcException + * {@code port} contains invalid value. + */ + public static VTNPortRange create(PortNumber port) throws RpcException { + return (port == null) ? null : new VTNPortRange(port); + } + + /** + * Return a {@link PortMatch} instance which represents the given + * condition. + * + * @param range A {@link VTNPortRange} instance. + * @return A {@link PortMatch} instance if {@code range} is not + * {@code null}. Otherwise {@code null}. + */ + public static PortMatch toPortMatch(VTNPortRange range) { + return (range == null) ? null : range.toPortMatch(); + } + + /** + * Private constructor only for JAXB. + */ + @SuppressWarnings("unused") + private VTNPortRange() { + } + + /** + * Construct a new instance from the given {@link PortMatch} instance. + * + * @param pmatch A {@link PortMatch} instance. + * @throws NullPointerException + * {@code pmatch} is {@code null}. + * @throws RpcException + * {@code pmatch} contains invalid value. + */ + public VTNPortRange(PortMatch pmatch) throws RpcException { + portFrom = pmatch.getPortFrom(); + checkPortFrom(); + ProtocolUtils.checkPortNumber(portFrom.intValue()); + + Integer to = pmatch.getPortTo(); + if (to == null) { + portTo = portFrom; + } else { + portTo = to; + ProtocolUtils.checkPortNumber(portTo.intValue()); + checkPortRange(); + } + } + + /** + * Construct a new instance from the given {@link VtnPortRange} instance. + * + * @param range A {@link VtnPortRange} instance. + * @throws NullPointerException + * {@code range} is {@code null}. + * @throws RpcException + * {@code range} contains invalid value. + */ + public VTNPortRange(VtnPortRange range) throws RpcException { + portFrom = ProtocolUtils.getPortNumber(range.getPortFrom()); + checkPortFrom(); + + Integer to = ProtocolUtils.getPortNumber(range.getPortTo()); + if (to == null) { + portTo = portFrom; + } else { + portTo = to; + checkPortRange(); + } + } + + /** + * Construct a new instance which specifies the given port number + * explicitly. + * + * @param port A {@link PortNumber} instance. + * @throws RpcException + * {@code port} contains invalid value. + */ + public VTNPortRange(PortNumber port) throws RpcException { + portFrom = ProtocolUtils.getPortNumber(port); + checkPortFrom(); + portTo = portFrom; + } + + /** + * Return the minimum (inclusive) value in the range of port numbers + * to match against packets. + * + * @return The minimum value in the range of port numbers. + */ + public Integer getPortFrom() { + return portFrom; + } + + /** + * Return the maximum (inclusive) value in the range of port numbers + * to match against packets. + * + * @return The maximum value in the range of port numbers. + */ + public Integer getPortTo() { + return portTo; + } + + /** + * Return the minimum (inclusive) value in the range of port numbers + * to match against packets. + * + * @return A {@link PortNumber} instance that contains the minimum value + * in the range of port numbers. + */ + public PortNumber getPortNumberFrom() { + return new PortNumber(portFrom); + } + + /** + * Return the maximum (inclusive) value in the range of port numbers + * to match against packets. + * + * @return A {@link PortNumber} instance that contains the maximum value + * in the range of port numbers. + */ + public PortNumber getPortNumberTo() { + return new PortNumber(portTo); + } + + /** + * Return a {@link PortMatch} instance which represents this condition. + * + * @return A {@link PortMatch} instance. + */ + public PortMatch toPortMatch() { + return new PortMatch(portFrom, portTo); + } + + /** + * Determine whether the given port number is contained by the port range + * specified by this instance. + * + * @param port A port number. + * @return {@code true} only if the given port number is contained by + * the port range. + */ + public boolean match(int port) { + int from = portFrom.intValue(); + int to = portTo.intValue(); + return (port >= from && port <= to); + } + + /** + * Store strings used to construct flow condition key. + * + * @param builder A {@link StringBuilder} instance that contains strings + * used to construct flow condition key. + */ + public void setConditionKey(StringBuilder builder) { + builder.append(portFrom); + if (portFrom.intValue() != portTo.intValue()) { + builder.append('-').append(portTo); + } + } + + /** + * Verify the contents of this instance. + * + * @throws RpcException Verifycation failed. + */ + public void verify() throws RpcException { + checkPortFrom(); + ProtocolUtils.checkPortNumber(portFrom.intValue()); + if (portTo == null) { + portTo = portFrom; + } else { + ProtocolUtils.checkPortNumber(portTo.intValue()); + checkPortRange(); + } + } + + /** + * Ensure that the minimum value in the port range is configured. + * + * @throws RpcException + * The minimum value in the port range is missing. + */ + private void checkPortFrom() throws RpcException { + if (portFrom == null) { + throw MiscUtils.getNullArgumentException("port-from"); + } + } + + /** + * Ensure the specified port range is valid. + * + * @throws RpcException + * The port range configured in this instance is invalid. + */ + private void checkPortRange() throws RpcException { + if (portFrom > portTo) { + StringBuilder builder = + new StringBuilder("Invalid port range: from="); + builder.append(portFrom).append(", to=").append(portTo); + throw RpcException.getBadArgumentException(builder.toString()); + } + } + + // Objects + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } + + VTNPortRange range = (VTNPortRange)o; + return (Objects.equals(portFrom, range.portFrom) && + Objects.equals(portTo, range.portTo)); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + return Objects.hash(portFrom, portTo); + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatch.java new file mode 100644 index 00000000..cccb8c8d --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatch.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; +import org.opendaylight.vtn.manager.flow.cond.TcpMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.TcpHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnTcpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnTcpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpDestinationRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpSourceRangeBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code VTNTcpMatch} describes the condition for TCP header to match against + * packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-tcp-match") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNTcpMatch extends VTNLayer4PortMatch { + /** + * Construct a new instance that matches every TCP packet. + */ + public VTNTcpMatch() { + } + + /** + * Construct a new instance from the given {@link TcpMatch} instance. + * + * @param tmatch A {@link TcpMatch} instance. + * @throws NullPointerException + * {@code tmatch} is {@code null}. + * @throws RpcException + * {@code tmatch} contains invalid value. + */ + public VTNTcpMatch(TcpMatch tmatch) throws RpcException { + super(tmatch); + } + + /** + * Construct a new instance from the given {@link VtnTcpMatchFields} + * instance. + * + * @param vtmatch A {@link VtnTcpMatchFields} instance. + * @throws NullPointerException + * {@code vtmatch} is {@code null}. + * @throws RpcException + * {@code vtmatch} contains invalid value. + */ + public VTNTcpMatch(VtnTcpMatchFields vtmatch) throws RpcException { + super(vtmatch.getTcpSourceRange(), vtmatch.getTcpDestinationRange()); + } + + /** + * Construct a new instance from the given {@link TcpMatchFields} instance. + * + * @param tmatch A {@link TcpMatchFields} instance. + * @throws NullPointerException + * {@code tmatch} is {@code null}. + * @throws RpcException + * {@code tmatch} contains invalid value. + */ + public VTNTcpMatch(TcpMatchFields tmatch) throws RpcException { + super(tmatch.getTcpSourcePort(), tmatch.getTcpDestinationPort()); + } + + /** + * Create an {@link VtnTcpMatchBuilder} instance. + * + * @param vtmatch An {@link VtnTcpMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code vtmatch} is {@code null}, this method creates a new + * {@link VtnTcpMatchBuilder} instance and returns it. + * Otherwise a {@link VtnTcpMatchBuilder} instance passed to + * {@code vtmatch} is returned. + */ + private VtnTcpMatchBuilder create(VtnTcpMatchBuilder vtmatch) { + return (vtmatch == null) ? new VtnTcpMatchBuilder() : vtmatch; + } + + /** + * Create an {@link TcpMatchBuilder} instance. + * + * @param tmatch An {@link TcpMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code tmatch} is {@code null}, this method creates a new + * {@link TcpMatchBuilder} instance and returns it. + * Otherwise a {@link TcpMatchBuilder} instance passed to + * {@code tmatch} is returned. + */ + private TcpMatchBuilder create(TcpMatchBuilder tmatch) { + return (tmatch == null) ? new TcpMatchBuilder() : tmatch; + } + + // VTNLayer4PortMatch + + /** + * Return an IP protocol number assigned to this protocol. + * + * @param ver An {@link IpVersion} instance which describes the + * IP version. + * @return 6 is always returned. + */ + public short getInetProtocol(IpVersion ver) { + return IPProtocols.TCP.shortValue(); + } + + /** + * Return a {@link TcpMatch} instance which represents this condition. + * + * @return A {@link TcpMatch} instance. + */ + public TcpMatch toL4Match() { + PortMatch src = VTNPortRange.toPortMatch(getSourcePort()); + PortMatch dst = VTNPortRange.toPortMatch(getDestinationPort()); + return new TcpMatch(src, dst); + } + + /** + * {@inheritDoc} + */ + @Override + public void setVtnMatch(VtnFlowMatchBuilder builder) { + VtnTcpMatchBuilder vtmatch = null; + VTNPortRange src = getSourcePort(); + if (src != null) { + TcpSourceRangeBuilder sb = new TcpSourceRangeBuilder(). + setPortFrom(src.getPortNumberFrom()). + setPortTo(src.getPortNumberTo()); + vtmatch = create(vtmatch).setTcpSourceRange(sb.build()); + } + + VTNPortRange dst = getDestinationPort(); + if (dst != null) { + TcpDestinationRangeBuilder db = new TcpDestinationRangeBuilder(). + setPortFrom(dst.getPortNumberFrom()). + setPortTo(dst.getPortNumberTo()); + vtmatch = create(vtmatch).setTcpDestinationRange(db.build()); + } + + if (vtmatch != null) { + builder.setVtnLayer4Match(vtmatch.build()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setMatch(MatchBuilder builder, IpVersion ver) { + TcpMatchBuilder tmatch = null; + VTNPortRange src = getSourcePort(); + if (src != null) { + tmatch = create(tmatch).setTcpSourcePort(src.getPortNumberFrom()); + } + + VTNPortRange dst = getDestinationPort(); + if (dst != null) { + tmatch = create(tmatch). + setTcpDestinationPort(dst.getPortNumberFrom()); + } + + if (tmatch != null) { + builder.setLayer4Match(tmatch.build()); + } + } + + // VTNLayer4PortMatch + + /** + * Return a class which represents the packet header type. + * + * @return A class for {@link TcpHeader}. + */ + @Override + public Class getHeaderType() { + return TcpHeader.class; + } + + /** + * Return a flow match type corresponding to the source port. + * + * @return {@link FlowMatchType#TCP_SRC}. + */ + @Override + public FlowMatchType getSourceMatchType() { + return FlowMatchType.TCP_SRC; + } + + /** + * Return a flow match type corresponding to the destination port. + * + * @return {@link FlowMatchType#TCP_DST}. + */ + @Override + public FlowMatchType getDestinationMatchType() { + return FlowMatchType.TCP_DST; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatch.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatch.java new file mode 100644 index 00000000..b683b84c --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatch.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; +import org.opendaylight.vtn.manager.flow.cond.UdpMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.UdpHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnUdpMatchFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnUdpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpDestinationRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpSourceRangeBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code VTNUdpMatch} describes the condition for UDP header to match against + * packets. + * + *

+ * Note that this class is not synchronized. + *

+ */ +@XmlRootElement(name = "vtn-udp-match") +@XmlAccessorType(XmlAccessType.NONE) +public final class VTNUdpMatch extends VTNLayer4PortMatch { + /** + * Construct a new instance that matches every UDP packet. + */ + public VTNUdpMatch() { + } + + /** + * Construct a new instance from the given {@link UdpMatch} instance. + * + * @param umatch A {@link UdpMatch} instance. + * @throws NullPointerException + * {@code umatch} is {@code null}. + * @throws RpcException + * {@code umatch} contains invalid value. + */ + public VTNUdpMatch(UdpMatch umatch) throws RpcException { + super(umatch); + } + + /** + * Construct a new instance from the given {@link VtnUdpMatchFields} + * instance. + * + * @param vumatch A {@link VtnUdpMatchFields} instance. + * @throws NullPointerException + * {@code vumatch} is {@code null}. + * @throws RpcException + * {@code vumatch} contains invalid value. + */ + public VTNUdpMatch(VtnUdpMatchFields vumatch) throws RpcException { + super(vumatch.getUdpSourceRange(), vumatch.getUdpDestinationRange()); + } + + /** + * Construct a new instance from the given {@link UdpMatchFields} instance. + * + * @param umatch A {@link UdpMatchFields} instance. + * @throws NullPointerException + * {@code umatch} is {@code null}. + * @throws RpcException + * {@code umatch} contains invalid value. + */ + public VTNUdpMatch(UdpMatchFields umatch) throws RpcException { + super(umatch.getUdpSourcePort(), umatch.getUdpDestinationPort()); + } + + /** + * Create an {@link VtnUdpMatchBuilder} instance. + * + * @param vumatch An {@link VtnUdpMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code vumatch} is {@code null}, this method creates a new + * {@link VtnUdpMatchBuilder} instance and returns it. + * Otherwise a {@link VtnUdpMatchBuilder} instance passed to + * {@code vumatch} is returned. + */ + private VtnUdpMatchBuilder create(VtnUdpMatchBuilder vumatch) { + return (vumatch == null) ? new VtnUdpMatchBuilder() : vumatch; + } + + /** + * Create an {@link UdpMatchBuilder} instance. + * + * @param umatch An {@link UdpMatchBuilder} instance. + * {@code null} must be specified on the first call. + * @return If {@code umatch} is {@code null}, this method creates a new + * {@link UdpMatchBuilder} instance and returns it. + * Otherwise a {@link UdpMatchBuilder} instance passed to + * {@code umatch} is returned. + */ + private UdpMatchBuilder create(UdpMatchBuilder umatch) { + return (umatch == null) ? new UdpMatchBuilder() : umatch; + } + + // VTNLayer4PortMatch + + /** + * Return an IP protocol number assigned to this protocol. + * + * @param ver An {@link IpVersion} instance which describes the + * IP version. + * @return 6 is always returned. + */ + public short getInetProtocol(IpVersion ver) { + return IPProtocols.UDP.shortValue(); + } + + /** + * Return a {@link UdpMatch} instance which represents this condition. + * + * @return A {@link UdpMatch} instance. + */ + public UdpMatch toL4Match() { + PortMatch src = VTNPortRange.toPortMatch(getSourcePort()); + PortMatch dst = VTNPortRange.toPortMatch(getDestinationPort()); + return new UdpMatch(src, dst); + } + + /** + * {@inheritDoc} + */ + @Override + public void setVtnMatch(VtnFlowMatchBuilder builder) { + VtnUdpMatchBuilder vumatch = null; + VTNPortRange src = getSourcePort(); + if (src != null) { + UdpSourceRangeBuilder sb = new UdpSourceRangeBuilder(). + setPortFrom(src.getPortNumberFrom()). + setPortTo(src.getPortNumberTo()); + vumatch = create(vumatch).setUdpSourceRange(sb.build()); + } + + VTNPortRange dst = getDestinationPort(); + if (dst != null) { + UdpDestinationRangeBuilder db = new UdpDestinationRangeBuilder(). + setPortFrom(dst.getPortNumberFrom()). + setPortTo(dst.getPortNumberTo()); + vumatch = create(vumatch).setUdpDestinationRange(db.build()); + } + + if (vumatch != null) { + builder.setVtnLayer4Match(vumatch.build()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setMatch(MatchBuilder builder, IpVersion ver) { + UdpMatchBuilder umatch = null; + VTNPortRange src = getSourcePort(); + if (src != null) { + umatch = create(umatch).setUdpSourcePort(src.getPortNumberFrom()); + } + + VTNPortRange dst = getDestinationPort(); + if (dst != null) { + umatch = create(umatch). + setUdpDestinationPort(dst.getPortNumberFrom()); + } + + if (umatch != null) { + builder.setLayer4Match(umatch.build()); + } + } + + // VTNLayer4PortMatch + + /** + * Return a class which represents the packet header type. + * + * @return A class for {@link UdpHeader}. + */ + @Override + public Class getHeaderType() { + return UdpHeader.class; + } + + /** + * Return a flow match type corresponding to the source port. + * + * @return {@link FlowMatchType#UDP_SRC}. + */ + @Override + public FlowMatchType getSourceMatchType() { + return FlowMatchType.UDP_SRC; + } + + /** + * Return a flow match type corresponding to the destination port. + * + * @return {@link FlowMatchType#UDP_DST}. + */ + @Override + public FlowMatchType getDestinationMatchType() { + return FlowMatchType.UDP_DST; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/package-info.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/package-info.java new file mode 100644 index 00000000..54a8fce3 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/flow/match/package-info.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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 + */ + +/** + * This package contains utility classes for flow match handling. + */ +@XmlJavaTypeAdapters({ + @XmlJavaTypeAdapter(value = ByteAdapter.class, type = Byte.class), + @XmlJavaTypeAdapter(value = ByteAdapter.class, type = byte.class), + @XmlJavaTypeAdapter(value = ShortAdapter.class, type = Short.class), + @XmlJavaTypeAdapter(value = ShortAdapter.class, type = short.class), + @XmlJavaTypeAdapter(value = IntegerAdapter.class, type = Integer.class), + @XmlJavaTypeAdapter(value = IntegerAdapter.class, type = int.class), + @XmlJavaTypeAdapter(value = LongAdapter.class, type = Long.class), + @XmlJavaTypeAdapter(value = LongAdapter.class, type = long.class), +}) +package org.opendaylight.vtn.manager.internal.util.flow.match; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters; + +import org.opendaylight.vtn.manager.util.xml.adapters.ByteAdapter; +import org.opendaylight.vtn.manager.util.xml.adapters.IntegerAdapter; +import org.opendaylight.vtn.manager.util.xml.adapters.LongAdapter; +import org.opendaylight.vtn.manager.util.xml.adapters.ShortAdapter; diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilder.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilder.java new file mode 100644 index 00000000..0d89846c --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilder.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +import java.net.Inet4Address; +import java.net.InetAddress; + +import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.Ip4Network; + +import org.opendaylight.controller.sal.packet.ARP; +import org.opendaylight.controller.sal.packet.Ethernet; +import org.opendaylight.controller.sal.packet.IEEE8021Q; +import org.opendaylight.controller.sal.packet.Packet; +import org.opendaylight.controller.sal.utils.EtherTypes; + +/** + * {@code ArpPacketBuilder} is a utility to build an ARP packet. + */ +public final class ArpPacketBuilder { + /** + * The sender protocol address. + */ + private Ip4Network senderProtocolAddress; + + /** + * ARP operation code. + */ + private short operation; + + /** + * VLAN ID for an ARP packet. + */ + private int vlanId; + + /** + * Construct a new instance that builds an ARP request to be sent to + * the untagged network. + */ + public ArpPacketBuilder() { + this(EtherHeader.VLAN_NONE); + } + + /** + * Construct a new instance that builds an ARP request to be sent to the + * specified VLAN. + * + * @param vid The VLAN ID that specifies the VLAN. + * {@link EtherHeader#VLAN_NONE} indicates the untagged + * network. + */ + public ArpPacketBuilder(int vid) { + this(vid, ARP.REQUEST); + } + + /** + * Construct a new instance that builds an ARP packet. + * + * @param vid The VLAN ID that specifies the VLAN. + * {@link EtherHeader#VLAN_NONE} indicates the untagged + * network. + * @param op ARP operation code. + */ + public ArpPacketBuilder(int vid, short op) { + vlanId = vid; + operation = op; + } + + /** + * Set the sender protocol address. + * + * @param ip4 An {@link Ip4Network} instance which indicates the + * sender protocol address. Note that the prefix length is + * always ignored. + * @return This instance. + */ + public ArpPacketBuilder setSenderProtocolAddress(Ip4Network ip4) { + senderProtocolAddress = ip4; + return this; + } + + /** + * Create a broadcast Ethernet frame which contains an ARP request message + * to probe the given IP address. + * + * @param src An {@link EtherAddress} instance to be used as the source + * MAC address. + * @param addr The target IP address. + * @return An Ethernet frame. {@code null} is returned if {@code addr} + * is invalid. + */ + public Ethernet build(EtherAddress src, InetAddress addr) { + return build(src, EtherAddress.BROADCAST, addr); + } + + /** + * Create an Ethernet frame which contains an ARP request message to + * probe the given IP address. + * + * @param src An {@link EtherAddress} instance to be used as the source + * MAC address. + * @param dst The destination MAC address. + * @param addr The target IP address. + * @return An Ethernet frame. {@code null} is returned if {@code addr} + * is invalid. + */ + public Ethernet build(EtherAddress src, EtherAddress dst, + InetAddress addr) { + // IP address must be an IPv4 address. + return (addr instanceof Inet4Address) + ? build(src, dst, new Ip4Network(addr)) + : null; + } + + /** + * Create an Ethernet frame which contains an ARP message. + * + * @param src Source MAC address. + * @param dst Destination MAC address. + * @param target Target IP address. + * @return An Ethernet frame. + */ + public Ethernet build(EtherAddress src, EtherAddress dst, + Ip4Network target) { + byte[] sha = src.getBytes(); + byte[] dstMac = dst.getBytes(); + byte[] tha = (dst.isBroadcast()) + ? new byte[EtherAddress.SIZE] : dstMac; + Ip4Network sender = senderProtocolAddress; + byte[] spa = (sender == null) + ? new byte[Ip4Network.SIZE] : sender.getBytes(); + byte[] tpa = target.getBytes(); + + // Create an ARP request message. + ARP arp = new ARP(); + arp.setHardwareType(ARP.HW_TYPE_ETHERNET). + setProtocolType(EtherTypes.IPv4.shortValue()). + setHardwareAddressLength((byte)EtherAddress.SIZE). + setProtocolAddressLength((byte)Ip4Network.SIZE). + setOpCode(operation). + setSenderHardwareAddress(sha).setSenderProtocolAddress(spa). + setTargetHardwareAddress(tha).setTargetProtocolAddress(tpa); + + short ethType = EtherTypes.ARP.shortValue(); + Packet payload = arp; + if (vlanId != EtherHeader.VLAN_NONE) { + // Add a VLAN tag. + IEEE8021Q tag = new IEEE8021Q(); + tag.setCfi((byte)0).setPcp((byte)0).setVid((short)vlanId). + setEtherType(ethType).setPayload(arp); + ethType = EtherTypes.VLANTAGGED.shortValue(); + payload = tag; + } + + // Create an ethernet frame. + Ethernet ether = new Ethernet(); + ether.setSourceMACAddress(sha).setDestinationMACAddress(dstMac). + setEtherType(ethType).setPayload(payload); + + return ether; + } +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/EtherHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/EtherHeader.java new file mode 100644 index 00000000..3f1e4f6b --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/EtherHeader.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +import org.opendaylight.vtn.manager.util.EtherAddress; + +/** + * {@code EtherHeader} describes the contents of ethernet header and + * IEEE 802.1Q VLAN tag. + */ +public interface EtherHeader extends ProtocolHeader { + /** + * A pseudo VLAN ID that indicates untagged ethernet frame. + */ + int VLAN_NONE = 0; + + /** + * Return the source MAC address. + * + * @return An {@link EtherAddress} instance which represents the source + * MAC address. + */ + EtherAddress getSourceAddress(); + + /** + * Set the source MAC address. + * + * @param mac An {@link EtherAddress} instance which represents the source + * MAC address. + */ + void setSourceAddress(EtherAddress mac); + + /** + * Return the destination MAC address. + * + * @return An {@link EtherAddress} instance which represents the + * destination MAC address. + */ + EtherAddress getDestinationAddress(); + + /** + * Set the destination MAC address. + * + * @param mac An {@link EtherAddress} instance which represents the + * destination MAC address. + */ + void setDestinationAddress(EtherAddress mac); + + /** + * Return the ethernet type. + * + * @return An integer value which represents the ethernet type. + */ + int getEtherType(); + + /** + * Return the VLAN ID in the IEEE 802.1Q VLAN tag. + * + * @return A VLAN ID in the VLAN tag. + * {@link #VLAN_NONE} is returned if this frame does not contain + * a VLAN tag. + */ + int getVlanId(); + + /** + * Set the VLAN ID to the IEEE 802.1Q VLAN tag. + * + * @param vid A VLAN ID in the VLAN tag. + * If {@link #VLAN_NONE} is specified, the VLAN tag will be + * removed. + */ + void setVlanId(int vid); + + /** + * Return the VLAN priority value in the IEEE 802.1Q VLAN tag. + * + * @return A byte value which represents the VLAN priority. + * A negative value is returned if the VLAN priority is not + * configured in this instance. + */ + short getVlanPriority(); + + /** + * Set the VLAN priority value to the IEEE 802.1Q VLAN tag. + * + * @param pcp A byte value which represents the VLAN priority. + */ + void setVlanPriority(short pcp); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/IcmpHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/IcmpHeader.java new file mode 100644 index 00000000..230d6fc7 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/IcmpHeader.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code IcmpHeader} describes the contents of ICMP header. + */ +public interface IcmpHeader extends Layer4Header { + /** + * Return the ICMP type. + * + * @return A short integer value which indicates the ICMP type. + */ + short getIcmpType(); + + /** + * Set the ICMP type. + * + * @param type A short integer value which indicates the ICMP type. + */ + void setIcmpType(short type); + + /** + * Return the ICMP code. + * + * @return A short integer value which indicates the ICMP code. + */ + short getIcmpCode(); + + /** + * Set the ICMP code. + * + * @param code A short integer value which indicates the ICMP code. + */ + void setIcmpCode(short code); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/InetHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/InetHeader.java new file mode 100644 index 00000000..c207647b --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/InetHeader.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +import org.opendaylight.vtn.manager.util.IpNetwork; + +/** + * {@code InetHeader} describes the contents of IP header. + */ +public interface InetHeader extends ProtocolHeader { + /** + * Return the source IP address. + * + * @return An {@link IpNetwork} instance which represents the source + * IP address. + */ + IpNetwork getSourceAddress(); + + /** + * Set the source IP address. + * + * @param ipn An {@link IpNetwork} instance which represents the source + * IP address. + */ + void setSourceAddress(IpNetwork ipn); + + /** + * Return the destination IP address. + * + * @return An {@link IpNetwork} instance which represents the destination + * IP address. + */ + IpNetwork getDestinationAddress(); + + /** + * Set the destination IP address. + * + * @param ipn An {@link IpNetwork} instance which represents the + * destination IP address. + */ + void setDestinationAddress(IpNetwork ipn); + + /** + * Return the IP protocol number. + * + * @return A short integer value which indicates the IP protocol number. + */ + short getProtocol(); + + /** + * Return the DSCP field value. + * + * @return A short value which indicates the DSCP field value. + */ + short getDscp(); + + /** + * Set the DSCP field value. + * + * @param value A short value which indicates the DSCP field value. + */ + void setDscp(short value); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4Header.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4Header.java new file mode 100644 index 00000000..ac0a702b --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4Header.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code Layer4Header} describes the contents of layer 4 protocol header. + */ +public interface Layer4Header extends ProtocolHeader { +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4PortHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4PortHeader.java new file mode 100644 index 00000000..ad7477e9 --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/Layer4PortHeader.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code Layer4PortHeader} describes the contents of layer 4 protocol header + * which identifies the service using 16-bit port number. + */ +public interface Layer4PortHeader extends Layer4Header { + /** + * Return the source port number. + * + * @return An integer value which represents the source port number. + */ + int getSourcePort(); + + /** + * Set the source port number. + * + * @param port An integer value which represents the source port number. + */ + void setSourcePort(int port); + + /** + * Return the destination port number. + * + * @return An integer value which represents the destination port number. + */ + int getDestinationPort(); + + /** + * Set the destination port number. + * + * @param port An integer value which represents the destination port + * number. + */ + void setDestinationPort(int port); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/PacketHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/PacketHeader.java new file mode 100644 index 00000000..32fa7bce --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/PacketHeader.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code PacketHeader} describes a class that keeps protocol headers + * for each protocol layer. + */ +public interface PacketHeader { + /** + * Return an {@link EtherHeader} instance which describes an Ethernet + * header and IEEE 802.1Q VLAN tag. + * + * @return An {@link EtherHeader} instance. + */ + EtherHeader getEtherHeader(); + + /** + * Returns an {@link InetHeader} instance which describes an IP header. + * + * @return An {@link InetHeader} instance if a packet associated with + * this instance is an IP packet. Otherwise {@code null}. + */ + InetHeader getInetHeader(); + + /** + * Returns a {@link Layer4Header} instance which describes a layer 4 + * protocol header. + * + * @return An {@link Layer4Header} instance if a packet associated with + * this instance contains a layer 4 protocol header. + * Otherwise {@code null}. + */ + Layer4Header getLayer4Header(); + + /** + * Return a description about protocol headers. + * + * @return A description about protocol headers. + */ + String getHeaderDescription(); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ProtocolHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ProtocolHeader.java new file mode 100644 index 00000000..d1b5831a --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ProtocolHeader.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code ProtocolHeader} describes a class that keeps network protocol header. + */ +public interface ProtocolHeader { + /** + * Set a brief description into the given string builder. + * + * @param builder A {@link StringBuilder} instance. + */ + void setDescription(StringBuilder builder); +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/TcpHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/TcpHeader.java new file mode 100644 index 00000000..b31230fa --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/TcpHeader.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code TcpHeader} describes the contents of TCP header. + */ +public interface TcpHeader extends Layer4PortHeader { +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/UdpHeader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/UdpHeader.java new file mode 100644 index 00000000..ba441d8c --- /dev/null +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/UdpHeader.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +/** + * {@code UdpHeader} describes the contents of UDP header. + */ +public interface UdpHeader extends Layer4PortHeader { +} diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/rpc/RpcFuture.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/rpc/RpcFuture.java index f007fda3..104ede76 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/rpc/RpcFuture.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/rpc/RpcFuture.java @@ -47,11 +47,6 @@ public final class RpcFuture private static final Logger LOG = LoggerFactory.getLogger(RpcFuture.class); - /** - * A {@link VTNFuture} instance associated with this RPC request. - */ - private final VTNFuture mainTask; - /** * RPC output generator. */ @@ -65,7 +60,6 @@ public final class RpcFuture * @param gen RPC output generator. */ public RpcFuture(VTNFuture f, RpcOutputGenerator gen) { - mainTask = f; generator = gen; Futures.addCallback(f, this); } diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/ReadTxContext.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/ReadTxContext.java index 446ddb08..26e3f9db 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/ReadTxContext.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/ReadTxContext.java @@ -12,6 +12,7 @@ package org.opendaylight.vtn.manager.internal.util.tx; import org.opendaylight.vtn.manager.internal.TxContext; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.InventoryReader; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondReader; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; @@ -40,6 +41,11 @@ public final class ReadTxContext implements TxContext { */ private InventoryReader inventoryReader; + /** + * A flow condition reader. + */ + private FlowCondReader flowCondReader; + /** * Construct a new instance. * @@ -89,6 +95,20 @@ public final class ReadTxContext implements TxContext { return reader; } + /** + * {@inheritDoc} + */ + @Override + public FlowCondReader getFlowCondReader() { + FlowCondReader reader = flowCondReader; + if (reader == null) { + reader = new FlowCondReader(getTransaction()); + flowCondReader = reader; + } + + return reader; + } + /** * {@inheritDoc} */ diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/TxQueueImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/TxQueueImpl.java index 0dabf9c2..119bfa5c 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/TxQueueImpl.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/tx/TxQueueImpl.java @@ -28,6 +28,7 @@ import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.InventoryReader; import org.opendaylight.vtn.manager.internal.util.concurrent.SettableVTNFuture; import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; +import org.opendaylight.vtn.manager.internal.util.flow.cond.FlowCondReader; import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; @@ -108,6 +109,11 @@ public final class TxQueueImpl implements TxQueue, Runnable, AutoCloseable { */ private InventoryReader inventoryReader; + /** + * A flow condition reader. + */ + private FlowCondReader flowCondReader; + /** * Construct a new instance. * @@ -254,6 +260,20 @@ public final class TxQueueImpl implements TxQueue, Runnable, AutoCloseable { return reader; } + /** + * {@inheritDoc} + */ + @Override + public FlowCondReader getFlowCondReader() { + FlowCondReader reader = flowCondReader; + if (reader == null) { + reader = new FlowCondReader(getReadWriteTransaction()); + flowCondReader = reader; + } + + return reader; + } + /** * {@inheritDoc} */ diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/DataGenerator.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/DataGenerator.java index 7f4d2671..32d546f0 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/DataGenerator.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/DataGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NEC Corporation + * Copyright (c) 2014-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -147,4 +147,13 @@ public final class DataGenerator { return port; } + + /** + * Return ICMP type/code value for test. + * + * @return A short value for ICMP type/code test. + */ + public Short getIcmpValue() { + return Short.valueOf((short)(getPort() & 0xff)); + } } diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java index 5834cb59..50c2c096 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java @@ -55,7 +55,6 @@ import org.opendaylight.vtn.manager.VTerminalIfPath; import org.opendaylight.vtn.manager.VTerminalPath; import org.opendaylight.vtn.manager.flow.action.FlowAction; import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction; -import org.opendaylight.vtn.manager.flow.cond.FlowCondition; import org.opendaylight.vtn.manager.flow.filter.FlowFilter; import org.opendaylight.vtn.manager.flow.filter.PassFilter; import org.opendaylight.vtn.manager.util.EtherAddress; @@ -2133,28 +2132,6 @@ public abstract class TestBase extends Assert { } } - /** - * Common Method to create FlowCondition. - * @return FlowCondition list object. - */ - public List createFlowConditions() { - List flowConditionList = new ArrayList(); - - try { - FlowCondition flowCondition = null; - flowConditionList.add(null); - flowConditionList.add(flowCondition); - - for (String conditionName : FLOW_CONDITION_NAME) { - flowCondition = new FlowCondition(conditionName, null); - flowConditionList.add(flowCondition); - } - return flowConditionList; - } catch (Exception ex) { - return null; - } - } - /** * Common Method to create PathMap. * @return PathMap list object. diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImplTest.java deleted file mode 100644 index 8f8fd6e3..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImplTest.java +++ /dev/null @@ -1,962 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.util.HashSet; - -import javax.xml.bind.Unmarshaller; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; -import org.opendaylight.vtn.manager.util.EtherAddress; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.util.MiscUtils; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.IEEE8021Q; -import org.opendaylight.controller.sal.packet.Packet; -import org.opendaylight.controller.sal.packet.address.EthernetAddress; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link EthernetMatchImpl}. - */ -public class EthernetMatchImplTest extends TestBase { - /** - * Test for {@link EthernetMatchImpl#EthernetMatchImpl(int)} and - * getter methods. - */ - @Test - public void testConstructor1() { - int[] types = { - 0, 1, 0x800, 0x806, 0x86dd, - }; - - EtherAddress nullMac = null; - for (int type: types) { - EthernetMatchImpl emi = new EthernetMatchImpl(type); - assertEquals(-1L, emi.getSourceAddress()); - assertEquals(-1L, emi.getDestinationAddress()); - assertEquals(type, emi.getEtherType()); - assertEquals((short)-1, emi.getVlan()); - assertEquals((byte)-1, emi.getVlanPriority()); - - Integer t = Integer.valueOf(type); - EthernetMatch em = - new EthernetMatch(nullMac, nullMac, t, null, null); - assertEquals(em, emi.getMatch()); - } - } - - /** - * Test for {@link EthernetMatchImpl#EthernetMatchImpl(EthernetMatch)} and - * getter methods. - * - * @throws VTNException An error occurred. - */ - @Test - public void testConstructor2() throws VTNException { - long[] srcs = {-1L, 1L, 0x000102030405L}; - long[] dsts = {-1L, 0xf0f1f2f3f4f5L, 0xa8b9cadbecfdL}; - int[] types = {-1, 0x800, 0x86dd}; - short[] vlans = {-1, 0, 1, 4095}; - byte[] priorities = {0, 3, 7}; - - EthernetMatchImplBuilder builder = new EthernetMatchImplBuilder(); - for (long src: srcs) { - builder.setSourceAddress(src); - for (long dst: dsts) { - builder.setDestinationAddress(dst); - for (int type: types) { - builder.setEtherType(type); - for (short vlan: vlans) { - builder.setVlanId(vlan); - builder.setVlanPriority((byte)-1); - EthernetMatchImpl emi = builder.create(); - assertEquals(src, emi.getSourceAddress()); - assertEquals(dst, emi.getDestinationAddress()); - assertEquals(type, emi.getEtherType()); - assertEquals(vlan, emi.getVlan()); - assertEquals((byte)-1, emi.getVlanPriority()); - assertEquals(builder.getEthernetMatch(), - emi.getMatch()); - - if (vlan <= 0) { - continue; - } - - for (byte pri: priorities) { - builder.setVlanPriority(pri); - emi = builder.create(); - assertEquals(src, emi.getSourceAddress()); - assertEquals(dst, emi.getDestinationAddress()); - assertEquals(type, emi.getEtherType()); - assertEquals(vlan, emi.getVlan()); - assertEquals(pri, emi.getVlanPriority()); - assertEquals(builder.getEthernetMatch(), - emi.getMatch()); - } - } - } - } - } - - // Specifying invalid MAC address via JAXB. - String[] badAddrs = { - "", "aa:bb:cc:dd:ee:ff:11", "00:11", "bad_address", - }; - Unmarshaller um = createUnmarshaller(EthernetMatch.class); - for (String addr: badAddrs) { - for (String attr: new String[]{"src", "dst"}) { - StringBuilder sb = new StringBuilder(XML_DECLARATION); - String xml = sb.append("").toString(); - EthernetMatch em = null; - try { - em = unmarshal(um, xml, EthernetMatch.class); - } catch (Exception e) { - unexpected(e); - } - - assertNotNull(em); - assertNotNull(em.getValidationStatus()); - try { - new EthernetMatchImpl(em); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - } - } - } - - // Specifying invalid ethernet type. - Integer[] badTypes = { - Integer.valueOf(Integer.MIN_VALUE), Integer.valueOf(-1), - Integer.valueOf(0x10000), Integer.valueOf(Integer.MAX_VALUE), - }; - EtherAddress nullMac = null; - for (Integer type: badTypes) { - EthernetMatch em = - new EthernetMatch(nullMac, nullMac, type, null, null); - try { - new EthernetMatchImpl(em); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid Ethernet type: " + type, - st.getDescription()); - } - } - - // Specifying invalid VLAN ID. - Short[] badVlans = { - Short.valueOf(Short.MIN_VALUE), Short.valueOf((short)-1), - Short.valueOf((short)4096), Short.valueOf(Short.MAX_VALUE), - }; - for (Short vlan: badVlans) { - EthernetMatch em = - new EthernetMatch(nullMac, nullMac, null, vlan, null); - try { - new EthernetMatchImpl(em); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid VLAN ID: " + vlan, st.getDescription()); - } - } - - // Specifying invalid VLAN priority. - Short validVlan = Short.valueOf((short)1); - Byte[] badPriorities = { - Byte.valueOf(Byte.MIN_VALUE), Byte.valueOf((byte)-1), - Byte.valueOf((byte)8), Byte.valueOf(Byte.MAX_VALUE), - }; - for (Byte pri: badPriorities) { - EthernetMatch em = - new EthernetMatch(nullMac, nullMac, null, validVlan, pri); - try { - new EthernetMatchImpl(em); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid VLAN priority: " + pri, - st.getDescription()); - } - } - - // Specifying VLAN priority without specifying valid VLAN ID. - Short[] noVlans = { - null, Short.valueOf((short)0), - }; - for (Short vlan: noVlans) { - for (byte p = 0; p <= 7; p++) { - Byte pri = Byte.valueOf(p); - EthernetMatch em = - new EthernetMatch(nullMac, nullMac, null, vlan, pri); - try { - new EthernetMatchImpl(em); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("VLAN priority requires a valid VLAN ID.", - st.getDescription()); - } - } - } - } - - /** - * Test case for {@link EthernetMatchImpl#setEtherType(int)}. - */ - @Test - public void testSetEtherType() { - int[] types = { - 0, 1, 0x800, 0x806, 0x86dd, - }; - EtherAddress nullMac = null; - for (int type: types) { - EthernetMatch em = - new EthernetMatch(nullMac, nullMac, null, null, null); - EthernetMatchImpl emi = null; - try { - emi = new EthernetMatchImpl(em); - } catch (VTNException e) { - unexpected(e); - } - - // New ethernet type can be set as long as existing type is not - // changed. - try { - for (int i = 0; i < 4; i++) { - emi.setEtherType(type); - assertEquals(type, emi.getEtherType()); - } - } catch (VTNException e) { - unexpected(e); - } - - try { - emi.setEtherType(type + 1); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - String expected = "Ethernet type conflict: type=0x" + - Integer.toHexString(type) + ", expected=0x" + - Integer.toHexString(type + 1); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals(expected, st.getDescription()); - } - } - } - - /** - * Test case for {@link EthernetMatchImpl#equals(Object)} and - * {@link EthernetMatchImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - long[] srcs = {-1L, 1L, 0x000102030405L}; - long[] dsts = {-1L, 0xf0f1f2f3f4f5L, 0xa8b9cadbecfdL}; - int[] types = {-1, 0x800, 0x86dd}; - short[] vlans = {-1, 0, 1, 4095}; - byte[] priorities = {0, 3, 7}; - int count = 0; - for (long src: srcs) { - EthernetAddress ethSrc = createEthernetAddress(src); - for (long dst: dsts) { - EthernetAddress ethDst = createEthernetAddress(dst); - for (int type: types) { - Integer ethType = (type == -1) ? null - : Integer.valueOf(type); - for (short vlan: vlans) { - Short ethVlan = (vlan == -1) ? null - : Short.valueOf(vlan); - EthernetMatch em = new EthernetMatch( - ethSrc, ethDst, ethType, ethVlan, null); - EthernetMatchImpl emi1 = new EthernetMatchImpl(em); - EthernetMatchImpl emi2 = new EthernetMatchImpl(em); - testEquals(set, emi1, emi2); - count++; - - if (vlan <= 0) { - continue; - } - - for (byte pri: priorities) { - Byte ethPri = Byte.valueOf(pri); - em = new EthernetMatch(ethSrc, ethDst, ethType, - ethVlan, ethPri); - emi1 = new EthernetMatchImpl(em); - emi2 = new EthernetMatchImpl(em); - testEquals(set, emi1, emi2); - count++; - } - } - } - } - } - - assertEquals(count, set.size()); - } - - /** - * Test case for {@link EthernetMatchImpl#toString()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testToString() throws VTNException { - String prefix = "EthernetMatchImpl["; - String suffix = "]"; - - long[] srcs = {-1L, 1L, 0x000102030405L}; - long[] dsts = {-1L, 0xf0f1f2f3f4f5L, 0xa8b9cadbecfdL}; - int[] types = {-1, 0x800, 0x86dd}; - short[] vlans = {-1, 0, 1, 4095}; - byte[] priorities = {0, 3, 7}; - - for (long src: srcs) { - EthernetAddress ethSrc = createEthernetAddress(src); - String s = (src == -1L) ? null - : "src=" + MiscUtils.formatMacAddress(src); - for (long dst: dsts) { - EthernetAddress ethDst = createEthernetAddress(dst); - String d = (dst == -1L) ? null - : "dst=" + MiscUtils.formatMacAddress(dst); - for (int type: types) { - Integer ethType; - String t; - if (type == -1) { - ethType = null; - t = null; - } else { - ethType = Integer.valueOf(type); - t = "type=0x" + Integer.toHexString(type); - } - for (short vlan: vlans) { - Short ethVlan; - String v; - if (vlan == -1) { - ethVlan = null; - v = null; - } else { - ethVlan = Short.valueOf(vlan); - v = "vlan=" + vlan; - } - - EthernetMatch em = new EthernetMatch( - ethSrc, ethDst, ethType, ethVlan, null); - EthernetMatchImpl emi = new EthernetMatchImpl(em); - String required = joinStrings(prefix, suffix, ",", - s, d, t, v); - assertEquals(required, emi.toString()); - - if (vlan <= 0) { - continue; - } - - for (byte pri: priorities) { - Byte ethPri = Byte.valueOf(pri); - String p = "pcp=" + pri; - em = new EthernetMatch(ethSrc, ethDst, ethType, - ethVlan, ethPri); - emi = new EthernetMatchImpl(em); - required = joinStrings(prefix, suffix, ",", - s, d, t, v, p); - assertEquals(required, emi.toString()); - } - } - } - } - } - } - - /** - * Ensure that {@link EthernetMatchImpl} is serializable. - * - * @throws VTNException An error occurred. - */ - @Test - public void testSerialize() throws VTNException { - long[] srcs = {-1L, 1L, 0x000102030405L}; - long[] dsts = {-1L, 0xf0f1f2f3f4f5L, 0xa8b9cadbecfdL}; - int[] types = {-1, 0x800, 0x86dd}; - short[] vlans = {-1, 0, 1, 4095}; - byte[] priorities = {0, 3, 7}; - - for (long src: srcs) { - EthernetAddress ethSrc = createEthernetAddress(src); - for (long dst: dsts) { - EthernetAddress ethDst = createEthernetAddress(dst); - for (int type: types) { - Integer ethType = (type == -1) ? null - : Integer.valueOf(type); - for (short vlan: vlans) { - Short ethVlan = (vlan == -1) ? null - : Short.valueOf(vlan); - EthernetMatch em = new EthernetMatch( - ethSrc, ethDst, ethType, ethVlan, null); - EthernetMatchImpl emi = new EthernetMatchImpl(em); - serializeTest(emi); - - if (vlan <= 0) { - continue; - } - - for (byte pri: priorities) { - Byte ethPri = Byte.valueOf(pri); - em = new EthernetMatch(ethSrc, ethDst, ethType, - ethVlan, ethPri); - emi = new EthernetMatchImpl(em); - serializeTest(emi); - } - } - } - } - } - } - - /** - * Test case for {@link EthernetMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testMatch() throws VTNException { - byte[] src = { - (byte)0x10, (byte)0x20, (byte)0x30, - (byte)0x40, (byte)0x50, (byte)0x60, - }; - byte[] dst = { - (byte)0xf0, (byte)0xf1, (byte)0xf2, - (byte)0xfa, (byte)0xfb, (byte)0xfc, - }; - int type = 0x0806; - byte pcp = 3; - - // Run tests with an ARP packet. - short[] vlans = { - MatchType.DL_VLAN_NONE, 1, 10, 200, 3000, 4095, - }; - for (short vlan: vlans) { - Ethernet pkt = createEthernet(src, dst, type, vlan, pcp, - PacketMatchTest.ARP_PACKET); - matchTest(pkt); - } - } - - /** - * Run tests for {@link EthernetMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)} - * using the given packet. - * - * @param pkt An {@link Ethernet} instance for test. - */ - private void matchTest(Ethernet pkt) { - EthernetParser ethParser = new EthernetParser(pkt); - byte[] src = ethParser.getSourceAddress(); - byte[] dst = ethParser.getDestinationAddress(); - int type = ethParser.getEtherType(); - short vlan = ethParser.getVlanId(); - byte pcp = ethParser.getVlanPcp(); - - byte[] anotherSrc = ethParser.getAnotherSourceAddress(); - byte[] anotherDst = ethParser.getAnotherDestinationAddress(); - int anotherType = ethParser.getAnotherEtherType(); - short anotherVlan = ethParser.getAnotherVlanId(); - byte anotherPcp = ethParser.getAnotherVlanPcp(); - - PacketMatchTest test = new PacketMatchTest(); - EthernetMatchImplBuilder builder = new EthernetMatchImplBuilder(); - - // Empty match should match every packet. - assertEquals(true, test.run(builder.create(), pkt)); - - // Specify single field in Ethernet frame. - EthernetMatchImpl emi = builder.reset().setSourceAddress(src).create(); - assertEquals(true, test.setMatchType(MatchType.DL_SRC).run(emi, pkt)); - emi = builder.reset().setSourceAddress(anotherSrc).create(); - assertEquals(false, test.run(emi, pkt)); - - test.reset().setMatchType(MatchType.DL_DST); - emi = builder.reset().setDestinationAddress(dst).create(); - assertEquals(true, test.run(emi, pkt)); - emi = builder.reset().setDestinationAddress(anotherDst).create(); - assertEquals(false, test.run(emi, pkt)); - - test.reset().setMatchType(MatchType.DL_TYPE); - emi = builder.reset().setEtherType(type).create(); - assertEquals(true, test.run(emi, pkt)); - emi = builder.reset().setEtherType(anotherType).create(); - assertEquals(false, test.run(emi, pkt)); - - // DL_VLAN should never be configured in PacketContext. - test.reset(); - if (vlan == MatchType.DL_VLAN_NONE) { - emi = builder.reset().setVlanId(vlan).create(); - assertEquals(true, test.run(emi, pkt)); - - short[] anotherVids = {1, 10, 300, 2345, 4095}; - for (short vid: anotherVids) { - emi = builder.reset().setVlanId(vid).create(); - assertEquals(false, test.run(emi, pkt)); - emi = builder.setVlanPriority((byte)2).create(); - assertEquals(false, test.run(emi, pkt)); - } - } else { - emi = builder.reset().setVlanId(vlan).create(); - assertEquals(true, test.run(emi, pkt)); - - short[] anotherVids = { - MatchType.DL_VLAN_NONE, - anotherVlan, - }; - for (short vid: anotherVids) { - emi = builder.reset().setVlanId(vid).create(); - assertEquals(false, test.run(emi, pkt)); - } - - short[] vids = {vlan, anotherVlan}; - for (short vid: vids) { - builder.reset().setVlanId(vid); - test.reset(); - if (vid == vlan) { - test.setMatchType(MatchType.DL_VLAN_PR); - } - for (byte pri = 0; pri <= 7; pri++) { - boolean expected = (vid == vlan && pri == pcp); - emi = builder.setVlanPriority(pri).create(); - assertEquals(expected, test.run(emi, pkt)); - } - } - } - - // Specify all fields. - builder.reset().setSourceAddress(src).setDestinationAddress(dst). - setEtherType(type).setVlanId(vlan); - test.reset().setMatchType(MatchType.DL_SRC, MatchType.DL_DST, - MatchType.DL_TYPE); - if (vlan != MatchType.DL_VLAN_NONE) { - builder.setVlanPriority(pcp); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - emi = builder.create(); - assertEquals(true, test.run(emi, pkt)); - - // Ensure that match() returns false if one field does not match. - test.reset().setMatchType(MatchType.DL_SRC); - emi = builder.setSourceAddress(anotherSrc).create(); - assertEquals(false, test.run(emi, pkt)); - - test.setMatchType(MatchType.DL_DST); - emi = builder.setSourceAddress(src).setDestinationAddress(anotherDst). - create(); - assertEquals(false, test.run(emi, pkt)); - - test.setMatchType(MatchType.DL_TYPE); - emi = builder.setDestinationAddress(dst).setEtherType(anotherType). - create(); - assertEquals(false, test.run(emi, pkt)); - - emi = builder.setEtherType(type).setVlanId(anotherVlan).create(); - assertEquals(false, test.run(emi, pkt)); - - emi = builder.setVlanId(vlan).setVlanPriority(anotherPcp).create(); - boolean expected = (vlan == MatchType.DL_VLAN_NONE); - if (!expected) { - test.setMatchType(MatchType.DL_VLAN_PR); - } - assertEquals(expected, test.run(emi, pkt)); - } -} - -/** - * Utility class to create {@link EthernetMatchImpl} instance. - */ -final class EthernetMatchImplBuilder extends TestBase { - /** - * Source MAC address. - */ - private EthernetAddress sourceAddress; - - /** - * Destinaiton MAC address. - */ - private EthernetAddress destinationAddress; - - /** - * Ethernet type. - */ - private Integer etherType; - - /** - * VLAN ID. - */ - private Short vlanId; - - /** - * VLAN priority. - */ - private Byte vlanPriority; - - /** - * Created {@link EthernetMatch} instance. - */ - private EthernetMatch ethernetMatch; - - /** - * Set source MAC address. - * - * @param addr A long integer value which represents a MAC address. - * @return This instance. - */ - public EthernetMatchImplBuilder setSourceAddress(long addr) { - sourceAddress = createEthernetAddress(addr); - ethernetMatch = null; - return this; - } - - /** - * Set source MAC address. - * - * @param addr A byte array which represents a MAC address. - * @return This instance. - */ - public EthernetMatchImplBuilder setSourceAddress(byte[] addr) { - sourceAddress = createEthernetAddress(addr); - ethernetMatch = null; - return this; - } - - /** - * Set destination MAC address. - * - * @param addr A long integer value which represents a MAC address. - * @return This instance. - */ - public EthernetMatchImplBuilder setDestinationAddress(long addr) { - destinationAddress = createEthernetAddress(addr); - ethernetMatch = null; - return this; - } - - /** - * Set destination MAC address. - * - * @param addr A byte array which represents a MAC address. - * @return This instance. - */ - public EthernetMatchImplBuilder setDestinationAddress(byte[] addr) { - destinationAddress = createEthernetAddress(addr); - ethernetMatch = null; - return this; - } - - /** - * Set ethernet type. - * - * @param type Ethernet type. - * @return This instance. - */ - public EthernetMatchImplBuilder setEtherType(int type) { - etherType = (type == -1) ? null : Integer.valueOf(type); - ethernetMatch = null; - return this; - } - - /** - * Set VLAN ID. - * - * @param vid VLAN ID. - * @return This instance. - */ - public EthernetMatchImplBuilder setVlanId(short vid) { - vlanId = (vid == -1) ? null : Short.valueOf(vid); - ethernetMatch = null; - return this; - } - - /** - * Set VLAN priority. - * - * @param pcp VLAN priority. - * @return This instance. - */ - public EthernetMatchImplBuilder setVlanPriority(byte pcp) { - vlanPriority = (pcp == -1) ? null : Byte.valueOf(pcp); - ethernetMatch = null; - return this; - } - - /** - * Reset to the initial state. - * - * @return This instance. - */ - public EthernetMatchImplBuilder reset() { - sourceAddress = null; - destinationAddress = null; - etherType = null; - vlanId = null; - vlanPriority = null; - ethernetMatch = null; - - return this; - } - - /** - * Construct an {@link EthernetMatch} instance. - * - * @return An {@link EthernetMatch} instance. - */ - public EthernetMatch getEthernetMatch() { - EthernetMatch em = ethernetMatch; - if (em == null) { - em = new EthernetMatch(sourceAddress, destinationAddress, - etherType, vlanId, vlanPriority); - ethernetMatch = em; - } - - return em; - } - - /** - * Construct an {@link EthernetMatchImpl} instance. - * - * @return An {@link EthernetMatchImpl} instance. - * @throws VTNException An error occurred. - */ - public EthernetMatchImpl build() throws VTNException { - EthernetMatch em = getEthernetMatch(); - return new EthernetMatchImpl(em); - } - - /** - * Construct an {@link EthernetMatchImpl} instance and ensure that it was - * constructed successfully. - * - * @return An {@link EthernetMatchImpl} instance. - */ - public EthernetMatchImpl create() { - EthernetMatchImpl emi = null; - try { - emi = build(); - } catch (Exception e) { - unexpected(e); - } - - return emi; - } -} - -/** - * Ethernet header parser. - */ -final class EthernetParser { - /** - * Ethernet frame. - */ - private final Ethernet ethernet; - - /** - * Source MAC address. - */ - private final byte[] sourceAddress; - - /** - * Destination MAC address. - */ - private final byte[] destinationAddress; - - /** - * Ethernet type. - */ - private final int etherType; - - /** - * VLAN ID. - */ - private final short vlanId; - - /** - * VLAN priority. - */ - private final byte vlanPcp; - - /** - * Payload of the ethernet frame. - */ - private final Packet payload; - - /** - * Construct a new instance. - * - * @param ether An ethernet frame. - */ - EthernetParser(Ethernet ether) { - ethernet = ether; - sourceAddress = ether.getSourceMACAddress(); - destinationAddress = ether.getDestinationMACAddress(); - - Packet pld = ether.getPayload(); - if (pld instanceof IEEE8021Q) { - IEEE8021Q tag = (IEEE8021Q)pld; - vlanId = tag.getVid(); - vlanPcp = tag.getPcp(); - etherType = NumberUtils.getUnsigned(tag.getEtherType()); - payload = tag.getPayload(); - } else { - vlanId = MatchType.DL_VLAN_NONE; - vlanPcp = -1; - etherType = NumberUtils.getUnsigned(ether.getEtherType()); - payload = pld; - } - } - - /** - * Return the ethernet frame configured in this instance. - * - * @return An {@link Ethernet} instance. - */ - public Ethernet getEthernet() { - return ethernet; - } - - /** - * Return the source MAC address. - * - * @return A byte array which represents the source MAC address. - */ - public byte[] getSourceAddress() { - return sourceAddress; - } - - /** - * Return the destination MAC address. - * - * @return A byte array which represents the destination MAC address. - */ - public byte[] getDestinationAddress() { - return destinationAddress; - } - - /** - * Return the ethernet type. - * - * @return Ethernet type. - */ - public int getEtherType() { - return etherType; - } - - /** - * Return the VLAN ID. - * - * @return VLAN ID. - */ - public short getVlanId() { - return vlanId; - } - - /** - * Return the VLAN priority. - * - * @return VLAN ID. - */ - public byte getVlanPcp() { - return vlanPcp; - } - - /** - * Return the payload of the ethernet frame. - * - * @return The payload of the ethernet frame. - */ - public Packet getPayload() { - return payload; - } - - /** - * Return a source MAC address that does not match this packet. - * - * @return A source MAC address that does not match this packet. - */ - public byte[] getAnotherSourceAddress() { - byte[] addr = sourceAddress.clone(); - addr[4] = (byte)~addr[4]; - return addr; - } - - /** - * Return a destination MAC address that does not match this packet. - * - * @return A destination MAC address that does not match this packet. - */ - public byte[] getAnotherDestinationAddress() { - byte[] addr = destinationAddress.clone(); - addr[5] = (byte)~addr[5]; - return addr; - } - - /** - * Return an ethernet type that does not match this packet. - * - * @return An ethernet type that does not match this packet. - */ - public int getAnotherEtherType() { - return (~etherType) & 0xffff; - } - - /** - * Return a VLAN ID that does not match this packet. - * - * @return A VLAN ID that does not match this packet. - */ - public short getAnotherVlanId() { - if (vlanId == MatchType.DL_VLAN_NONE) { - return (short)4095; - } - - short vid = (short)(~vlanId & 0xfff); - if (vid == MatchType.DL_VLAN_NONE) { - vid = 1; - } - - return vid; - } - - /** - * Return a VLAN priority that does not match this packet. - * - * @return A VLAN priority that does not match this packet. - */ - public byte getAnotherVlanPcp() { - if (vlanId == MatchType.DL_VLAN_NONE) { - return -1; - } - - return (byte)((vlanPcp + 1) & 0x7); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImplTest.java deleted file mode 100644 index 88f5ae01..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowCondImplTest.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.io.File; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.TreeMap; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; -import org.opendaylight.vtn.manager.flow.cond.FlowCondition; -import org.opendaylight.vtn.manager.flow.cond.FlowMatch; -import org.opendaylight.vtn.manager.flow.cond.Inet4Match; -import org.opendaylight.vtn.manager.flow.cond.TcpMatch; - -import org.opendaylight.vtn.manager.internal.ContainerConfig; -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; - -import org.opendaylight.vtn.manager.internal.DataGenerator; -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.core.UpdateType; -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.ICMP; -import org.opendaylight.controller.sal.packet.IPv4; -import org.opendaylight.controller.sal.packet.TCP; -import org.opendaylight.controller.sal.packet.UDP; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.GlobalConstants; -import org.opendaylight.controller.sal.utils.IPProtocols; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link FlowCondImpl}. - */ -public class FlowCondImplTest extends TestBase { - /** - * Test case for basic methods. - * - * @throws VTNException An error occurred. - */ - @Test - public void testBasic() throws VTNException { - VTNManagerImpl mgr = getVTNManager(); - ContainerConfig cfg = new ContainerConfig(mgr.getContainerName()); - cfg.init(); - - // Create an empty flow condition. - String name = "flow_condition"; - FlowCondImpl fci = new FlowCondImpl(name, null); - FlowCondition fc = new FlowCondition(name, null); - assertEquals(name, fci.getName()); - assertEquals(fc, fci.getFlowCondition()); - serializeTest(fci); - for (int idx = 0; idx <= 10; idx++) { - assertEquals(null, fci.getMatch(idx)); - assertEquals(null, fci.removeMatch(idx)); - - FlowCondImpl copy = fci.clone(); - assertNotSame(fci, copy); - assertNotSame(copy, fci.clone()); - assertEquals(fci, copy); - assertEquals(name, copy.getName()); - assertEquals(fc, copy.getFlowCondition()); - assertEquals(null, copy.getMatch(idx)); - assertEquals(null, copy.removeMatch(idx)); - } - - File path = getPath(name); - Status st = fci.saveConfig(mgr); - assertTrue(st.isSuccess()); - assertTrue(path.isFile()); - assertEquals(fci, cfg.load(ContainerConfig.Type.FLOWCOND, name)); - fci.destroy(mgr); - assertFalse(path.isFile()); - - // Configure FlowMatch. - Map map = FlowMatchImplTest.createFlowMatches(); - int index = 1; - boolean first = true; - FlowMatchImpl fmi = null; - for (Map.Entry entry: map.entrySet()) { - FlowMatch key = entry.getKey(); - FlowMatch value = entry.getValue(); - FlowMatch fm = key.assignIndex(index); - FlowMatch expected = value.assignIndex(index); - fmi = new FlowMatchImpl(expected); - UpdateType result = fci.setMatch(fm); - if (first) { - assertEquals(UpdateType.ADDED, result); - } else { - assertEquals(UpdateType.CHANGED, result); - } - first = false; - - assertEquals(null, fci.setMatch(fm)); - - assertEquals(expected, fci.getMatch(index)); - ArrayList matches = new ArrayList(); - matches.add(expected); - fc = new FlowCondition(name, matches); - assertEquals(fc, fci.getFlowCondition()); - serializeTest(fci); - - FlowCondImpl copy = fci.clone(); - assertNotSame(fci, copy); - assertNotSame(copy, fci.clone()); - assertEquals(fci, copy); - assertEquals(name, copy.getName()); - assertEquals(fc, copy.getFlowCondition()); - assertEquals(expected, copy.getMatch(index)); - - st = fci.saveConfig(mgr); - assertTrue(st.isSuccess()); - assertTrue(path.isFile()); - assertEquals(fci, cfg.load(ContainerConfig.Type.FLOWCOND, name)); - fci.destroy(mgr); - assertFalse(path.isFile()); - } - - assertEquals(fmi, fci.removeMatch(index)); - - // Configure all matches into one flow condition. - LinkedList matchList = new LinkedList(); - ArrayList expectedList = new ArrayList(); - for (Map.Entry entry: map.entrySet()) { - FlowMatch key = entry.getKey(); - FlowMatch value = entry.getValue(); - FlowMatch fm = key.assignIndex(index); - FlowMatch expected = value.assignIndex(index); - expectedList.add(expected); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - assertEquals(null, fci.setMatch(fm)); - index += 13; - - // Reverse order of match list. - matchList.addFirst(fm); - } - - FlowCondition expectedCond = new FlowCondition(name, expectedList); - assertEquals(expectedCond, fci.getFlowCondition()); - serializeTest(fci); - - FlowCondImpl copy = fci.clone(); - assertNotSame(fci, copy); - assertNotSame(copy, fci.clone()); - assertEquals(fci, copy); - assertEquals(name, copy.getName()); - assertEquals(expectedCond, copy.getFlowCondition()); - - st = fci.saveConfig(mgr); - assertTrue(st.isSuccess()); - assertTrue(path.isFile()); - assertEquals(fci, cfg.load(ContainerConfig.Type.FLOWCOND, name)); - fci.destroy(mgr); - assertFalse(path.isFile()); - - for (FlowMatch fm: expectedList) { - int idx = fm.getIndex().intValue(); - assertEquals(fm, fci.getMatch(idx)); - } - for (int i = 1; i <= 10; i++) { - int idx = index + i; - assertEquals(null, fci.getMatch(idx)); - assertEquals(null, fci.removeMatch(idx)); - - idx = 1 - i; - assertEquals(null, fci.getMatch(idx)); - assertEquals(null, fci.removeMatch(idx)); - } - - // Create another flow condition that has the same contents. - fc = new FlowCondition(null, matchList); - FlowCondImpl fci1 = new FlowCondImpl(name, fc); - assertEquals(name, fci1.getName()); - assertEquals(expectedCond, fci1.getFlowCondition()); - assertEquals(fci, fci1); - assertFalse(fci1.setMatches(matchList)); - assertFalse(fci1.setMatches(expectedList)); - - // Remove all flow matches in fci1. - for (FlowMatch fm: expectedList) { - int idx = fm.getIndex().intValue(); - fmi = new FlowMatchImpl(fm); - assertEquals(fm, fci1.getMatch(idx)); - assertEquals(fmi, fci1.removeMatch(idx)); - assertEquals(null, fci1.removeMatch(idx)); - assertEquals(null, fci1.getMatch(idx)); - } - - // Restore all flow matches. - assertTrue(fci1.setMatches(matchList)); - assertFalse(fci1.setMatches(expectedList)); - assertEquals(name, fci1.getName()); - assertEquals(expectedCond, fci1.getFlowCondition()); - assertEquals(fci, fci1); - - // Specify duplicated index. - LinkedList badList = new LinkedList(matchList); - FlowMatch dup1 = badList.getFirst(); - int duplicate = dup1.getIndex().intValue(); - FlowMatch dup2 = badList.removeLast(); - assertNotSame(dup1, dup2); - badList.addLast(dup2.assignIndex(duplicate)); - try { - new FlowCondImpl(name, new FlowCondition(null, badList)); - unexpected(); - } catch (VTNException e) { - st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Duplicate match index: " + duplicate, - st.getDescription()); - } - - try { - fci1.setMatches(badList); - unexpected(); - } catch (VTNException e) { - st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Duplicate match index: " + duplicate, - st.getDescription()); - } - - assertEquals(name, fci1.getName()); - assertEquals(expectedCond, fci1.getFlowCondition()); - assertEquals(fci, fci1); - } - - /** - * Test case for {@link FlowCondImpl#equals(Object)} and - * {@link FlowCondImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - - String[] names = {"name_1", "name_2", "cond_1"}; - Map map = FlowMatchImplTest.createFlowMatches(); - ArrayList matchList = new ArrayList(); - int index = 1; - int count = 0; - for (FlowMatch key: map.keySet()) { - FlowMatch fm = key.assignIndex(index); - index++; - ArrayList l = new ArrayList(); - l.add(fm); - matchList.add(fm); - for (String name: names) { - FlowCondition fc = new FlowCondition(null, l); - FlowCondImpl fci1 = new FlowCondImpl(name, fc); - FlowCondImpl fci2 = new FlowCondImpl(copy(name), fc); - testEquals(set, fci1, fci2); - count++; - - if (matchList.size() > 1) { - fc = new FlowCondition(null, matchList); - fci1 = new FlowCondImpl(name, fc); - fci2 = new FlowCondImpl(copy(name), fc); - testEquals(set, fci1, fci2); - count++; - } - } - } - - for (String name: names) { - FlowCondition fc = new FlowCondition(null, null); - FlowCondImpl fci1 = new FlowCondImpl(name, fc); - FlowCondImpl fci2 = new FlowCondImpl(copy(name), fc); - testEquals(set, fci1, fci2); - count++; - } - - assertEquals(count, set.size()); - } - - /** - * Test case for {@link FlowCondImpl#toString()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testToString() throws VTNException { - String prefix = "FlowCondImpl["; - String suffix = "]"; - - String[] names = {"name_1", "name_2", "cond_1"}; - Map map = FlowMatchImplTest.createFlowMatches(); - for (String name: names) { - TreeMap matches = - new TreeMap(); - String n = "name=" + name; - String m = "matches=" + matches.values(); - FlowCondImpl fci = new FlowCondImpl(name, null); - String required = joinStrings(prefix, suffix, ",", n, m); - assertEquals(required, fci.toString()); - - int index = 1; - for (Map.Entry entry: map.entrySet()) { - FlowMatch key = entry.getKey(); - FlowMatch value = entry.getValue(); - FlowMatch fm = key.assignIndex(index); - FlowMatch expected = value.assignIndex(index); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - matches.put(index, new FlowMatchImpl(expected)); - m = "matches=" + matches.values(); - required = joinStrings(prefix, suffix, ",", n, m); - assertEquals(required, fci.toString()); - index++; - } - } - } - - /** - * Test case for - * {@link FlowCondImpl#match(VTNManagerImpl mgr, PacketContext pctx)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - // Create an empty flow condition. - FlowCondImpl empty = new FlowCondImpl("empty", null); - - // Create a flow condition. - FlowCondImpl fci = new FlowCondImpl("empty", null); - - // 10000: IP DSCP == 35 - byte dscp = 35; - Inet4MatchImplBuilder inet4Builder = new Inet4MatchImplBuilder(); - Inet4Match im = inet4Builder.setDscp(dscp).getInet4Match(); - FlowMatch fm = new FlowMatch(10000, null, im, null); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - - // 10: ether type == 0x1234 - int ethType = 0x1234; - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - EthernetMatch em = ethBuilder.reset().setEtherType(ethType). - getEthernetMatch(); - fm = new FlowMatch(10, em, null, null); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - - // 1500: TCP dst port 1000-2000 - TcpMatchImplBuilder tcpBuilder = new TcpMatchImplBuilder(); - short dstFrom = 1000; - short dstTo = 2000; - TcpMatch tm = tcpBuilder.setDestinationPortFrom(dstFrom). - setDestinationPortTo(dstTo).getTcpMatch(); - fm = new FlowMatch(1500, null, null, tm); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - - // 300: Source MAC == mac1 && VLAN ID == 3 - DataGenerator gen = new DataGenerator(); - byte[] mac1 = gen.getMacAddress(); - short vlan = 3; - em = ethBuilder.reset().setSourceAddress(mac1).setVlanId(vlan). - getEthernetMatch(); - fm = new FlowMatch(300, em, null, null); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - - // 150: Source IP address in 192.168.233.0/24 - im = inet4Builder.reset().setSourceAddress("192.168.233.0"). - setSourceSuffix((short)24).getInet4Match(); - fm = new FlowMatch(150, null, im, null); - assertEquals(UpdateType.ADDED, fci.setMatch(fm)); - - // Create an untagged Ethernet frame with type 0x5555. - byte[] payload = { - (byte)0xf4, (byte)0xec, (byte)0x8b, (byte)0x72, - (byte)0x67, (byte)0x43, (byte)0x5e, (byte)0x20, - (byte)0x28, (byte)0xc9, (byte)0x0f, (byte)0x7c, - }; - - byte[] mac2 = gen.getMacAddress(); - byte[] mac3 = gen.getMacAddress(); - Ethernet ether = createEthernet(mac2, mac3, 0x5555, - MatchType.DL_VLAN_NONE, (byte)0, - payload); - - // Empty flow condition should match every packet. - PacketMatchTest test = new PacketMatchTest(); - VTNManagerImpl mgr = getVTNManager(); - assertEquals(true, test.run(mgr, empty, ether)); - - // This packet should not be matched. - test.setMatchType(MatchType.DL_TYPE, MatchType.DL_SRC); - assertEquals(false, test.run(mgr, fci, ether)); - - // Create an Ethernet frame with VLAN tag(vid=10) and type 0x1234. - // FlowMatch at index 10 should match this packet. - ether = createEthernet(mac2, mac3, ethType, (short)10, (byte)0, - payload); - assertEquals(true, test.reset().run(mgr, empty, ether)); - test.setMatchType(MatchType.DL_TYPE); - assertEquals(true, test.run(mgr, fci, ether)); - - // Create an Ethernet frame to be matched by FlowMatch at index 300. - ether = createEthernet(mac1, mac3, 0x3333, vlan, (byte)0, payload); - assertEquals(true, test.reset().run(mgr, empty, ether)); - test.setMatchType(MatchType.DL_TYPE, MatchType.DL_SRC); - assertEquals(true, test.run(mgr, fci, ether)); - - // Create an UDP packet to be matched by FlowMatch at index 10000. - UDP udp = new UDP(); - udp.setSourcePort((short)gen.getPort()). - setDestinationPort((short)gen.getPort()). - setLength((short)123).setChecksum((short)0x3333). - setRawPayload(payload); - InetAddress ipaddr1 = gen.getInetAddress(); - InetAddress ipaddr2 = gen.getInetAddress(); - IPv4 ipv4 = createIPv4(ipaddr1, ipaddr2, IPProtocols.UDP.shortValue(), - dscp); - ipv4.setPayload(udp); - ether = createEthernet(mac2, mac3, EtherTypes.IPv4.intValue(), - (short)4095, (byte)2, ipv4); - assertEquals(true, test.reset().run(mgr, empty, ether)); - test.setMatchType(MatchType.DL_TYPE, MatchType.DL_SRC, - MatchType.NW_SRC, MatchType.NW_PROTO, - MatchType.NW_TOS); - assertEquals(true, test.run(mgr, fci, ether)); - - // Change DSCP so that the packet is not be matched. - ipv4 = createIPv4(ipaddr1, ipaddr2, IPProtocols.UDP.shortValue(), - (byte)(dscp + 1)); - ipv4.setPayload(udp); - ether = createEthernet(mac2, mac3, EtherTypes.IPv4.intValue(), - (short)4095, (byte)2, ipv4); - assertEquals(true, test.reset().run(mgr, empty, ether)); - test.setMatchType(MatchType.DL_TYPE, MatchType.DL_SRC, - MatchType.NW_SRC, MatchType.NW_PROTO, - MatchType.NW_TOS); - assertEquals(false, test.run(mgr, fci, ether)); - - // Create an ICMP packet to be matched by FlowMatch at index 150. - InetAddress inetSrc = InetAddress.getByName("192.168.233.98"); - ICMP icmp = new ICMP(); - icmp.setType((byte)gen.getPort()).setCode((byte)gen.getPort()). - setIdentifier((short)0x1234).setSequenceNumber((short)0x5678). - setRawPayload(payload); - ipv4 = createIPv4(inetSrc, ipaddr2, IPProtocols.ICMP.shortValue(), - dscp); - ipv4.setPayload(icmp); - ether = createEthernet(mac2, mac3, EtherTypes.IPv4.intValue(), - (short)30, (byte)1, ipv4); - assertEquals(true, test.reset().run(mgr, empty, ether)); - test.setMatchType(MatchType.DL_TYPE, MatchType.NW_SRC); - assertEquals(true, test.run(mgr, fci, ether)); - - // Create a TCP packet. - short[] ports = { - (short)(dstFrom - 1), - dstFrom, - (short)(dstFrom + ((dstTo - dstFrom) >> 1)), - dstTo, - (short)(dstTo + 1), - }; - for (short port: ports) { - TCP tcp = new TCP(); - tcp.setSourcePort((short)gen.getPort()).setDestinationPort(port). - setSequenceNumber(0x12345).setAckNumber(0x23456). - setDataOffset((byte)1).setHeaderLenFlags((short)0x18). - setReserved((byte)0).setWindowSize((short)1500). - setChecksum((short)0x9999).setRawPayload(payload); - ipv4 = createIPv4(ipaddr1, ipaddr2, IPProtocols.TCP.shortValue(), - dscp); - ipv4.setPayload(tcp); - ether = createEthernet(mac2, mac3, EtherTypes.IPv4.intValue(), - (short)30, (byte)1, ipv4); - assertEquals(true, test.reset().run(mgr, empty, ether)); - - test.setMatchType(MatchType.DL_TYPE, MatchType.DL_SRC, - MatchType.NW_SRC, MatchType.NW_PROTO, - MatchType.TP_DST); - - // If the destination port is in range [1000, 2000], the FlowMatch - // at index 1500 should match the packet. - // Otherwise the last FlowMatch should match the packet. - if (port < dstFrom || port > dstTo) { - test.setMatchType(MatchType.NW_TOS); - } - assertEquals(true, test.run(mgr, fci, ether)); - } - - // Create a TCP packet that should not be mached. - TCP tcp = new TCP(); - tcp.setSourcePort((short)gen.getPort()). - setDestinationPort((short)(dstTo + 1)). - setSequenceNumber(0x12345).setAckNumber(0x23456). - setDataOffset((byte)1).setHeaderLenFlags((short)0x18). - setReserved((byte)0).setWindowSize((short)1500). - setChecksum((short)0x9999).setRawPayload(payload); - ipv4 = createIPv4(ipaddr1, ipaddr2, IPProtocols.TCP.shortValue(), - (byte)(dscp + 1)); - ipv4.setPayload(tcp); - ether = createEthernet(mac2, mac3, EtherTypes.IPv4.intValue(), - (short)30, (byte)1, ipv4); - assertEquals(true, test.reset().run(mgr, empty, ether)); - - test.setMatchType(MatchType.DL_TYPE, MatchType.DL_SRC, - MatchType.NW_SRC, MatchType.NW_PROTO, - MatchType.NW_TOS, MatchType.TP_DST); - assertEquals(false, test.run(mgr, fci, ether)); - } - - /** - * Create VTN Manager instance for test. - * - * @return {@link VTNManagerImpl} instance. - */ - private VTNManagerImpl getVTNManager() { - return new VTNManagerImpl() { - @Override - public String getContainerName() { - return GlobalConstants.DEFAULT.toString(); - } - }; - } - - /** - * Return a path to the configuration file corresponding to the - * specified flow condition. - * - * @param name The name of the flow condition. - * @return A {@link File} instance associated with the configuration file - * of the flow condition. - */ - private File getPath(String name) { - String base = GlobalConstants.STARTUPHOME.toString(); - File parent = new File(base, GlobalConstants.DEFAULT.toString()); - parent = new File(parent, "vtn"); - parent = new File(parent, "FLOWCOND"); - return new File(parent, name + ".conf"); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEventTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEventTest.java deleted file mode 100644 index a5263e87..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowConditionEventTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import org.junit.Test; -import org.opendaylight.vtn.manager.internal.TestBase; -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; -import org.opendaylight.controller.sal.core.UpdateType; - -/** - * JUnit test for {@link FlowConditionEvent}. - */ -public class FlowConditionEventTest extends TestBase { - - /** - * Junit for FlowConditionEvent method. - */ - @Test - public void testRaise() { - //Checking for all the scenarios for raise method in FlowConditionEvent. - for (String tenantName : TENANT_NAME) { - for (UpdateType updateTye: updateTypeList()) { - for (VTNManagerImpl mgr: createVtnManagerImplobj()) { - try { - FlowConditionEvent.raise(mgr, tenantName, updateTye); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - } - } - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImplTest.java deleted file mode 100644 index 40e9eef9..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowMatchImplTest.java +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; -import org.opendaylight.vtn.manager.flow.cond.FlowMatch; -import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; -import org.opendaylight.vtn.manager.flow.cond.Inet4Match; -import org.opendaylight.vtn.manager.flow.cond.InetMatch; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.flow.cond.TcpMatch; -import org.opendaylight.vtn.manager.flow.cond.UdpMatch; - -import org.opendaylight.vtn.manager.internal.DataGenerator; -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.ICMP; -import org.opendaylight.controller.sal.packet.IPv4; -import org.opendaylight.controller.sal.packet.Packet; -import org.opendaylight.controller.sal.packet.TCP; -import org.opendaylight.controller.sal.packet.UDP; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.IPProtocols; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link FlowMatchImpl}. - */ -public class FlowMatchImplTest extends TestBase { - - /** - * Create a map that contains {@link FlowMatch} instances. - * - *

- * An instance of {@link FlowMatch} to be passed to the constructor of - * {@link FlowMatchImpl} is set as a key, and an instance of - * {@link FlowMatch} instances to be returned by the call of - * {@link FlowMatchImpl#getMatch()} is set as a value. - *

- * - * @return A map that contains {@link FlowMatch} instances. - */ - public static Map createFlowMatches() { - Map map = new HashMap(); - FlowMatch fm = new FlowMatch(null, null, null); - map.put(fm, fm); - - // Specify EthernetMatch. - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - EthernetMatch em = ethBuilder.reset(). - setSourceAddress(0x000102030405L). - setDestinationAddress(0xf0f1f2f3f4f5L).setVlanId((short)0). - getEthernetMatch(); - fm = new FlowMatch(em, null, null); - map.put(fm, fm); - - em = ethBuilder.reset().setSourceAddress(0xa83401bf34ceL). - setDestinationAddress(0x00abcdef1234L).setEtherType(0x800). - setVlanId((short)4095).setVlanPriority((byte)7).getEthernetMatch(); - fm = new FlowMatch(em, null, null); - map.put(fm, fm); - - // Specify Inet4Match. - Inet4MatchImplBuilder inet4Builder = new Inet4MatchImplBuilder(); - Inet4Match im = inet4Builder.getInet4Match(); - fm = new FlowMatch(null, im, null); - - // Ethernet type will be configured. - em = ethBuilder.reset().setEtherType(EtherTypes.IPv4.intValue()). - getEthernetMatch(); - FlowMatch expected = new FlowMatch(em, im, null); - map.put(fm, expected); - - im = inet4Builder.setDscp((byte)41).getInet4Match(); - fm = new FlowMatch(null, im, null); - expected = new FlowMatch(em, im, null); - map.put(fm, expected); - - em = ethBuilder.setSourceAddress(0x3873cad23847L).setVlanId((short)3). - getEthernetMatch(); - im = inet4Builder.reset(). - setSourceAddress("192.168.100.255").setSourceSuffix((short)25). - setDestinationAddress("203.198.39.255"). - setDestinationSuffix((short)23).setProtocol((short)123). - setDscp((byte)45).getInet4Match(); - fm = new FlowMatch(em, im, null); - expected = new FlowMatch(em, inet4Builder.getExpectedInet4Match(), - null); - map.put(fm, expected); - - // Specify TcpMatch. - TcpMatchImplBuilder tcpBuilder = new TcpMatchImplBuilder(); - TcpMatch tm = tcpBuilder.getTcpMatch(); - fm = new FlowMatch(null, null, tm); - - // Ethernet type and IP protocol will be configured. - em = ethBuilder.reset().setEtherType(EtherTypes.IPv4.intValue()). - getEthernetMatch(); - im = inet4Builder.reset().setProtocol(IPProtocols.TCP.shortValue()). - getInet4Match(); - expected = new FlowMatch(em, im, tm); - map.put(fm, expected); - - tm = tcpBuilder.setSourcePortFrom(35).setDestinationPortFrom(987). - getTcpMatch(); - fm = new FlowMatch(null, null, tm); - expected = new FlowMatch(em, im, tm); - map.put(fm, expected); - - em = ethBuilder.setSourceAddress(0x043e1eb0e32cL). - setDestinationAddress(0xc8ff32f9e7feL).setVlanId((short)123). - setVlanPriority((byte)4).getEthernetMatch(); - im = inet4Builder.setSourceAddress("10.20.30.45"). - setDestinationAddress("192.168.90.100").setDscp((byte)0). - getInet4Match(); - tm = tcpBuilder.reset(). - setSourcePortFrom(100).setSourcePortTo(101). - setDestinationPortFrom(30000).setDestinationPortTo(40000). - getTcpMatch(); - fm = new FlowMatch(em, im, tm); - map.put(fm, fm); - - // Specify UdpMatch. - UdpMatchImplBuilder udpBuilder = new UdpMatchImplBuilder(); - UdpMatch um = udpBuilder.getUdpMatch(); - fm = new FlowMatch(null, null, um); - - // Ethernet type and IP protocol will be configured. - em = ethBuilder.reset().setEtherType(EtherTypes.IPv4.intValue()). - getEthernetMatch(); - im = inet4Builder.reset().setProtocol(IPProtocols.UDP.shortValue()). - getInet4Match(); - expected = new FlowMatch(em, im, um); - map.put(fm, expected); - - um = udpBuilder.setSourcePortFrom(999).setDestinationPortFrom(64321). - getUdpMatch(); - fm = new FlowMatch(null, null, um); - expected = new FlowMatch(em, im, um); - map.put(fm, expected); - - em = ethBuilder.setSourceAddress(0xfc086b487935L).setVlanId((short)19). - getEthernetMatch(); - im = inet4Builder.setDestinationAddress("123.234.56.78"). - getInet4Match(); - um = udpBuilder.reset(). - setSourcePortFrom(12345).setSourcePortTo(20000). - setDestinationPortFrom(50).setDestinationPortTo(60).getUdpMatch(); - fm = new FlowMatch(em, im, um); - map.put(fm, fm); - - // Specify IcmpMatch. - IcmpMatchImplBuilder icmpBuilder = new IcmpMatchImplBuilder(); - IcmpMatch icm = icmpBuilder.getIcmpMatch(); - fm = new FlowMatch(null, null, icm); - - // Ethernet type and IP protocol will be configured. - em = ethBuilder.reset().setEtherType(EtherTypes.IPv4.intValue()). - getEthernetMatch(); - im = inet4Builder.reset().setProtocol(IPProtocols.ICMP.shortValue()). - getInet4Match(); - expected = new FlowMatch(em, im, icm); - map.put(fm, expected); - - icm = icmpBuilder.setType((short)0).setCode((short)0). - getIcmpMatch(); - fm = new FlowMatch(null, null, icm); - expected = new FlowMatch(em, im, icm); - map.put(fm, expected); - - em = ethBuilder.setVlanId((short)159).setVlanPriority((byte)6). - getEthernetMatch(); - im = inet4Builder.setSourceAddress("10.245.32.189"). - setSourceSuffix((short)28). - setDestinationAddress("192.168.195.209"). - setDestinationSuffix((short)31).setDscp((byte)49). - getInet4Match(); - icm = icmpBuilder.reset().setType((short)123).setCode((short)91). - getIcmpMatch(); - fm = new FlowMatch(em, im, icm); - expected = new FlowMatch(em, inet4Builder.getExpectedInet4Match(), - icm); - map.put(fm, expected); - - return map; - } - - /** - * Test for {@link FlowMatchImpl#FlowMatchImpl(FlowMatch)}, - * {@link InetMatchImpl#create(InetMatch)}, and getter methods.n - * - * @throws VTNException An error occurred. - */ - @Test - public void testConstructor() throws VTNException { - int[] indices = {1, 100, 256, 1000, 40000, 65535}; - Map map = createFlowMatches(); - - FlowMatch fmatch = null; - for (Map.Entry entry: map.entrySet()) { - FlowMatch key = entry.getKey(); - FlowMatch value = entry.getValue(); - fmatch = key; - for (int index: indices) { - FlowMatch fm = key.assignIndex(index); - FlowMatch expected = value.assignIndex(index); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - assertEquals(index, fmi.getIndex()); - assertEquals(expected, fmi.getMatch()); - } - } - - assertNotNull(fmatch); - - // Pass null. - try { - new FlowMatchImpl(null); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Flow match cannot be null", st.getDescription()); - } - - // No index is assigned. - try { - new FlowMatchImpl(fmatch); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Match index cannot be null", st.getDescription()); - } - - // Invalid index is specified. - int[] badIndices = { - Integer.MIN_VALUE, -3, -2, -1, 0, - 65536, 65537, 1000000, 20000000, Integer.MAX_VALUE, - }; - for (int index: badIndices) { - FlowMatch fm = fmatch.assignIndex(index); - try { - new FlowMatchImpl(fm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid match index: " + index, - st.getDescription()); - } - } - - // Unexpecetd ethenet type. - int ethType = 0x86dd; - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - EthernetMatch em = ethBuilder.setEtherType(ethType).getEthernetMatch(); - Inet4MatchImplBuilder inet4Builder = new Inet4MatchImplBuilder(); - Inet4Match im = inet4Builder.getInet4Match(); - FlowMatch fm = new FlowMatch(1, em, im, null); - try { - new FlowMatchImpl(fm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Ethernet type conflict: type=0x" + - Integer.toHexString(ethType) + ", expected=0x" + - Integer.toHexString(EtherTypes.IPv4.intValue()), - st.getDescription()); - } - - // Unexpected IP protocol type. - short proto = IPProtocols.UDP.shortValue(); - im = inet4Builder.setProtocol(proto).getInet4Match(); - TcpMatchImplBuilder tcpBuilder = new TcpMatchImplBuilder(); - L4Match lm = tcpBuilder.getTcpMatch(); - fm = new FlowMatch(1, null, im, lm); - try { - new FlowMatchImpl(fm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("IP protocol conflict: proto=" + proto + - ", expected=" + IPProtocols.TCP.intValue(), - st.getDescription()); - } - - proto = IPProtocols.EGP.shortValue(); - im = inet4Builder.setProtocol(proto).getInet4Match(); - UdpMatchImplBuilder udpBuilder = new UdpMatchImplBuilder(); - lm = udpBuilder.getUdpMatch(); - fm = new FlowMatch(1, null, im, lm); - try { - new FlowMatchImpl(fm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("IP protocol conflict: proto=" + proto + - ", expected=" + IPProtocols.UDP.intValue(), - st.getDescription()); - } - - proto = IPProtocols.TCP.shortValue(); - im = inet4Builder.setProtocol(proto).getInet4Match(); - IcmpMatchImplBuilder icmpBuilder = new IcmpMatchImplBuilder(); - lm = icmpBuilder.getIcmpMatch(); - fm = new FlowMatch(1, null, im, lm); - try { - new FlowMatchImpl(fm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("IP protocol conflict: proto=" + proto + - ", expected=" + IPProtocols.ICMP.intValue(), - st.getDescription()); - } - } - - /** - * Test case for {@link FlowMatchImpl#equals(Object)} and - * {@link FlowMatchImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - - int[] indices = {1, 100, 256, 1000, 40000, 65535}; - Map map = createFlowMatches(); - for (FlowMatch fmatch: map.keySet()) { - for (int index: indices) { - FlowMatch fm = fmatch.assignIndex(index); - FlowMatchImpl fmi1 = new FlowMatchImpl(fm); - FlowMatchImpl fmi2 = new FlowMatchImpl(fm); - testEquals(set, fmi1, fmi2); - } - } - - assertEquals(map.size() * indices.length, set.size()); - } - - /** - * Test case for {@link FlowMatchImpl#toString()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testToString() throws VTNException { - String prefix = "FlowMatchImpl["; - String suffix = "]"; - - int[] indices = {1, 100, 256, 1000, 40000, 65535}; - Map map = createFlowMatches(); - for (Map.Entry entry: map.entrySet()) { - FlowMatch key = entry.getKey(); - FlowMatch value = entry.getValue(); - for (int index: indices) { - FlowMatch fm = key.assignIndex(index); - FlowMatch expected = value.assignIndex(index); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - - EthernetMatch em = expected.getEthernetMatch(); - InetMatch im = expected.getInetMatch(); - L4Match lm = expected.getLayer4Match(); - - String idx = "index=" + index; - String e = (em == null) ? null - : "ether=" + new EthernetMatchImpl(em); - String i = (im == null) ? null - : "inet=" + new Inet4MatchImpl(im); - String l; - if (lm == null) { - l = null; - } else if (lm instanceof TcpMatch) { - l = "L4=" + new TcpMatchImpl((TcpMatch)lm); - } else if (lm instanceof UdpMatch) { - l = "L4=" + new UdpMatchImpl((UdpMatch)lm); - } else { - l = "L4=" + new IcmpMatchImpl((IcmpMatch)lm); - } - - String required = joinStrings(prefix, suffix, ",", idx, - e, i, l); - assertEquals(required, fmi.toString()); - } - } - } - - /** - * Ensure that {@link FlowMatchImpl} is serializable. - * - * @throws VTNException An error occurred. - */ - @Test - public void testSerialize() throws VTNException { - int[] indices = {1, 100, 256, 1000, 40000, 65535}; - Map map = createFlowMatches(); - for (FlowMatch fmatch: map.keySet()) { - for (int index: indices) { - FlowMatch fm = fmatch.assignIndex(index); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - serializeTest(fmi); - } - } - } - - /** - * Test case for {@link FlowMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - DataGenerator gen = new DataGenerator(); - ArrayList ipPackets = new ArrayList(); - byte[] payload = { - (byte)0xa8, (byte)0xa6, (byte)0x94, (byte)0xd4, - (byte)0x46, (byte)0xe2, (byte)0x08, (byte)0xe0, - (byte)0x78, (byte)0x4e, (byte)0x5e, (byte)0xf4, - }; - - TCP tcp = new TCP(); - tcp.setSourcePort((short)gen.getPort()). - setDestinationPort((short)gen.getPort()). - setSequenceNumber(0x12345).setAckNumber(0x23456). - setDataOffset((byte)1).setHeaderLenFlags((short)0x18). - setReserved((byte)0).setWindowSize((short)1500). - setChecksum((short)0x9999).setRawPayload(payload); - IPv4 ipv4 = createIPv4(gen.getInetAddress(), gen.getInetAddress(), - IPProtocols.TCP.shortValue(), (byte)0); - ipv4.setPayload(tcp); - ipPackets.add(ipv4); - - UDP udp = new UDP(); - udp.setSourcePort((short)gen.getPort()). - setDestinationPort((short)gen.getPort()). - setLength((short)123).setChecksum((short)0x3333). - setRawPayload(payload); - ipv4 = createIPv4(gen.getInetAddress(), gen.getInetAddress(), - IPProtocols.UDP.shortValue(), (byte)1); - ipv4.setPayload(udp); - ipPackets.add(ipv4); - - ICMP icmp = new ICMP(); - icmp.setType((byte)gen.getPort()).setCode((byte)gen.getPort()). - setIdentifier((short)0x1234).setSequenceNumber((short)0x5678). - setRawPayload(payload); - ipv4 = createIPv4(gen.getInetAddress(), gen.getInetAddress(), - IPProtocols.ICMP.shortValue(), (byte)2); - ipv4.setPayload(icmp); - ipPackets.add(ipv4); - - ipv4 = createIPv4(gen.getInetAddress(), gen.getInetAddress(), - (short)123, (byte)3); - ipv4.setRawPayload(payload); - ipPackets.add(ipv4); - - ipv4 = createIPv4(gen.getInetAddress(), gen.getInetAddress(), - IPProtocols.TCP.shortValue(), (byte)4); - ipv4.setFragmentOffset((short)123); - ipv4.setRawPayload(payload); - ipPackets.add(ipv4); - - ArrayList etherPackets = new ArrayList(); - short[] vlans = { - MatchType.DL_VLAN_NONE, 1, 10, 4095, - }; - - byte pcp = 0; - for (short vlan: vlans) { - // Unsupported packet. - Ethernet ether = createEthernet( - gen.getMacAddress(), gen.getMacAddress(), 0x4444, vlan, pcp, - payload); - etherPackets.add(ether); - pcp = (byte)((pcp + 1) & 0x7); - - // ARP packet. - ether = createEthernet(gen.getMacAddress(), gen.getMacAddress(), - EtherTypes.ARP.intValue(), vlan, pcp, - PacketMatchTest.ARP_PACKET); - etherPackets.add(ether); - pcp = (byte)((pcp + 1) & 0x7); - - // IPv4 packets. - for (IPv4 pkt: ipPackets) { - ether = createEthernet(gen.getMacAddress(), - gen.getMacAddress(), - EtherTypes.IPv4.intValue(), vlan, pcp, - pkt); - etherPackets.add(ether); - pcp = (byte)((pcp + 1) & 0x7); - } - } - - PacketMatchTest test = new PacketMatchTest(); - List empties = getEmptyMatches(); - for (Ethernet ether: etherPackets) { - // Empty condition should match every packet. - for (FlowMatchImpl fmi: empties) { - assertEquals(true, test.run(fmi, ether)); - } - - ethernetMatchTest(ether); - ipv4MatchTest(ether); - layer4MatchTest(ether); - } - } - - /** - * Create a list of empty {@link FlowMatchImpl} instances. - * - * @return A list of empty {@link FlowMatchImpl} instances. - * @throws VTNException An error occurred. - */ - private List getEmptyMatches() throws VTNException { - ArrayList empty = new ArrayList(); - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - EthernetMatch em = ethBuilder.getEthernetMatch(); - - empty.add(new FlowMatchImpl(new FlowMatch(1, null, null, null))); - empty.add(new FlowMatchImpl(new FlowMatch(2, em, null, null))); - - return empty; - } - - /** - * Test ethernet matches. - * - * @param pkt An {@link Ethernet} instance for test. - * @throws VTNException An error occurred. - */ - private void ethernetMatchTest(Ethernet pkt) throws VTNException { - EthernetParser ethParser = new EthernetParser(pkt); - byte[] src = ethParser.getSourceAddress(); - byte[] dst = ethParser.getDestinationAddress(); - int type = ethParser.getEtherType(); - short vlan = ethParser.getVlanId(); - byte pcp = ethParser.getVlanPcp(); - - byte[] anotherSrc = ethParser.getAnotherSourceAddress(); - byte[] anotherDst = ethParser.getAnotherDestinationAddress(); - int anotherType = ethParser.getAnotherEtherType(); - short anotherVlan = ethParser.getAnotherVlanId(); - byte anotherPcp = ethParser.getAnotherVlanPcp(); - - PacketMatchTest test = new PacketMatchTest(); - - // Create flow match that specifies all Ethernet header fields. - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - ethBuilder.setSourceAddress(src).setDestinationAddress(dst). - setEtherType(type).setVlanId(vlan); - test.reset().setMatchType(MatchType.DL_SRC, MatchType.DL_DST, - MatchType.DL_TYPE); - if (vlan != MatchType.DL_VLAN_NONE) { - ethBuilder.setVlanPriority(pcp); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - EthernetMatch em = ethBuilder.getEthernetMatch(); - FlowMatch fm = new FlowMatch(1, em, null, null); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - assertEquals(true, test.run(fmi, pkt)); - - // Ensure that the packet matches only if all conditions are met. - test.reset().setMatchType(MatchType.DL_SRC); - em = ethBuilder.setSourceAddress(anotherSrc).getEthernetMatch(); - fm = new FlowMatch(1, em, null, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.DL_DST); - em = ethBuilder.setSourceAddress(src). - setDestinationAddress(anotherDst).getEthernetMatch(); - fm = new FlowMatch(1, em, null, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.DL_TYPE); - em = ethBuilder.setDestinationAddress(dst).setEtherType(anotherType). - getEthernetMatch(); - fm = new FlowMatch(1, em, null, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - em = ethBuilder.setEtherType(type).setVlanId(anotherVlan). - getEthernetMatch(); - fm = new FlowMatch(1, em, null, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - boolean tagged = (vlan != MatchType.DL_VLAN_NONE); - if (tagged) { - em = ethBuilder.setEtherType(type). - setVlanId(MatchType.DL_VLAN_NONE).setVlanPriority((byte)-1). - getEthernetMatch(); - fm = new FlowMatch(1, em, null, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - em = ethBuilder.setVlanId(vlan).setVlanPriority(anotherPcp). - getEthernetMatch(); - fm = new FlowMatch(1, em, null, null); - fmi = new FlowMatchImpl(fm); - assertEquals(!tagged, test.run(fmi, pkt)); - } - - /** - * Test ethernet and IPv4 matches. - * - * @param pkt An {@link Ethernet} instance for test. - * @throws VTNException An error occurred. - */ - private void ipv4MatchTest(Ethernet pkt) throws VTNException { - EthernetParser ethParser = new EthernetParser(pkt); - byte[] src = ethParser.getSourceAddress(); - byte[] dst = ethParser.getDestinationAddress(); - int type = ethParser.getEtherType(); - short vlan = ethParser.getVlanId(); - byte pcp = ethParser.getVlanPcp(); - - byte[] anotherSrc = ethParser.getAnotherSourceAddress(); - byte[] anotherDst = ethParser.getAnotherDestinationAddress(); - int anotherType = ethParser.getAnotherEtherType(); - short anotherVlan = ethParser.getAnotherVlanId(); - byte anotherPcp = ethParser.getAnotherVlanPcp(); - - PacketMatchTest test = new PacketMatchTest(); - - // Create flow match that specifies all Ethernet header fields. - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - ethBuilder.setSourceAddress(src).setDestinationAddress(dst). - setEtherType(type).setVlanId(vlan); - test.reset().setMatchType(MatchType.DL_SRC, MatchType.DL_DST, - MatchType.DL_TYPE); - if (vlan != MatchType.DL_VLAN_NONE) { - ethBuilder.setVlanPriority(pcp); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - Inet4MatchImplBuilder inet4Builder = new Inet4MatchImplBuilder(); - Packet payload = ethParser.getPayload(); - if (!(payload instanceof IPv4)) { - // IPv4 conditions should never be used. - inet4Builder.setSourceAddress("10.0.0.1"). - setDestinationAddress("192.168.10.1"). - setProtocol((short)6).setDscp((byte)1); - - // Ether type will be tested before VLAN tag. - test.reset().setMatchType(MatchType.DL_SRC, MatchType.DL_DST, - MatchType.DL_TYPE); - EthernetMatch em = ethBuilder. - setEtherType(EtherTypes.IPv4.shortValue()).getEthernetMatch(); - Inet4Match im = inet4Builder.getInet4Match(); - FlowMatch fm = new FlowMatch(1, em, im, null); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - return; - } - - EthernetMatch em = ethBuilder.getEthernetMatch(); - Inet4Parser inet4Parser = new Inet4Parser((IPv4)payload); - int ipSrc = inet4Parser.getSourceAddress(); - int ipDst = inet4Parser.getDestinationAddress(); - short ipProto = inet4Parser.getProtocol(); - byte ipDscp = inet4Parser.getDiffServ(); - test.setMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS); - inet4Builder.setSourceAddress(ipSrc).setDestinationAddress(ipDst). - setProtocol(ipProto).setDscp(ipDscp); - - int anotherIpSrc = inet4Parser.getAnotherSourceAddress(); - int anotherIpDst = inet4Parser.getAnotherDestinationAddress(); - short anotherIpProto = inet4Parser.getAnotherProtocol(); - byte anotherIpDscp = inet4Parser.getAnotherDiffServ(); - - Inet4Match im = inet4Builder.getInet4Match(); - FlowMatch fm = new FlowMatch(1, em, im, null); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - assertEquals(true, test.run(fmi, pkt)); - - // Ensure that the packet matches only if all conditions are met. - test.reset().setMatchType(MatchType.DL_SRC); - em = ethBuilder.setSourceAddress(anotherSrc).getEthernetMatch(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.DL_DST); - em = ethBuilder.setSourceAddress(src). - setDestinationAddress(anotherDst).getEthernetMatch(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - // DL_TYPE condition cannot be changed because IPv4 condition - // will be configured. - test.setMatchType(MatchType.DL_TYPE); - em = ethBuilder.setDestinationAddress(dst).setVlanId(anotherVlan). - getEthernetMatch(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - boolean tagged = (vlan != MatchType.DL_VLAN_NONE); - if (tagged) { - em = ethBuilder.setEtherType(type). - setVlanId(MatchType.DL_VLAN_NONE).setVlanPriority((byte)-1). - getEthernetMatch(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - em = ethBuilder.setVlanId(vlan).setVlanPriority(anotherPcp). - getEthernetMatch(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - if (tagged) { - assertEquals(false, test.run(fmi, pkt)); - em = ethBuilder.setVlanPriority(pcp).getEthernetMatch(); - } else { - test.setMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS); - assertEquals(true, test.run(fmi, pkt)); - test.clearMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS); - } - - test.setMatchType(MatchType.NW_SRC); - im = inet4Builder.setSourceAddress(anotherIpSrc).getInet4Match(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.NW_DST); - im = inet4Builder.setSourceAddress(ipSrc). - setDestinationAddress(anotherIpDst).getInet4Match(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.NW_PROTO); - im = inet4Builder.setDestinationAddress(ipDst). - setProtocol(anotherIpProto).getInet4Match(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.NW_TOS); - im = inet4Builder.setProtocol(ipProto).setDscp(anotherIpDscp). - getInet4Match(); - fm = new FlowMatch(1, em, im, null); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - } - - /** - * Test ethernet, IPv4, and layer 4 matches. - * - * @param pkt An {@link Ethernet} instance for test. - * @throws VTNException An error occurred. - */ - private void layer4MatchTest(Ethernet pkt) throws VTNException { - EthernetParser ethParser = new EthernetParser(pkt); - byte[] src = ethParser.getSourceAddress(); - byte[] dst = ethParser.getDestinationAddress(); - int type = ethParser.getEtherType(); - short vlan = ethParser.getVlanId(); - byte pcp = ethParser.getVlanPcp(); - - byte[] anotherSrc = ethParser.getAnotherSourceAddress(); - byte[] anotherDst = ethParser.getAnotherDestinationAddress(); - int anotherType = ethParser.getAnotherEtherType(); - short anotherVlan = ethParser.getAnotherVlanId(); - byte anotherPcp = ethParser.getAnotherVlanPcp(); - - PacketMatchTest test = new PacketMatchTest(); - - // Create flow match that specifies all Ethernet header fields. - EthernetMatchImplBuilder ethBuilder = new EthernetMatchImplBuilder(); - ethBuilder.setSourceAddress(src).setDestinationAddress(dst). - setEtherType(type).setVlanId(vlan); - test.reset().setMatchType(MatchType.DL_SRC, MatchType.DL_DST, - MatchType.DL_TYPE); - if (vlan != MatchType.DL_VLAN_NONE) { - ethBuilder.setVlanPriority(pcp); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - Inet4MatchImplBuilder inet4Builder = new Inet4MatchImplBuilder(); - Packet payload = ethParser.getPayload(); - if (!(payload instanceof IPv4)) { - // IPv4 conditions should never be used. - inet4Builder.setSourceAddress("10.0.0.1"). - setDestinationAddress("192.168.10.1"). - setProtocol((short)6).setDscp((byte)1); - - // Ether type will be tested before VLAN tag. - test.reset().setMatchType(MatchType.DL_SRC, MatchType.DL_DST, - MatchType.DL_TYPE); - EthernetMatch em = ethBuilder. - setEtherType(EtherTypes.IPv4.shortValue()).getEthernetMatch(); - Inet4Match im = inet4Builder.getInet4Match(); - FlowMatch fm = new FlowMatch(1, em, im, null); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - return; - } - - EthernetMatch em = ethBuilder.getEthernetMatch(); - Inet4Parser inet4Parser = new Inet4Parser((IPv4)payload); - int ipSrc = inet4Parser.getSourceAddress(); - int ipDst = inet4Parser.getDestinationAddress(); - short ipProto = inet4Parser.getProtocol(); - byte ipDscp = inet4Parser.getDiffServ(); - test.setMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS); - inet4Builder.setSourceAddress(ipSrc).setDestinationAddress(ipDst). - setProtocol(ipProto).setDscp(ipDscp); - - payload = inet4Parser.getPayload(); - IPProtocols ipType = null; - if (payload instanceof TCP) { - ipType = IPProtocols.TCP; - } else if (payload instanceof UDP) { - ipType = IPProtocols.UDP; - } else if (payload instanceof ICMP) { - ipType = IPProtocols.ICMP; - } - - TcpMatchImplBuilder tcpBuilder = new TcpMatchImplBuilder(); - if (ipType == null) { - // Layer 4 conditions should never be used. - Inet4Match im = inet4Builder. - setProtocol(IPProtocols.TCP.shortValue()).getInet4Match(); - TcpMatch tm = tcpBuilder.setSourcePortFrom(12345). - setDestinationPortFrom(333).getTcpMatch(); - FlowMatch fm = new FlowMatch(1, em, im, tm); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - - // IP protocol will be tested before TOS. - if (ipProto != IPProtocols.TCP.shortValue()) { - test.clearMatchType(MatchType.NW_TOS); - } - assertEquals(false, test.run(fmi, pkt)); - - return; - } - - int anotherIpSrc = inet4Parser.getAnotherSourceAddress(); - int anotherIpDst = inet4Parser.getAnotherDestinationAddress(); - short anotherIpProto = inet4Parser.getAnotherProtocol(); - byte anotherIpDscp = inet4Parser.getAnotherDiffServ(); - - L4MatchImplBuilder l4Builder; - L4Parser l4Parser; - switch (ipType) { - case TCP: - l4Builder = new TcpMatchImplBuilder(); - l4Parser = new TcpParser((TCP)payload); - break; - - case UDP: - l4Builder = new UdpMatchImplBuilder(); - l4Parser = new UdpParser((UDP)payload); - break; - - default: - l4Builder = new IcmpMatchImplBuilder(); - l4Parser = new IcmpParser((ICMP)payload); - break; - } - - int l4Src = l4Parser.getSource(); - int l4Dst = l4Parser.getDestination(); - int anotherL4Src = l4Parser.getAnotherSource(); - int anotherL4Dst = l4Parser.getAnotherDestination(); - test.setMatchType(MatchType.TP_SRC, MatchType.TP_DST); - - L4Match lm = l4Builder.setSource(l4Src).setDestination(l4Dst). - getLayer4Match(); - Inet4Match im = inet4Builder.getInet4Match(); - FlowMatch fm = new FlowMatch(1, em, im, lm); - FlowMatchImpl fmi = new FlowMatchImpl(fm); - assertEquals(true, test.run(fmi, pkt)); - - // Ensure that the packet matches only if all conditions are met. - test.reset().setMatchType(MatchType.DL_SRC); - em = ethBuilder.setSourceAddress(anotherSrc).getEthernetMatch(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.DL_DST); - em = ethBuilder.setSourceAddress(src). - setDestinationAddress(anotherDst).getEthernetMatch(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - // DL_TYPE condition cannot be changed because IPv4 condition - // will be configured. - test.setMatchType(MatchType.DL_TYPE); - em = ethBuilder.setDestinationAddress(dst).setVlanId(anotherVlan). - getEthernetMatch(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - boolean tagged = (vlan != MatchType.DL_VLAN_NONE); - if (tagged) { - em = ethBuilder.setEtherType(type). - setVlanId(MatchType.DL_VLAN_NONE).setVlanPriority((byte)-1). - getEthernetMatch(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - test.setMatchType(MatchType.DL_VLAN_PR); - } - - em = ethBuilder.setVlanId(vlan).setVlanPriority(anotherPcp). - getEthernetMatch(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - if (tagged) { - assertEquals(false, test.run(fmi, pkt)); - em = ethBuilder.setVlanPriority(pcp).getEthernetMatch(); - } else { - test.setMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS, - MatchType.TP_SRC, MatchType.TP_DST); - assertEquals(true, test.run(fmi, pkt)); - test.clearMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS, - MatchType.TP_SRC, MatchType.TP_DST); - } - - test.setMatchType(MatchType.NW_SRC); - im = inet4Builder.setSourceAddress(anotherIpSrc).getInet4Match(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.NW_DST); - im = inet4Builder.setSourceAddress(ipSrc). - setDestinationAddress(anotherIpDst).getInet4Match(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - // NW_PROTO condition cannot be changed because L4 condition will be - // configured. - test.setMatchType(MatchType.NW_PROTO, MatchType.NW_TOS); - im = inet4Builder.setDestinationAddress(ipDst).setDscp(anotherIpDscp). - getInet4Match(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.TP_SRC); - im = inet4Builder.setDscp(ipDscp).getInet4Match(); - lm = l4Builder.setSource(anotherL4Src).getLayer4Match(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - - test.setMatchType(MatchType.TP_DST); - lm = l4Builder.setSource(l4Src).setDestination(anotherL4Dst). - getLayer4Match(); - fm = new FlowMatch(1, em, im, lm); - fmi = new FlowMatchImpl(fm); - assertEquals(false, test.run(fmi, pkt)); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImplTest.java deleted file mode 100644 index 78cf9d89..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/IcmpMatchImplTest.java +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.util.HashSet; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.ICMP; -import org.opendaylight.controller.sal.packet.IEEE8021Q; -import org.opendaylight.controller.sal.packet.IPv4; -import org.opendaylight.controller.sal.packet.Packet; -import org.opendaylight.controller.sal.packet.UDP; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.IPProtocols; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link IcmpMatchImpl}. - */ -public class IcmpMatchImplTest extends TestBase { - /** - * Test for {@link IcmpMatchImpl#IcmpMatchImpl(IcmpMatch)}, - * {@link L4MatchImpl#create(org.opendaylight.vtn.manager.flow.cond.L4Match)}, - * and getter methods. - * - * @throws VTNException An error occurred. - */ - @Test - public void testConstructor() throws VTNException { - short[] types = { - -1, 0, 4, 18, 32, 159, 255, - }; - short[] codes = { - -1, 0, 3, 21, 45, 183, 255, - }; - - IcmpMatchImplBuilder builder = new IcmpMatchImplBuilder(); - for (short type: types) { - builder.setType(type); - for (short code: codes) { - builder.setCode(code); - IcmpMatchImpl icmi = builder.create(); - assertEquals(type, icmi.getType()); - assertEquals(code, icmi.getCode()); - assertEquals(builder.getIcmpMatch(), icmi.getMatch()); - assertEquals(IPProtocols.ICMP.shortValue(), - icmi.getInetProtocol()); - - // Instantiate using L4Match.create(). - IcmpMatch icm = builder.getIcmpMatch(); - assertEquals(icmi, L4MatchImpl.create(icm)); - } - } - - // Specifying invalid ICMP type and code. - short[] badValues = { - Short.MIN_VALUE, -3, -2, -1, - 256, 257, 300, 12345, Short.MAX_VALUE, - }; - for (short v: badValues) { - Short bad = Short.valueOf(v); - builder.reset().setType(bad); - try { - builder.build(); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid value for ICMP type: " + bad, - st.getDescription()); - } - - builder.reset().setCode(bad); - try { - builder.build(); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid value for ICMP code: " + bad, - st.getDescription()); - } - } - } - - /** - * Test case for {@link IcmpMatchImpl#equals(Object)} and - * {@link IcmpMatchImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - HashSet hashCodes = new HashSet(); - - short[] types = { - -1, 0, 4, 18, 32, 159, 255, - }; - short[] codes = { - -1, 0, 3, 21, 45, 183, 255, - }; - - IcmpMatchImplBuilder builder = new IcmpMatchImplBuilder(); - for (short type: types) { - builder.setType(type); - for (short code: codes) { - builder.setCode(code); - IcmpMatchImpl icmi1 = builder.create(); - IcmpMatchImpl icmi2 = builder.create(); - testEquals(set, icmi1, icmi2); - assertTrue(hashCodes.add(icmi1.hashCode())); - assertFalse(hashCodes.add(icmi1.hashCode())); - assertFalse(hashCodes.add(icmi2.hashCode())); - } - } - - assertEquals(types.length * codes.length, set.size()); - } - - /** - * Test case for {@link IcmpMatchImpl#toString()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testToString() throws VTNException { - String prefix = "IcmpMatchImpl["; - String suffix = "]"; - - short[] types = { - -1, 0, 4, 18, 32, 159, 255, - }; - short[] codes = { - -1, 0, 3, 21, 45, 183, 255, - }; - - IcmpMatchImplBuilder builder = new IcmpMatchImplBuilder(); - for (short type: types) { - builder.setType(type); - String t = (type == -1) ? null : "type=" + type; - for (short code: codes) { - builder.setCode(code); - String s = (code == -1) ? null : "code=" + code; - IcmpMatchImpl icmi = builder.create(); - - String required = joinStrings(prefix, suffix, ",", t, s); - assertEquals(required, icmi.toString()); - } - } - } - - /** - * Ensure that {@link IcmpMatchImpl} is serializable. - * - * @throws VTNException An error occurred. - */ - @Test - public void testSerialize() throws VTNException { - short[] types = { - -1, 0, 4, 18, 32, 159, 255, - }; - short[] codes = { - -1, 0, 3, 21, 45, 183, 255, - }; - - IcmpMatchImplBuilder builder = new IcmpMatchImplBuilder(); - for (short type: types) { - builder.setType(type); - for (short code: codes) { - builder.setCode(code); - IcmpMatchImpl icmi = builder.create(); - serializeTest(icmi); - } - } - } - - /** - * Test case for {@link IcmpMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - short type = 8; - short code = 0; - byte[] payload = { - (byte)0x04, (byte)0xce, (byte)0xfe, (byte)0x21, - (byte)0xdc, (byte)0xb1, (byte)0x16, (byte)0x3b, - }; - ICMP icmp = new ICMP(); - icmp.setType((byte)type).setCode((byte)code). - setIdentifier((short)0x1234).setSequenceNumber((short)0x5678). - setRawPayload(payload); - - String saddr = "10.234.198.83"; - String daddr = "192.168.238.254"; - InetAddress src = InetAddress.getByName(saddr); - InetAddress dst = InetAddress.getByName(daddr); - short proto = IPProtocols.ICMP.shortValue(); - byte dscp = 0; - IPv4 ipv4 = createIPv4(src, dst, proto, dscp); - ipv4.setPayload(icmp); - - IPv4 nonIcmp1 = createIPv4(src, dst, (short)100, dscp); - nonIcmp1.setRawPayload(payload); - - UDP udp = new UDP(); - udp.setSourcePort((short)1).setDestinationPort((short)2). - setLength((short)123).setChecksum((short)0x1234); - IPv4 nonIcmp2 = createIPv4(src, dst, IPProtocols.UDP.shortValue(), - dscp); - nonIcmp2.setPayload(udp); - IPv4[] nonIcmp = {nonIcmp1, nonIcmp2}; - - // Run tests with changing VLAN ID. - short[] vlans = { - MatchType.DL_VLAN_NONE, 10, - }; - - byte[] srcMac = { - (byte)0x10, (byte)0x20, (byte)0x30, - (byte)0x40, (byte)0x50, (byte)0x60, - }; - byte[] dstMac = { - (byte)0xf0, (byte)0xf1, (byte)0xf2, - (byte)0xfa, (byte)0xfb, (byte)0xfc, - }; - int ethType = EtherTypes.IPv4.intValue(); - byte pcp = 0; - for (short vlan: vlans) { - Ethernet pkt = createEthernet(srcMac, dstMac, ethType, vlan, pcp, - ipv4); - matchTest(pkt); - - // Test non-IPv4 packet. - pkt = createEthernet(srcMac, dstMac, (short)100, vlan, pcp, - payload); - matchTest(pkt); - - // Test non-ICMP packet. - for (IPv4 p: nonIcmp) { - pkt = createEthernet(srcMac, dstMac, ethType, vlan, pcp, p); - matchTest(pkt); - } - } - } - - /** - * Run tests for {@link IcmpMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)} - * using the given packet. - * - * @param pkt An {@link Ethernet} instance for test. - */ - private void matchTest(Ethernet pkt) { - PacketMatchTest test = new PacketMatchTest(); - IcmpMatchImplBuilder builder = new IcmpMatchImplBuilder(); - - ICMP icmp = getIcmpPacket(pkt); - if (icmp == null) { - // Should not match non-ICMP packet. - assertEquals(false, test.run(builder.create(), pkt)); - - short type = 0; - short code = 0; - builder.setType(type).setCode(code).create(); - assertEquals(false, test.run(builder.create(), pkt)); - return; - } - - IcmpParser icmpParser = new IcmpParser(icmp); - short type = icmpParser.getType(); - short code = icmpParser.getCode(); - - short anotherType = icmpParser.getAnotherType(); - short anotherCode = icmpParser.getAnotherCode(); - - // Empty match should match every packet. - assertEquals(true, test.run(builder.create(), pkt)); - - // Specify single field in ICMP header. - IcmpMatchImpl icmi = builder.reset().setType(type).create(); - assertEquals(true, test.setMatchType(MatchType.TP_SRC).run(icmi, pkt)); - icmi = builder.reset().setType(anotherType).create(); - assertEquals(false, test.run(icmi, pkt)); - - test.reset().setMatchType(MatchType.TP_DST); - icmi = builder.reset().setCode(code).create(); - assertEquals(true, test.run(icmi, pkt)); - icmi = builder.reset().setCode(anotherCode).create(); - assertEquals(false, test.run(icmi, pkt)); - - // Specify all fieldd. - icmi = builder.reset().setType(type).setCode(code).create(); - test.reset().setMatchType(MatchType.TP_SRC, MatchType.TP_DST); - assertEquals(true, test.run(icmi, pkt)); - - // Ensure that match() returns false if one field does not match. - test.reset().setMatchType(MatchType.TP_SRC); - icmi = builder.setType(anotherType).create(); - assertEquals(false, test.run(icmi, pkt)); - - test.setMatchType(MatchType.TP_DST); - icmi = builder.setType(type).setCode(anotherCode).create(); - assertEquals(false, test.run(icmi, pkt)); - } - - /** - * Return an {@link ICMP} instance configured in the given packet. - * - * @param pkt An {@link Ethernet} instance. - * @return An {@link ICMP} instance if found. - * {@code null} if not found. - */ - private ICMP getIcmpPacket(Ethernet pkt) { - Packet payload = pkt.getPayload(); - if (payload instanceof IEEE8021Q) { - IEEE8021Q tag = (IEEE8021Q)payload; - payload = tag.getPayload(); - } - - if (payload instanceof IPv4) { - IPv4 ipv4 = (IPv4)payload; - payload = ipv4.getPayload(); - if (payload instanceof ICMP) { - return (ICMP)payload; - } - } - - return null; - } -} - -/** - * Utility class to create {@link IcmpMatchImpl} instance. - */ -final class IcmpMatchImplBuilder extends TestBase - implements L4MatchImplBuilder { - /** - * ICMP type. - */ - private Short icmpType; - - /** - * ICMP code. - */ - private Short icmpCode; - - /** - * Created {@link IcmpMatch} instance. - */ - private IcmpMatch icmpMatch; - - /** - * Set ICMP type. - * - * @param type ICMP type. - * @return This instance. - */ - public IcmpMatchImplBuilder setType(short type) { - icmpType = (type == -1) ? null : Short.valueOf(type); - icmpMatch = null; - return this; - } - - /** - * Set ICMP type. - * - * @param type ICMP type. - * @return This instance. - */ - public IcmpMatchImplBuilder setType(Short type) { - icmpType = type; - icmpMatch = null; - return this; - } - - /** - * Set ICMP code. - * - * @param code ICMP code. - * @return This instance. - */ - public IcmpMatchImplBuilder setCode(short code) { - icmpCode = (code == -1) ? null : Short.valueOf(code); - icmpMatch = null; - return this; - } - - /** - * Set ICMP code. - * - * @param code ICMP code. - * @return This instance. - */ - public IcmpMatchImplBuilder setCode(Short code) { - icmpCode = code; - icmpMatch = null; - return this; - } - - /** - * Reset to the initial state. - * - * @return This instance. - */ - public IcmpMatchImplBuilder reset() { - icmpType = null; - icmpCode = null; - icmpMatch = null; - - return this; - } - - /** - * Construct an {@link IcmpMatch} instance. - * - * @return An {@link IcmpMatch} instance. - */ - public IcmpMatch getIcmpMatch() { - IcmpMatch icm = icmpMatch; - if (icm == null) { - icm = new IcmpMatch(icmpType, icmpCode); - icmpMatch = icm; - } - - return icm; - } - - /** - * Construct an {@link IcmpMatchImpl} instance. - * - * @return An {@link IcmpMatchImpl} instance. - * @throws VTNException An error occurred. - */ - public IcmpMatchImpl build() throws VTNException { - IcmpMatch im = getIcmpMatch(); - return new IcmpMatchImpl(im); - } - - /** - * Construct an {@link IcmpMatchImpl} instance and ensure that it was - * constructed successfully. - * - * @return An {@link IcmpMatchImpl} instance. - */ - public IcmpMatchImpl create() { - IcmpMatchImpl icmi = null; - try { - icmi = build(); - } catch (Exception e) { - unexpected(e); - } - - return icmi; - } - - /** - * {@inheritDoc} - */ - @Override - public IcmpMatch getLayer4Match() { - return getIcmpMatch(); - } - - /** - * {@inheritDoc} - */ - @Override - public IcmpMatchImplBuilder setSource(int src) { - return setType((short)src); - } - - /** - * {@inheritDoc} - */ - @Override - public IcmpMatchImplBuilder setDestination(int dst) { - return setCode((short)dst); - } -} - - -/** - * ICMP header parser. - */ -final class IcmpParser implements L4Parser { - /** - * ICMP packet. - */ - private final ICMP packet; - - /** - * ICMP type. - */ - private final int icmpType; - - /** - * ICMP code. - */ - private final int icmpCode; - - /** - * Construct a new instance. - * - * @param icmp An {@link ICMP} instance. - */ - IcmpParser(ICMP icmp) { - packet = icmp; - icmpType = NumberUtils.getUnsigned(icmp.getType()); - icmpCode = NumberUtils.getUnsigned(icmp.getCode()); - } - - /** - * Return the ICMP packet. - * - * @return An {@link ICMP} instance. - */ - public ICMP getPacket() { - return packet; - } - - /** - * Return the ICMP type. - * - * @return The ICMP type. - */ - public short getType() { - return (short)icmpType; - } - - /** - * Return the ICMP code. - * - * @return The ICMP code. - */ - public short getCode() { - return (short)icmpCode; - } - - /** - * Return an ICMP tye that does not match this packet. - * - * @return An ICMP type that does not match this packet. - */ - public short getAnotherType() { - return (short)(~icmpType & 0xff); - } - - /** - * Return an ICMP code that does not match this packet. - * - * @return An ICMP code that does not match this packet. - */ - public short getAnotherCode() { - return (short)(~icmpCode & 0xff); - } - - /** - * {@inheritDoc} - */ - @Override - public int getSource() { - return icmpType; - } - - /** - * {@inheritDoc} - */ - @Override - public int getDestination() { - return icmpCode; - } - - /** - * {@inheritDoc} - */ - @Override - public int getAnotherSource() { - return (int)getAnotherType(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getAnotherDestination() { - return (int)getAnotherCode(); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatchTest.java deleted file mode 100644 index b6469c38..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4AddressMatchTest.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2014 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.util.HashSet; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; - -import org.opendaylight.vtn.manager.internal.util.MiscUtils; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link Inet4AddressMatch}. - */ -public class Inet4AddressMatchTest extends TestBase { - /** - * Test for getter methods. - * - * @throws Exception An error occurred. - */ - @Test - public void testGetter() throws Exception { - String[] strAddrs = { - "0.0.0.0", - "10.45.134.209", - "192.168.39.17", - "203.201.183.231", - "255.255.255.255", - }; - - short[] badSuffixes = { - Short.MIN_VALUE, -3, -2, -1, 0, - 32, 33, 50, 100, Short.MAX_VALUE, - }; - - for (String strAddr: strAddrs) { - InetAddress iaddr = InetAddress.getByName(strAddr); - int addr = MiscUtils.toInteger(iaddr); - Inet4AddressMatch am = new Inet4AddressMatch(iaddr, null); - assertEquals(addr, am.getAddress()); - assertEquals(iaddr, am.getInetAddress()); - assertEquals(-1, am.getMask()); - assertEquals(null, am.getCidrSuffix()); - - for (short suff = 1; suff < 32; suff++) { - int mask = -1 << (32 - suff); - int raddr = addr & mask; - InetAddress riaddr = MiscUtils.toInetAddress(raddr); - Short s = Short.valueOf(suff); - am = new Inet4AddressMatch(iaddr, s); - assertEquals(raddr, am.getAddress()); - assertEquals(riaddr, am.getInetAddress()); - assertEquals(mask, am.getMask()); - assertEquals(s, am.getCidrSuffix()); - } - - // Specifying invalid CIDR suffix. - for (short suff: badSuffixes) { - Short s = Short.valueOf(suff); - try { - new Inet4AddressMatch(iaddr, s); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid CIDR suffix: " + suff, - st.getDescription()); - } - } - } - } - - /** - * Test case for {@link Inet4AddressMatch#equals(Object)} and - * {@link Inet4AddressMatch#hashCode()}. - * - * @throws Exception An error occurred. - */ - @Test - public void testEquals() throws Exception { - HashSet set = new HashSet(); - String[] strAddrs = { - "0.0.0.0", - "10.45.134.209", - "192.168.39.17", - "203.201.183.231", - "255.255.255.255", - }; - - HashSet alreadySet = new HashSet(); - int count = 0; - for (String strAddr: strAddrs) { - InetAddress iaddr = InetAddress.getByName(strAddr); - int addr = MiscUtils.toInteger(iaddr); - long cookie = (long)addr << Integer.SIZE; - if (alreadySet.add(cookie)) { - Inet4AddressMatch am1 = new Inet4AddressMatch(iaddr, null); - Inet4AddressMatch am2 = new Inet4AddressMatch(copy(iaddr), - null); - testEquals(set, am1, am2); - count++; - } - - for (short suff = 1; suff < 32; suff++) { - int mask = -1 << (32 - suff); - int raddr = addr & mask; - cookie = ((long)raddr << Integer.SIZE) | (long)suff; - if (alreadySet.add(cookie)) { - Inet4AddressMatch am1 = - new Inet4AddressMatch(iaddr, new Short(suff)); - Inet4AddressMatch am2 = - new Inet4AddressMatch(copy(iaddr), new Short(suff)); - testEquals(set, am1, am2); - count++; - } - } - } - - assertEquals(count, set.size()); - } - - /** - * Test case for {@link Inet4AddressMatch#toString()}. - * - * @throws Exception An error occurred. - */ - @Test - public void testToString() throws Exception { - String[] strAddrs = { - "0.0.0.0", - "10.45.134.209", - "192.168.39.17", - "203.201.183.231", - "255.255.255.255", - }; - - short[] badSuffixes = { - Short.MIN_VALUE, -3, -2, -1, 0, - 32, 33, 50, 100, Short.MAX_VALUE, - }; - - for (String strAddr: strAddrs) { - InetAddress iaddr = InetAddress.getByName(strAddr); - int addr = MiscUtils.toInteger(iaddr); - Inet4AddressMatch am = new Inet4AddressMatch(iaddr, null); - assertEquals(strAddr, am.toString()); - - for (short suff = 1; suff < 32; suff++) { - int mask = -1 << (32 - suff); - int raddr = addr & mask; - InetAddress riaddr = MiscUtils.toInetAddress(raddr); - Short s = Short.valueOf(suff); - am = new Inet4AddressMatch(iaddr, s); - assertEquals(riaddr.getHostAddress() + "/" + s, am.toString()); - } - } - } - - /** - * Ensure that {@link Inet4AddressMatch} is serializable. - * - * @throws Exception An error occurred. - */ - @Test - public void testSerialize() throws Exception { - String[] strAddrs = { - "0.0.0.0", - "10.45.134.209", - "192.168.39.17", - "203.201.183.231", - "255.255.255.255", - }; - - short[] badSuffixes = { - Short.MIN_VALUE, -3, -2, -1, 0, - 32, 33, 50, 100, Short.MAX_VALUE, - }; - - for (String strAddr: strAddrs) { - InetAddress iaddr = InetAddress.getByName(strAddr); - int addr = MiscUtils.toInteger(iaddr); - Inet4AddressMatch am = new Inet4AddressMatch(iaddr, null); - serializeTest(am); - - for (short suff = 1; suff < 32; suff++) { - int mask = -1 << (32 - suff); - int raddr = addr & mask; - InetAddress riaddr = MiscUtils.toInetAddress(raddr); - Short s = Short.valueOf(suff); - am = new Inet4AddressMatch(iaddr, s); - serializeTest(am); - } - } - } - - /** - * Test case for {@link Inet4AddressMatch#match(int)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - String[] strAddrs = { - "0.0.0.0", - "10.45.134.209", - "192.168.39.17", - "203.201.183.231", - "255.255.255.255", - }; - - for (String strAddr: strAddrs) { - InetAddress iaddr = InetAddress.getByName(strAddr); - int addr = MiscUtils.toInteger(iaddr); - Inet4AddressMatch am = new Inet4AddressMatch(iaddr, null); - assertEquals(true, am.match(addr)); - for (int nbits = 1; nbits <= 32; nbits++) { - int mask = -1 << (32 - nbits); - int[] addrs = { - 0, - addr & mask, - addr ^ mask, - addr | mask, - addr | (~mask), - -1, - }; - for (int a: addrs) { - assertEquals(a == addr, am.match(a)); - } - } - - for (short suff = 1; suff < 32; suff++) { - am = new Inet4AddressMatch(iaddr, Short.valueOf(suff)); - int mask = -1 << (32 - suff); - int raddr = addr & mask; - int[] addrs = { - 0, - addr & mask, - addr ^ mask, - addr | mask, - addr | (~mask), - -1, - }; - for (int a: addrs) { - assertEquals((a & mask) == raddr, am.match(a)); - } - } - } - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImplTest.java deleted file mode 100644 index 0484d4d6..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/Inet4MatchImplTest.java +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.util.HashSet; - -import javax.xml.bind.Unmarshaller; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.Inet4Match; -import org.opendaylight.vtn.manager.flow.cond.InetMatch; -import org.opendaylight.vtn.manager.util.Ip4Network; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.util.MiscUtils; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.IEEE8021Q; -import org.opendaylight.controller.sal.packet.IPv4; -import org.opendaylight.controller.sal.packet.Packet; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link Inet4MatchImpl}. - */ -public class Inet4MatchImplTest extends TestBase { - /** - * Test for {@link Inet4MatchImpl#Inet4MatchImpl(short)} and - * getter methods. - */ - @Test - public void testConstructor1() { - short[] protocols = { - 0, 1, 6, 17, 50, 129, 255, - }; - for (short proto: protocols) { - Inet4MatchImpl imi = new Inet4MatchImpl(proto); - Short p = Short.valueOf(proto); - assertEquals(null, imi.getSource()); - assertEquals(null, imi.getDestination()); - assertEquals(proto, imi.getProtocol()); - assertEquals(p, imi.getProtocolShort()); - assertEquals((byte)-1, imi.getDscp()); - assertEquals(null, imi.getDscpByte()); - assertEquals(EtherTypes.IPv4.intValue(), imi.getEtherType()); - - InetMatch im = new Inet4Match(null, null, null, null, p, null); - assertEquals(im, imi.getMatch()); - } - } - - /** - * Test for {@link Inet4MatchImpl#Inet4MatchImpl(InetMatch)}, - * {@link InetMatchImpl#create(InetMatch)}, and getter methods.n - * - * @throws VTNException An error occurred. - */ - @Test - public void testConstructor2() throws VTNException { - String[] srcs = { - null, "10.0.0.2", "192.168.230.180", - }; - short[] srcSuffs = { - -1, 8, 24, - }; - String[] dsts = { - null, "10.20.30.40", "172.30.193.35", - }; - short[] dstSuffs = { - -1, 16, 23, - }; - short[] protocols = { - -1, 0, 6, 17, - }; - byte[] dscps = { - -1, 0, 30, 63, - }; - - Inet4MatchImplBuilder builder = new Inet4MatchImplBuilder(); - for (String src: srcs) { - builder.setSourceAddress(src); - for (short srcSuff: srcSuffs) { - builder.setSourceSuffix(srcSuff); - for (String dst: dsts) { - builder.setDestinationAddress(dst); - for (short dstSuff: dstSuffs) { - builder.setDestinationSuffix(dstSuff); - for (short proto: protocols) { - builder.setProtocol(proto); - for (byte dscp: dscps) { - builder.setDscp(dscp); - builder.verify(); - } - } - } - } - } - } - - // Specifying invalid MAC address via JAXB. - String[] badAddrs = { - "", "192.168.100.256", "::1", "bad_address", - }; - Unmarshaller um = createUnmarshaller(Inet4Match.class); - for (String addr: badAddrs) { - for (String attr: new String[]{"src", "dst"}) { - StringBuilder sb = new StringBuilder(XML_DECLARATION); - String xml = sb.append("").toString(); - - InetMatch im = null; - try { - im = unmarshal(um, xml, Inet4Match.class); - } catch (Exception e) { - unexpected(e); - } - - assertNotNull(im); - assertNotNull(im.getValidationStatus()); - try { - new Inet4MatchImpl(im); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - } - } - } - - // Specifying invalid IP protocol number. - Short[] badProtocols = { - Short.valueOf(Short.MIN_VALUE), Short.valueOf((short)-1), - Short.valueOf((short)0x100), Short.valueOf(Short.MAX_VALUE), - }; - for (Short proto: badProtocols) { - InetMatch im = new Inet4Match(null, null, null, null, proto, null); - try { - new Inet4MatchImpl(im); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid IP protocol number: " + proto, - st.getDescription()); - } - } - - // Specifying invalid DSCP value. - Byte[] badDscps = { - Byte.valueOf(Byte.MIN_VALUE), Byte.valueOf((byte)-1), - Byte.valueOf((byte)64), Byte.valueOf(Byte.MAX_VALUE), - }; - for (Byte dscp: badDscps) { - InetMatch im = new Inet4Match(null, null, null, null, null, dscp); - try { - new Inet4MatchImpl(im); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid DSCP field value: " + dscp, - st.getDescription()); - } - } - - // Specifying invalid CIDR suffix. - Short[] badSuffixes = { - Short.valueOf(Short.MIN_VALUE), Short.valueOf((short)-1), - Short.valueOf((short)0), Short.valueOf((short)32), - Short.valueOf((short)100), Short.valueOf(Short.MAX_VALUE), - }; - - InetAddress iaddr = null; - try { - iaddr = InetAddress.getByName("192.168.100.200"); - } catch (Exception e) { - unexpected(e); - } - - for (Short suff: badSuffixes) { - InetMatch im = new Inet4Match(iaddr, suff, null, null, null, null); - try { - new Inet4MatchImpl(im); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid CIDR suffix: " + suff, - st.getDescription()); - } - - im = new Inet4Match(null, null, iaddr, suff, null, null); - try { - new Inet4MatchImpl(im); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid CIDR suffix: " + suff, - st.getDescription()); - } - } - - // Passing null to InetMatchImpl.create(InetMatch). - try { - InetMatchImpl.create(null); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Unexpected inet match instance: null", - st.getDescription()); - } - } - - /** - * Test case for {@link Inet4MatchImpl#setProtocol(short)}. - */ - @Test - public void testSetProtocol() { - short[] protocols = { - 0, 1, 6, 17, 254, - }; - for (short proto: protocols) { - Short p = Short.valueOf(proto); - InetMatch im = new Inet4Match(null, null, null, null, p, null); - Inet4MatchImpl imi = null; - try { - imi = new Inet4MatchImpl(im); - } catch (VTNException e) { - unexpected(e); - } - - // New IP protocol can be set as long as existing protocol is not - // changed. - try { - for (int i = 0; i < 4; i++) { - imi.setProtocol(proto); - assertEquals(proto, imi.getProtocol()); - assertEquals(p, imi.getProtocolShort()); - } - } catch (VTNException e) { - unexpected(e); - } - - short newproto = (short)(proto + 1); - try { - imi.setProtocol(newproto); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - String expected = "IP protocol conflict: proto=" + proto + - ", expected=" + newproto; - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals(expected, st.getDescription()); - } - } - } - - /** - * Test case for {@link Inet4MatchImpl#equals(Object)} and - * {@link Inet4MatchImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - - String[] srcs = { - null, "10.0.0.2", "192.168.230.180", - }; - short[] srcSuffs = { - -1, 8, 24, - }; - String[] dsts = { - null, "10.20.30.40", "172.30.193.35", - }; - short[] dstSuffs = { - -1, 16, 23, - }; - short[] protocols = { - -1, 0, 6, 17, - }; - byte[] dscps = { - -1, 0, 30, 63, - }; - - int count = 0; - Inet4MatchImplBuilder builder = new Inet4MatchImplBuilder(); - for (String src: srcs) { - builder.setSourceAddress(src); - for (short srcSuff: srcSuffs) { - if (src == null && srcSuff != -1) { - continue; - } - builder.setSourceSuffix(srcSuff); - for (String dst: dsts) { - builder.setDestinationAddress(dst); - for (short dstSuff: dstSuffs) { - if (dst == null && dstSuff != -1) { - continue; - } - builder.setDestinationSuffix(dstSuff); - for (short proto: protocols) { - builder.setProtocol(proto); - for (byte dscp: dscps) { - builder.setDscp(dscp); - Inet4MatchImpl imi1 = builder.create(); - Inet4Match im = builder.getInet4Match(); - Inet4MatchImpl imi2 = builder.create(); - testEquals(set, imi1, imi2); - count++; - } - } - } - } - } - } - - assertEquals(count, set.size()); - } - - /** - * Test case for {@link Inet4MatchImpl#toString()}. - * - * @throws Exception An error occurred. - */ - @Test - public void testToString() throws Exception { - String prefix = "Inet4MatchImpl["; - String suffix = "]"; - - String[] srcs = { - null, "10.0.0.2", "192.168.230.180", - }; - short[] srcSuffs = { - -1, 8, 24, - }; - String[] dsts = { - null, "10.20.30.40", "172.30.193.35", - }; - short[] dstSuffs = { - -1, 16, 23, - }; - short[] protocols = { - -1, 0, 6, 17, - }; - byte[] dscps = { - -1, 0, 30, 63, - }; - - Inet4MatchImplBuilder builder = new Inet4MatchImplBuilder(); - for (String src: srcs) { - builder.setSourceAddress(src); - for (short srcSuff: srcSuffs) { - builder.setSourceSuffix(srcSuff); - String s; - if (src == null) { - s = null; - } else if (srcSuff == -1) { - s = "src=" + src; - } else { - InetAddress iaddr = InetAddress.getByName(src); - InetAddress raddr = - Ip4Network.getNetworkAddress(iaddr, (int)srcSuff); - s = "src=" + raddr.getHostAddress() + "/" + srcSuff; - } - for (String dst: dsts) { - builder.setDestinationAddress(dst); - for (short dstSuff: dstSuffs) { - builder.setDestinationSuffix(dstSuff); - String d; - if (dst == null) { - d = null; - } else if (dstSuff == -1) { - d = "dst=" + dst; - } else { - InetAddress iaddr = InetAddress.getByName(dst); - InetAddress raddr = Ip4Network. - getNetworkAddress(iaddr, (int)dstSuff); - d = "dst=" + raddr.getHostAddress() + "/" + - dstSuff; - } - for (short proto: protocols) { - builder.setProtocol(proto); - String p = (proto == -1) ? null - : "proto=" + proto; - for (byte dscp: dscps) { - builder.setDscp(dscp); - String ds = (dscp == -1) ? null - : "dscp=" + dscp; - Inet4MatchImpl imi = builder.create(); - String required = joinStrings( - prefix, suffix, ",", s, d, p, ds); - assertEquals(required, imi.toString()); - } - } - } - } - } - } - } - - /** - * Ensure that {@link Inet4MatchImpl} is serializable. - * - * @throws VTNException An error occurred. - */ - @Test - public void testSerialize() throws VTNException { - String[] srcs = { - null, "10.0.0.2", "192.168.230.180", - }; - short[] srcSuffs = { - -1, 8, 24, - }; - String[] dsts = { - null, "10.20.30.40", "172.30.193.35", - }; - short[] dstSuffs = { - -1, 16, 23, - }; - short[] protocols = { - -1, 0, 6, 17, - }; - byte[] dscps = { - -1, 0, 30, 63, - }; - - Inet4MatchImplBuilder builder = new Inet4MatchImplBuilder(); - for (String src: srcs) { - builder.setSourceAddress(src); - for (short srcSuff: srcSuffs) { - builder.setSourceSuffix(srcSuff); - for (String dst: dsts) { - builder.setDestinationAddress(dst); - for (short dstSuff: dstSuffs) { - builder.setDestinationSuffix(dstSuff); - for (short proto: protocols) { - builder.setProtocol(proto); - for (byte dscp: dscps) { - builder.setDscp(dscp); - Inet4MatchImpl imi = builder.create(); - serializeTest(imi); - } - } - } - } - } - } - } - - /** - * Test case for {@link Inet4MatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - String saddr = "10.234.198.83"; - String daddr = "192.168.238.254"; - InetAddress src = InetAddress.getByName(saddr); - InetAddress dst = InetAddress.getByName(daddr); - short proto = 100; - byte dscp = 35; - byte[] payload = { - (byte)0x04, (byte)0xce, (byte)0xfe, (byte)0x21, - (byte)0xdc, (byte)0xb1, (byte)0x16, (byte)0x3b, - }; - - IPv4 ipv4 = createIPv4(src, dst, proto, dscp); - ipv4.setRawPayload(payload); - - // Run tests with changing VLAN ID. - short[] vlans = { - MatchType.DL_VLAN_NONE, 10, - }; - - byte[] srcMac = { - (byte)0x10, (byte)0x20, (byte)0x30, - (byte)0x40, (byte)0x50, (byte)0x60, - }; - byte[] dstMac = { - (byte)0xf0, (byte)0xf1, (byte)0xf2, - (byte)0xfa, (byte)0xfb, (byte)0xfc, - }; - int type = EtherTypes.IPv4.intValue(); - byte pcp = 0; - for (short vlan: vlans) { - Ethernet pkt = createEthernet(srcMac, dstMac, type, vlan, pcp, - ipv4); - matchTest(pkt); - - // Test non-IPv4 packet. - pkt = createEthernet(srcMac, dstMac, (short)100, vlan, pcp, - payload); - matchTest(pkt); - } - } - - /** - * Run tests for {@link Inet4MatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)} - * using the given packet. - * - * @param pkt An {@link Ethernet} instance for test. - */ - private void matchTest(Ethernet pkt) { - Packet payload = pkt.getPayload(); - if (payload instanceof IEEE8021Q) { - IEEE8021Q tag = (IEEE8021Q)payload; - payload = tag.getPayload(); - } - - PacketMatchTest test = new PacketMatchTest(); - Inet4MatchImplBuilder builder = new Inet4MatchImplBuilder(); - - if (!(payload instanceof IPv4)) { - // Should not match non-IPv4 packet. - assertEquals(false, test.run(builder.create(), pkt)); - - int src = 123; - int dst = 456; - builder.setSourceAddress(src). - setDestinationAddress(dst).setProtocol((short)6). - setDscp((byte)0); - assertEquals(false, test.run(builder.create(), pkt)); - return; - } - - Inet4Parser inet4Parser = new Inet4Parser((IPv4)payload); - int src = inet4Parser.getSourceAddress(); - int dst = inet4Parser.getDestinationAddress(); - short proto = inet4Parser.getProtocol(); - byte dscp = inet4Parser.getDiffServ(); - - int anotherSrc = inet4Parser.getAnotherSourceAddress(); - int anotherDst = inet4Parser.getAnotherDestinationAddress(); - short anotherProto = inet4Parser.getAnotherProtocol(); - byte anotherDscp = inet4Parser.getAnotherDiffServ(); - - // Empty match should match every packet. - assertEquals(true, test.run(builder.create(), pkt)); - - // Specify single field in IPv4 header. - Inet4MatchImpl imi = builder.reset().setSourceAddress(src).create(); - assertEquals(true, test.setMatchType(MatchType.NW_SRC).run(imi, pkt)); - imi = builder.reset().setSourceAddress(anotherSrc).create(); - assertEquals(false, test.run(imi, pkt)); - - test.reset().setMatchType(MatchType.NW_DST); - imi = builder.reset().setDestinationAddress(dst).create(); - assertEquals(true, test.run(imi, pkt)); - imi = builder.reset().setDestinationAddress(anotherDst).create(); - assertEquals(false, test.run(imi, pkt)); - - test.reset().setMatchType(MatchType.NW_PROTO); - imi = builder.reset().setProtocol(proto).create(); - assertEquals(true, test.run(imi, pkt)); - imi = builder.reset().setProtocol(anotherProto).create(); - assertEquals(false, test.run(imi, pkt)); - - test.reset().setMatchType(MatchType.NW_TOS); - imi = builder.reset().setDscp(dscp).create(); - assertEquals(true, test.run(imi, pkt)); - imi = builder.reset().setDscp(anotherDscp).create(); - assertEquals(false, test.run(imi, pkt)); - - // Specify IP address by network address. - for (short suff = 1; suff <= 31; suff++) { - int mask = -1 << (32 - suff); - - int rsrc = src & mask; - test.reset().setMatchType(MatchType.NW_SRC); - imi = builder.reset().setSourceAddress(rsrc). - setSourceSuffix(suff).create(); - assertEquals(true, test.run(imi, pkt)); - int badAddr = rsrc & ~0x80000000; - imi = builder.reset().setSourceAddress(badAddr).create(); - assertEquals(false, test.run(imi, pkt)); - - int rdst = dst & mask; - test.reset().setMatchType(MatchType.NW_DST); - imi = builder.reset().setDestinationAddress(rdst). - setDestinationSuffix(suff).create(); - assertEquals(true, test.run(imi, pkt)); - badAddr = rdst & ~0x80000000; - imi = builder.reset().setDestinationAddress(badAddr).create(); - assertEquals(false, test.run(imi, pkt)); - - // Specify all fields. - imi = builder.reset().setSourceAddress(src).setSourceSuffix(suff). - setDestinationAddress(dst). - setProtocol(proto).setDscp(dscp).create(); - test.reset().setMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS); - assertEquals(true, test.run(imi, pkt)); - - imi = builder.reset().setSourceAddress(src). - setDestinationAddress(dst).setDestinationSuffix(suff). - setProtocol(proto).setDscp(dscp).create(); - assertEquals(true, test.run(imi, pkt)); - } - - // Specify all fields by implicit IP addresses. - imi = builder.reset().setSourceAddress(src).setDestinationAddress(dst). - setProtocol(proto).setDscp(dscp).create(); - test.reset().setMatchType(MatchType.NW_SRC, MatchType.NW_DST, - MatchType.NW_PROTO, MatchType.NW_TOS); - assertEquals(true, test.run(imi, pkt)); - - // Ensure that match() returns false if one field does not match. - test.reset().setMatchType(MatchType.NW_SRC); - imi = builder.setSourceAddress(anotherSrc).create(); - assertEquals(false, test.run(imi, pkt)); - - test.setMatchType(MatchType.NW_DST); - imi = builder.setSourceAddress(src).setDestinationAddress(anotherDst). - create(); - assertEquals(false, test.run(imi, pkt)); - - test.setMatchType(MatchType.NW_PROTO); - imi = builder.setDestinationAddress(dst).setProtocol(anotherProto) - .create(); - assertEquals(false, test.run(imi, pkt)); - - test.setMatchType(MatchType.NW_TOS); - imi = builder.setProtocol(proto).setDscp(anotherDscp).create(); - assertEquals(false, test.run(imi, pkt)); - } -} - -/** - * Utility class to create {@link Inet4MatchImpl} instance. - */ -final class Inet4MatchImplBuilder extends TestBase { - /** - * Source IP address. - */ - private InetAddress sourceAddress; - - /** - * CIDR suffix for source IP address. - */ - private Short sourceSuffix; - - /** - * Destinaiton IP address. - */ - private InetAddress destinationAddress; - - /** - * CIDR suffix for destination IP address. - */ - private Short destinationSuffix; - - /** - * IP protocol number. - */ - private Short protocol; - - /** - * DSCP field in the TOS field. - */ - private Byte dscp; - - /** - * Created {@link Inet4Match} instance. - */ - private Inet4Match inet4Match; - - /** - * Set source IP address. - * - * @param addr An {@link InetAddress} instance. - * @return This instance. - */ - public Inet4MatchImplBuilder setSourceAddress(InetAddress addr) { - sourceAddress = addr; - inet4Match = null; - return this; - } - - /** - * Set source IP address. - * - * @param addr An integer value which represents an IPv4 address. - * @return This instance. - */ - public Inet4MatchImplBuilder setSourceAddress(int addr) { - sourceAddress = MiscUtils.toInetAddress(addr); - inet4Match = null; - return this; - } - - /** - * Set source IP address. - * - * @param addr A string representation of an IP address. - * @return This instance. - */ - public Inet4MatchImplBuilder setSourceAddress(String addr) { - if (addr == null) { - sourceAddress = null; - } else { - try { - sourceAddress = InetAddress.getByName(addr); - } catch (Exception e) { - unexpected(e); - } - } - inet4Match = null; - return this; - } - - /** - * Set CIDR suffix for source address. - * - * @param suff A CIDR suffix. - * @return This instance. - */ - public Inet4MatchImplBuilder setSourceSuffix(short suff) { - sourceSuffix = (suff == -1) ? null : Short.valueOf(suff); - inet4Match = null; - return this; - } - - /** - * Set destination IP address. - * - * @param addr An integer value which represents an IPv4 address. - * @return This instance. - */ - public Inet4MatchImplBuilder setDestinationAddress(int addr) { - destinationAddress = MiscUtils.toInetAddress(addr); - inet4Match = null; - return this; - } - - /** - * Set destination IP address. - * - * @param addr An {@link InetAddress} instance. - * @return This instance. - */ - public Inet4MatchImplBuilder setDestinationAddress(InetAddress addr) { - destinationAddress = addr; - inet4Match = null; - return this; - } - - /** - * Set destination IP address. - * - * @param addr A string representation of an IP address. - * @return This instance. - */ - public Inet4MatchImplBuilder setDestinationAddress(String addr) { - if (addr == null) { - destinationAddress = null; - } else { - try { - destinationAddress = InetAddress.getByName(addr); - } catch (Exception e) { - unexpected(e); - } - } - inet4Match = null; - return this; - } - - /** - * Set CIDR suffix for destination address. - * - * @param suff A CIDR suffix. - * @return This instance. - */ - public Inet4MatchImplBuilder setDestinationSuffix(short suff) { - destinationSuffix = (suff == -1) ? null : Short.valueOf(suff); - inet4Match = null; - return this; - } - - /** - * Set IP protocol number. - * - * @param proto IP protocol number. - * @return This instance. - */ - public Inet4MatchImplBuilder setProtocol(short proto) { - protocol = (proto == -1) ? null : Short.valueOf(proto); - inet4Match = null; - return this; - } - - /** - * Set DSCP field value. - * - * @param d DSCP field value. - * @return This instance. - */ - public Inet4MatchImplBuilder setDscp(byte d) { - dscp = (d == -1) ? null : Byte.valueOf(d); - inet4Match = null; - return this; - } - - /** - * Reset to the initial state. - * - * @return This instance. - */ - public Inet4MatchImplBuilder reset() { - sourceAddress = null; - sourceSuffix = null; - destinationAddress = null; - destinationSuffix = null; - protocol = null; - dscp = null; - inet4Match = null; - - return this; - } - - /** - * Construct an {@link Inet4Match} instance. - * - * @return An {@link Inet4Match} instance. - */ - public Inet4Match getInet4Match() { - Inet4Match im = inet4Match; - if (im == null) { - im = new Inet4Match(sourceAddress, sourceSuffix, - destinationAddress, destinationSuffix, - protocol, dscp); - inet4Match = im; - } - - return im; - } - - /** - * Return an {@link Inet4Match} instance to be expected to be returned - * by the call of {@link Inet4MatchImpl#getMatch()}. - * - * @return An {@link Inet4Match} instance. - */ - public Inet4Match getExpectedInet4Match() { - InetAddress src = sourceAddress; - Short srcSuff = sourceSuffix; - if (src == null) { - // Source suffix should be ignored. - srcSuff = null; - } else if (srcSuff != null) { - src = Ip4Network.getNetworkAddress(src, srcSuff.intValue()); - } - - InetAddress dst = destinationAddress; - Short dstSuff = destinationSuffix; - if (dst == null) { - // Destination suffix should be ignored. - dstSuff = null; - } else if (dstSuff != null) { - dst = Ip4Network.getNetworkAddress(dst, dstSuff.intValue()); - } - - return new Inet4Match(src, srcSuff, dst, dstSuff, protocol, dscp); - } - - /** - * Construct an {@link Inet4MatchImpl} instance. - * - * @return An {@link Inet4MatchImpl} instance. - * @throws VTNException An error occurred. - */ - public Inet4MatchImpl build() throws VTNException { - InetMatch im = getInet4Match(); - return new Inet4MatchImpl(im); - } - - /** - * Construct an {@link Inet4MatchImpl} instance and ensure that it was - * constructed successfully. - * - * @return An {@link Inet4MatchImpl} instance. - */ - public Inet4MatchImpl create() { - Inet4MatchImpl imi = null; - try { - imi = build(); - } catch (Exception e) { - unexpected(e); - } - - return imi; - } - - /** - * Construct an {@link Inet4MatchImpl} instance, and verify it. - */ - public void verify() { - Inet4MatchImpl imi = create(); - assertEquals(EtherTypes.IPv4.intValue(), imi.getEtherType()); - Inet4Match im = getExpectedInet4Match(); - assertEquals(im, imi.getMatch()); - - Inet4AddressMatch am = imi.getSource(); - if (sourceAddress == null) { - assertEquals(null, am); - } else { - verify(am, im.getSourceAddress(), im.getSourceSuffix()); - } - - am = imi.getDestination(); - if (destinationAddress == null) { - assertEquals(null, am); - } else { - verify(am, im.getDestinationAddress(), im.getDestinationSuffix()); - } - - short p = (protocol == null) ? -1 : protocol.shortValue(); - assertEquals(p, imi.getProtocol()); - assertEquals(protocol, imi.getProtocolShort()); - - byte d = (dscp == null) ? -1 : dscp.byteValue(); - assertEquals(d, imi.getDscp()); - assertEquals(dscp, imi.getDscpByte()); - - // Instantiate using InetMatchImpl.create(). - try { - assertEquals(imi, InetMatchImpl.create(im)); - } catch (Exception e) { - unexpected(e); - } - } - - /** - * Verify contents of the given {@link Inet4AddressMatch} instance. - * - * @param am A {@link Inet4AddressMatch} instance. - * @param addr Expected network address. - * @param suff Expected CIDR suffix. - */ - private void verify(Inet4AddressMatch am, InetAddress addr, Short suff) { - assertEquals(addr, am.getInetAddress()); - assertEquals(MiscUtils.toInteger(addr), am.getAddress()); - assertEquals(suff, am.getCidrSuffix()); - assertEquals(toNetMask(suff), am.getMask()); - } - - /** - * Convert the given CIDR suffix into netmask. - * - * @param suff A CIDR suffix. - * @return A netmask value. - */ - private int toNetMask(Short suff) { - if (suff == null) { - return -1; - } - - InetAddress mask = Ip4Network.getInetMask(suff.intValue()); - return MiscUtils.toInteger(mask); - } -} - -/** - * IPv4 header parser. - */ -final class Inet4Parser { - /** - * IPv4 packet. - */ - private final IPv4 packet; - - /** - * Source IP address. - */ - private int sourceAddress; - - /** - * Destination IP address. - */ - private int destinationAddress; - - /** - * IP protocol number. - */ - private final short protocol; - - /** - * DSCP field value. - */ - private final byte diffServ; - - /** - * Construct a new instance. - * - * @param ipv4 An {@link IPv4} instance. - */ - Inet4Parser(IPv4 ipv4) { - packet = ipv4; - sourceAddress = ipv4.getSourceAddress(); - destinationAddress = ipv4.getDestinationAddress(); - protocol = (short)NumberUtils.getUnsigned(ipv4.getProtocol()); - diffServ = ipv4.getDiffServ(); - } - - /** - * Return the IPv4 packet. - * - * @return An {@link IPv4} instance. - */ - public IPv4 getPacket() { - return packet; - } - - /** - * Return the payload of the IPv4 packet. - * - * @return A {@link Packet} instance that represents the payload of this - * IPv4 packet. - */ - public Packet getPayload() { - return packet.getPayload(); - } - - /** - * Return the source IP address. - * - * @return An integer which represents the source IP address. - */ - public int getSourceAddress() { - return sourceAddress; - } - - /** - * Return the destination IP address. - * - * @return An integer which represents the destination IP address. - */ - public int getDestinationAddress() { - return destinationAddress; - } - - /** - * Return the IP protocol number. - * - * @return IP protocol number. - */ - public short getProtocol() { - return protocol; - } - - /** - * Return the DSCP field value. - * - * @return DSCP value. - */ - public byte getDiffServ() { - return diffServ; - } - - /** - * Return a source IP address that does not match this packet. - * - * @return A source IP address that does not match this packet. - */ - public int getAnotherSourceAddress() { - return ~sourceAddress; - } - - /** - * Return a destination IP address that does not match this packet. - * - * @return A destination IP address that does not match this packet. - */ - public int getAnotherDestinationAddress() { - return ~destinationAddress; - } - - /** - * Return an IP protocol number that does not match this packet. - * - * @return An IP protocol number that does not match this packet. - */ - public short getAnotherProtocol() { - return (short)(~protocol & 0xff); - } - - /** - * Return a DSCP field value that does not match this packet. - * - * @return A DSCP field value that does not match this packet. - */ - public byte getAnotherDiffServ() { - return (byte)(~diffServ & 0x3f); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatchTest.java deleted file mode 100644 index 0e1766f1..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/L4PortMatchTest.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.util.HashSet; - -import javax.xml.bind.Unmarshaller; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.PortMatch; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link L4PortMatch}. - */ -public class L4PortMatchTest extends TestBase { - /** - * Test for getter methods. - * - * @throws Exception An error occurred. - */ - @Test - public void testGetter() throws Exception { - int[] ports = { - 0, 1, 10, 150, 789, 12345, 33333, 56789, 65535, - }; - - Unmarshaller um = createUnmarshaller(PortMatch.class); - int nranges = 3; - for (int port: ports) { - Integer from = Integer.valueOf(port); - PortMatch pm = new PortMatch(from); - L4PortMatch lpm = new L4PortMatch(pm); - assertEquals(port, lpm.getPortFrom()); - assertEquals(port, lpm.getPortTo()); - - // Construct PortMatch that has no portTo field. - StringBuilder sb = new StringBuilder(XML_DECLARATION); - String xml = sb.append("").toString(); - pm = unmarshal(um, xml, PortMatch.class); - assertEquals(null, pm.getPortTo()); - lpm = new L4PortMatch(pm); - assertEquals(port, lpm.getPortFrom()); - assertEquals(port, lpm.getPortTo()); - - if (port != 65535) { - // Specify the range of ports. - for (int to = port; to <= port + nranges; to++) { - pm = new PortMatch(from, Integer.valueOf(to)); - lpm = new L4PortMatch(pm); - assertEquals(port, lpm.getPortFrom()); - assertEquals(to, lpm.getPortTo()); - } - } - if (port != 0) { - // Specifying invalid port range. - for (int to = port - nranges; to <= port; to++) { - if (from > to) { - continue; - } - pm = new PortMatch(from, Integer.valueOf(to)); - try { - new L4PortMatch(pm); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Invalid port range: from=" + port + - ", to=" + to, st.getDescription()); - } - } - } - } - - // Specifying empty PortMatch. - PortMatch pm = new PortMatch((Integer)null); - try { - new L4PortMatch(pm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("\"from\" is not specified.", st.getDescription()); - } - - // Specifying invalid port. - int[] badPorts = { - Integer.MIN_VALUE, -3, -2, -1, - 0x10000, 0x10001, 0x400000, Integer.MAX_VALUE, - }; - for (int port: badPorts) { - Integer bad = Integer.valueOf(port); - pm = new PortMatch(bad); - try { - new L4PortMatch(pm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("from: Invalid port number: " + port, - st.getDescription()); - } - - pm = new PortMatch(Integer.valueOf(0), bad); - try { - new L4PortMatch(pm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("to: Invalid port number: " + port, - st.getDescription()); - } - } - } - - /** - * Test case for {@link L4PortMatch#equals(Object)} and - * {@link L4PortMatch#hashCode()}. - * - * @throws Exception An error occurred. - */ - @Test - public void testEquals() throws Exception { - HashSet set = new HashSet(); - int[] ports = { - 0, 1, 10, 150, 789, 12345, 33333, 56789, 65535, - }; - - int nranges = 3; - for (int port: ports) { - Integer from = Integer.valueOf(port); - PortMatch pm1 = new PortMatch(from); - PortMatch pm2 = new PortMatch(from); - L4PortMatch lpm1 = new L4PortMatch(pm1); - L4PortMatch lpm2 = new L4PortMatch(pm2); - testEquals(set, lpm1, lpm2); - - if (port != 65535) { - // Specify the range of ports. - for (int to = port + 1; to <= port + nranges; to++) { - pm1 = new PortMatch(from, Integer.valueOf(to)); - pm2 = new PortMatch(from, Integer.valueOf(to)); - lpm1 = new L4PortMatch(pm1); - lpm2 = new L4PortMatch(pm2); - testEquals(set, lpm1, lpm2); - } - } - } - - int requires = ports.length + ((ports.length - 1) * nranges); - assertEquals(requires, set.size()); - } - - /** - * Test case for {@link L4PortMatch#toString()}. - * - * @throws Exception An error occurred. - */ - @Test - public void testToString() throws Exception { - int[] ports = { - 0, 1, 10, 150, 789, 12345, 33333, 56789, 65535, - }; - - int nranges = 3; - for (int port: ports) { - Integer from = Integer.valueOf(port); - PortMatch pm = new PortMatch(from); - L4PortMatch lpm = new L4PortMatch(pm); - assertEquals(from.toString(), lpm.toString()); - - if (port != 65535) { - // Specify the range of ports. - for (int to = port + 1; to <= port + nranges; to++) { - pm = new PortMatch(from, Integer.valueOf(to)); - lpm = new L4PortMatch(pm); - assertEquals(from + "-" + to, lpm.toString()); - } - } - } - } - - /** - * Ensure that {@link L4PortMatch} is serializable. - * - * @throws Exception An error occurred. - */ - @Test - public void testSerialize() throws Exception { - int[] ports = { - 0, 1, 10, 150, 789, 12345, 33333, 56789, 65535, - }; - - int nranges = 3; - for (int port: ports) { - Integer from = Integer.valueOf(port); - PortMatch pm = new PortMatch(from); - L4PortMatch lpm = new L4PortMatch(pm); - serializeTest(lpm); - - if (port != 65535) { - // Specify the range of ports. - for (int to = port + 1; to <= port + nranges; to++) { - pm = new PortMatch(from, Integer.valueOf(to)); - lpm = new L4PortMatch(pm); - serializeTest(lpm); - } - } - } - } - - /** - * Test case for {@link L4PortMatch#match(int)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - int[] ports = { - 0, 1, 10, 150, 789, 12345, 33333, 56789, 65535, - }; - int[] badPorts = { - Integer.MIN_VALUE, -3, -2, -1, - 0x10000, 0x10001, 0x400000, Integer.MAX_VALUE, - }; - - int nranges = 3; - for (int port: ports) { - Integer from = Integer.valueOf(port); - PortMatch pm = new PortMatch(from); - L4PortMatch lpm = new L4PortMatch(pm); - assertEquals(true, lpm.match(port)); - for (int i = 1; i <= 10; i++) { - assertEquals(false, lpm.match(port + i)); - assertEquals(false, lpm.match(port - i)); - } - for (int p: badPorts) { - assertEquals(false, lpm.match(p)); - } - - if (port != 65535) { - // Specify the range of ports. - for (int to = port + 1; to <= port + nranges; to++) { - pm = new PortMatch(from, Integer.valueOf(to)); - lpm = new L4PortMatch(pm); - for (int p = port; p <= to; p++) { - assertEquals(true, lpm.match(port)); - } - for (int p: badPorts) { - assertEquals(false, lpm.match(p)); - } - for (int i = 1; i <= 10; i++) { - assertEquals(false, lpm.match(to + i)); - assertEquals(false, lpm.match(port - i)); - } - } - } - } - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MapTypeTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MapTypeTest.java index 79517ba5..9d9d46a9 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MapTypeTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MapTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014 NEC Corporation + * Copyright (c) 2013-2015 NEC Corporation * All rights reserved. * * This program and the accompanying materials are made available under the @@ -13,9 +13,9 @@ import org.junit.Test; import org.opendaylight.vtn.manager.VNodeRoute.Reason; -import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; -import org.opendaylight.controller.sal.match.MatchType; +import org.opendaylight.vtn.manager.internal.TestBase; /** * JUnit test for {@link MapType}. @@ -35,7 +35,7 @@ public class MapTypeTest extends TestBase { case MAC: assertEquals(Reason.MACMAPPED, type.getReason()); - assertEquals(MatchType.DL_SRC, type.getMatchType()); + assertEquals(FlowMatchType.DL_SRC, type.getMatchType()); break; case VLAN: diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatchTest.java deleted file mode 100644 index 4c5dda8b..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/PacketMatchTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.util.EnumSet; - -import org.opendaylight.vtn.manager.util.EtherAddress; - -import org.opendaylight.vtn.manager.internal.PacketContext; -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.core.Node; -import org.opendaylight.controller.sal.core.NodeConnector; -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.ARP; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.NodeConnectorCreator; -import org.opendaylight.controller.sal.utils.NodeCreator; - -/** - * Utility to test {@link PacketMatch#match(PacketContext)}. - */ -public final class PacketMatchTest extends TestBase { - /** - * A node connector for test. - */ - static final NodeConnector NODE_CONNECTOR; - - /** - * An ARP packet for test. - */ - static final ARP ARP_PACKET; - - /** - * Initialize test class. - */ - static { - // Create a node connector. - Node node = NodeCreator.createOFNode(Long.valueOf(1L)); - NODE_CONNECTOR = NodeConnectorCreator. - createNodeConnector(Short.valueOf((short)1), node); - - // Create an ARP packet. - byte[] sha = { - (byte)0x01, (byte)0x23, (byte)0x45, - (byte)0x67, (byte)0x89, (byte)0xab, - }; - byte[] tha = { - (byte)0xff, (byte)0xff, (byte)0xff, - (byte)0xff, (byte)0xff, (byte)0xff, - }; - byte[] spa = {(byte)10, (byte)0, (byte)1, (byte)2}; - byte[] tpa = {(byte)192, (byte)168, (byte)100, (byte)200}; - - ARP_PACKET = new ARP(); - ARP_PACKET.setHardwareType(ARP.HW_TYPE_ETHERNET). - setHardwareAddressLength((byte)EtherAddress.SIZE). - setProtocolType(EtherTypes.IPv4.shortValue()). - setProtocolAddressLength((byte)4). - setOpCode(ARP.REQUEST). - setSenderHardwareAddress(sha). - setTargetHardwareAddress(tha). - setSenderProtocolAddress(spa). - setTargetProtocolAddress(tpa); - } - - /** - * A set of {@link MatchType} instances to be configured in a - * {@link PacketContext} instance. - */ - private final EnumSet matchTypes = - EnumSet.noneOf(MatchType.class); - - /** - * Configure {@link MatchType} instances expected to be configured - * into {@link PacketContext}. - * - * @param types An array of {@link MatchType} instances. - * @return This instance. - */ - public PacketMatchTest setMatchType(MatchType ... types) { - if (types != null) { - for (MatchType mtype: types) { - matchTypes.add(mtype); - } - } - - return this; - } - - /** - * Remove {@link MatchType} instances from a set of match fields - * expected to be configured into {@link PacketContext}. - * - * @param types An array of {@link MatchType} instances. - * @return This instance. - */ - public PacketMatchTest clearMatchType(MatchType ... types) { - if (types != null) { - for (MatchType mtype: types) { - matchTypes.remove(mtype); - } - } - - return this; - } - - /** - * Reset to the initial state. - * - * @return This instance. - */ - public PacketMatchTest reset() { - matchTypes.clear(); - return this; - } - - /** - * Run test for {@link PacketMatch#match(PacketContext)}. - * - * @param pm A {@link PacketMatch} instance to be tested. - * @param ether An {@link Ethernet} instance to be passed to {@code pm}. - * @return A boolean value returned by the call of - * {@link PacketMatch#match(PacketContext)}. - */ - public boolean run(PacketMatch pm, Ethernet ether) { - PacketContext pctx = createPacketContext(ether, NODE_CONNECTOR); - boolean ret = pm.match(pctx); - - for (MatchType mtype: MatchType.values()) { - assertEquals(mtype.toString(), matchTypes.contains(mtype), - pctx.hasMatchField(mtype)); - } - - return ret; - } - - /** - * Run test for {@link FlowCondImpl#match(VTNManagerImpl, PacketContext)}. - * - * @param mgr VTN Manager service. - * @param fci A {@link FlowCondImpl} instance to be tested. - * @param ether An {@link Ethernet} instance to be passed to {@code fci}. - * @return A boolean value returned by the call of - * {@link FlowCondImpl#match(VTNManagerImpl, PacketContext)}. - */ - public boolean run(VTNManagerImpl mgr, FlowCondImpl fci, Ethernet ether) { - PacketContext pctx = createPacketContext(ether, NODE_CONNECTOR); - boolean ret = fci.match(mgr, pctx); - - for (MatchType mtype: MatchType.values()) { - assertEquals(mtype.toString(), matchTypes.contains(mtype), - pctx.hasMatchField(mtype)); - } - - return ret; - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java index e99075cc..eb6ed45e 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java @@ -45,10 +45,7 @@ public class SetDlDstActionImplTest extends TestBase { try { SetDlDstActionImpl impl = new SetDlDstActionImpl(act); assertEquals(act, impl.getFlowAction()); - - // Ensure that MAC address bytes are copied. - assertNotSame(bytes, impl.getAddress()); - assertArrayEquals(bytes, impl.getAddress()); + assertArrayEquals(bytes, impl.getAddress().getBytes()); } catch (Exception e) { unexpected(e); } diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java index a3ccad6a..8259fd60 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java @@ -45,10 +45,7 @@ public class SetDlSrcActionImplTest extends TestBase { try { SetDlSrcActionImpl impl = new SetDlSrcActionImpl(act); assertEquals(act, impl.getFlowAction()); - - // Ensure that MAC address bytes are copied. - assertNotSame(bytes, impl.getAddress()); - assertArrayEquals(bytes, impl.getAddress()); + assertArrayEquals(bytes, impl.getAddress().getBytes()); } catch (Exception e) { unexpected(e); } diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java index a223f936..44c042a6 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java @@ -19,6 +19,7 @@ import org.junit.Test; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction; +import org.opendaylight.vtn.manager.util.IpNetwork; import org.opendaylight.vtn.manager.internal.TestBase; @@ -36,10 +37,11 @@ public class SetInet4DstActionImplTest extends TestBase { @Test public void testGetter() throws Exception { for (InetAddress iaddr: createInet4Addresses(false)) { + IpNetwork ipn = IpNetwork.create(iaddr); SetInet4DstAction act = new SetInet4DstAction(iaddr); SetInet4DstActionImpl impl = new SetInet4DstActionImpl(act); assertEquals(act, impl.getFlowAction()); - assertEquals(iaddr, impl.getAddress()); + assertEquals(ipn, impl.getAddress()); } // null action. diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImplTest.java index ebac3428..982f5a71 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImplTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImplTest.java @@ -19,6 +19,7 @@ import org.junit.Test; import org.opendaylight.vtn.manager.VTNException; import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction; +import org.opendaylight.vtn.manager.util.IpNetwork; import org.opendaylight.vtn.manager.internal.TestBase; @@ -36,10 +37,11 @@ public class SetInet4SrcActionImplTest extends TestBase { @Test public void testGetter() throws Exception { for (InetAddress iaddr: createInet4Addresses(false)) { + IpNetwork ipn = IpNetwork.create(iaddr); SetInet4SrcAction act = new SetInet4SrcAction(iaddr); SetInet4SrcActionImpl impl = new SetInet4SrcActionImpl(act); assertEquals(act, impl.getFlowAction()); - assertEquals(iaddr, impl.getAddress()); + assertEquals(ipn, impl.getAddress()); } // null action. diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImplTest.java deleted file mode 100644 index fd86ebf3..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/TcpMatchImplTest.java +++ /dev/null @@ -1,961 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.util.HashSet; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.L4Match; -import org.opendaylight.vtn.manager.flow.cond.PortMatch; -import org.opendaylight.vtn.manager.flow.cond.TcpMatch; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.IEEE8021Q; -import org.opendaylight.controller.sal.packet.IPv4; -import org.opendaylight.controller.sal.packet.Packet; -import org.opendaylight.controller.sal.packet.TCP; -import org.opendaylight.controller.sal.packet.UDP; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.IPProtocols; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link TcpMatchImpl}. - */ -public class TcpMatchImplTest extends TestBase { - /** - * Test for {@link TcpMatchImpl#TcpMatchImpl(TcpMatch)}, - * {@link L4MatchImpl#create(org.opendaylight.vtn.manager.flow.cond.L4Match)}, - * and getter methods. - * - * @throws VTNException An error occurred. - */ - @Test - public void testConstructor() throws VTNException { - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int nranges = 3; - TcpMatchImplBuilder builder = new TcpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 0 : nranges; - int[] srcRange = new int[snr + 2]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i - 1; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 0 : nranges; - int[] dstRange = new int[dnr + 2]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i - 1; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - builder.verify(); - } - } - } - } - - // Specifying empty PortMatch. - PortMatch empty = new PortMatch((Integer)null); - TcpMatch tm = new TcpMatch(empty, null); - try { - new TcpMatchImpl(tm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("source: \"from\" is not specified.", - st.getDescription()); - } - - tm = new TcpMatch(null, empty); - try { - new TcpMatchImpl(tm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("destination: \"from\" is not specified.", - st.getDescription()); - } - - // Specifying bad port number. - Integer badPort = Integer.valueOf(-1); - tm = new TcpMatch(badPort, null); - try { - new TcpMatchImpl(tm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("source: from: Invalid port number: " + badPort, - st.getDescription()); - } - - tm = new TcpMatch(null, badPort); - try { - new TcpMatchImpl(tm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("destination: from: Invalid port number: " + badPort, - st.getDescription()); - } - - // Specifying invalid port range. - Integer badFrom = Integer.valueOf(3); - Integer badTo = Integer.valueOf(2); - PortMatch badRange = new PortMatch(badFrom, badTo); - tm = new TcpMatch(badRange, null); - try { - new TcpMatchImpl(tm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("source: Invalid port range: from=" + badFrom + - ", to=" + badTo, st.getDescription()); - } - - tm = new TcpMatch(null, badRange); - try { - new TcpMatchImpl(tm); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("destination: Invalid port range: from=" + badFrom + - ", to=" + badTo, st.getDescription()); - } - - // Passing null to L4MatchImpl.create(L4Match). - try { - L4MatchImpl.create(null); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("Unexpected L4 match instance: null", - st.getDescription()); - } - } - - /** - * Test case for {@link TcpMatchImpl#equals(Object)} and - * {@link TcpMatchImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int count = 0; - int nranges = 3; - TcpMatchImplBuilder builder = new TcpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 1 : nranges; - int[] srcRange = new int[snr]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 1 : nranges; - int[] dstRange = new int[dnr]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - TcpMatchImpl tmi1 = builder.create(); - TcpMatchImpl tmi2 = builder.create(); - testEquals(set, tmi1, tmi2); - count++; - } - } - } - } - - assertEquals(count, set.size()); - } - - /** - * Test case for {@link TcpMatchImpl#toString()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testToString() throws VTNException { - String prefix = "TcpMatchImpl["; - String suffix = "]"; - - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int nranges = 3; - TcpMatchImplBuilder builder = new TcpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 1 : nranges; - int[] srcRange = new int[snr]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 1 : nranges; - int[] dstRange = new int[dnr]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - TcpMatchImpl tmi = builder.create(); - - String s; - if (src == -1) { - s = null; - } else if (srcTo == -1 || src == srcTo) { - s = "src=" + src; - } else { - s = "src=" + src + "-" + srcTo; - } - - String d; - if (dst == -1) { - d = null; - } else if (dstTo == -1 || dst == dstTo) { - d = "dst=" + dst; - } else { - d = "dst=" + dst + "-" + dstTo; - } - - String required = joinStrings(prefix, suffix, ",", - s, d); - assertEquals(required, tmi.toString()); - } - } - } - } - } - - /** - * Ensure that {@link TcpMatchImpl} is serializable. - * - * @throws VTNException An error occurred. - */ - @Test - public void testSerialize() throws VTNException { - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int nranges = 3; - TcpMatchImplBuilder builder = new TcpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 1 : nranges; - int[] srcRange = new int[snr]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 1 : nranges; - int[] dstRange = new int[dnr]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - TcpMatchImpl tmi = builder.create(); - serializeTest(tmi); - } - } - } - } - } - - /** - * Test case for {@link TcpMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - int srcPort = 123; - int dstPort = 65000; - byte[] payload = { - (byte)0x04, (byte)0xce, (byte)0xfe, (byte)0x21, - (byte)0xdc, (byte)0xb1, (byte)0x16, (byte)0x3b, - }; - TCP tcp = new TCP(); - tcp.setSourcePort((short)srcPort).setDestinationPort((short)dstPort). - setSequenceNumber(0x12345).setAckNumber(0x23456). - setDataOffset((byte)1).setHeaderLenFlags((short)0x18). - setReserved((byte)0).setWindowSize((short)0xfc00). - setChecksum((short)0x7777); - - String saddr = "10.234.198.83"; - String daddr = "192.168.238.254"; - InetAddress src = InetAddress.getByName(saddr); - InetAddress dst = InetAddress.getByName(daddr); - short proto = IPProtocols.TCP.shortValue(); - byte dscp = 0; - IPv4 ipv4 = createIPv4(src, dst, proto, dscp); - ipv4.setPayload(tcp); - - IPv4 nonTcp1 = createIPv4(src, dst, (short)100, dscp); - nonTcp1.setRawPayload(payload); - - UDP udp = new UDP(); - udp.setSourcePort((short)1).setDestinationPort((short)2). - setLength((short)123).setChecksum((short)0x1234); - IPv4 nonTcp2 = createIPv4(src, dst, IPProtocols.UDP.shortValue(), - dscp); - nonTcp2.setPayload(udp); - IPv4[] nonTcp = {nonTcp1, nonTcp2}; - - // Run tests with changing VLAN ID. - short[] vlans = { - MatchType.DL_VLAN_NONE, 10, - }; - - byte[] srcMac = { - (byte)0x10, (byte)0x20, (byte)0x30, - (byte)0x40, (byte)0x50, (byte)0x60, - }; - byte[] dstMac = { - (byte)0xf0, (byte)0xf1, (byte)0xf2, - (byte)0xfa, (byte)0xfb, (byte)0xfc, - }; - int ethType = EtherTypes.IPv4.intValue(); - byte pcp = 0; - for (short vlan: vlans) { - Ethernet pkt = createEthernet(srcMac, dstMac, ethType, vlan, pcp, - ipv4); - matchTest(pkt); - - // Test non-IPv4 packet. - pkt = createEthernet(srcMac, dstMac, (short)100, vlan, pcp, - payload); - matchTest(pkt); - - // Test non-TCP packet. - for (IPv4 p: nonTcp) { - pkt = createEthernet(srcMac, dstMac, ethType, vlan, pcp, p); - matchTest(pkt); - } - } - } - - /** - * Run tests for {@link TcpMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)} - * using the given packet. - * - * @param pkt An {@link Ethernet} instance for test. - */ - private void matchTest(Ethernet pkt) { - PacketMatchTest test = new PacketMatchTest(); - TcpMatchImplBuilder builder = new TcpMatchImplBuilder(); - - TCP tcp = getTcpPacket(pkt); - if (tcp == null) { - // Should not match non-TCP packet. - assertEquals(false, test.run(builder.create(), pkt)); - - builder.setSourcePortFrom(123).setDestinationPortFrom(65000); - assertEquals(false, test.run(builder.create(), pkt)); - return; - } - - TcpParser tcpParser = new TcpParser(tcp); - int src = tcpParser.getSourcePort(); - int dst = tcpParser.getDestinationPort(); - - int anotherSrc = tcpParser.getAnotherSourcePort(); - int anotherDst = tcpParser.getAnotherDestinationPort(); - - // Empty match should match every packet. - assertEquals(true, test.run(builder.create(), pkt)); - - // Specify single field in TCP header. - TcpMatchImpl tmi = builder.reset().setSourcePortFrom(src).create(); - assertEquals(true, test.setMatchType(MatchType.TP_SRC).run(tmi, pkt)); - tmi = builder.reset().setSourcePortFrom(anotherSrc).create(); - assertEquals(false, test.run(tmi, pkt)); - - test.reset().setMatchType(MatchType.TP_DST); - tmi = builder.reset().setDestinationPortFrom(dst).create(); - assertEquals(true, test.run(tmi, pkt)); - tmi = builder.reset().setDestinationPortFrom(anotherDst).create(); - assertEquals(false, test.run(tmi, pkt)); - - // Specify port number by range. - int nrange = 100; - int srcFrom = src - nrange; - int srcTo = src + nrange; - test.reset().setMatchType(MatchType.TP_SRC); - tmi = builder.reset().setSourcePortFrom(srcFrom). - setSourcePortTo(srcTo).create(); - assertEquals(true, test.run(tmi, pkt)); - int bad = src + 1; - tmi = builder.setSourcePortFrom(bad).create(); - assertEquals(false, test.run(tmi, pkt)); - bad = src - 1; - tmi = builder.setSourcePortFrom(srcFrom).setSourcePortTo(bad).create(); - assertEquals(false, test.run(tmi, pkt)); - - int dstFrom = dst - nrange; - int dstTo = dst + nrange; - test.reset().setMatchType(MatchType.TP_DST); - tmi = builder.reset().setDestinationPortFrom(dstFrom). - setDestinationPortTo(dstTo).create(); - assertEquals(true, test.run(tmi, pkt)); - bad = dst + 1; - tmi = builder.setDestinationPortFrom(bad).create(); - assertEquals(false, test.run(tmi, pkt)); - bad = dst - 1; - tmi = builder.setDestinationPortFrom(dstFrom). - setDestinationPortTo(bad).create(); - assertEquals(false, test.run(tmi, pkt)); - - // Specify all fields. - test.reset().setMatchType(MatchType.TP_SRC, MatchType.TP_DST); - tmi = builder.reset(). - setSourcePortFrom(srcFrom).setSourcePortTo(srcTo). - setDestinationPortFrom(dstFrom).setDestinationPortTo(dstTo). - create(); - assertEquals(true, test.run(tmi, pkt)); - - test.reset().setMatchType(MatchType.TP_SRC); - tmi = builder.setSourcePortFrom(src + 1).create(); - assertEquals(false, test.run(tmi, pkt)); - - test.setMatchType(MatchType.TP_DST); - tmi = builder.setSourcePortFrom(src).setDestinationPortTo(dst - 1). - create(); - assertEquals(false, test.run(tmi, pkt)); - - tmi = builder.reset().setSourcePortFrom(src). - setDestinationPortFrom(dst).create(); - assertEquals(true, test.run(tmi, pkt)); - - test.reset().setMatchType(MatchType.TP_SRC); - tmi = builder.setSourcePortFrom(src + 1).create(); - assertEquals(false, test.run(tmi, pkt)); - - test.setMatchType(MatchType.TP_DST); - tmi = builder.setSourcePortFrom(src).setDestinationPortFrom(dst + 1). - create(); - assertEquals(false, test.run(tmi, pkt)); - } - - /** - * Return an {@link TCP} instance configured in the given packet. - * - * @param pkt An {@link Ethernet} instance. - * @return An {@link TCP} instance if found. - * {@code null} if not found. - */ - private TCP getTcpPacket(Ethernet pkt) { - Packet payload = pkt.getPayload(); - if (payload instanceof IEEE8021Q) { - IEEE8021Q tag = (IEEE8021Q)payload; - payload = tag.getPayload(); - } - - if (payload instanceof IPv4) { - IPv4 ipv4 = (IPv4)payload; - payload = ipv4.getPayload(); - if (payload instanceof TCP) { - return (TCP)payload; - } - } - - return null; - } -} - -/** - * Interface for {@link L4MatchImpl} builder. - */ -interface L4MatchImplBuilder { - /** - * Construct a new {@link L4Match} instance. - * - * @return A {@link L4Match} instance. - */ - L4Match getLayer4Match(); - - /** - * Set an integer value that specifies the source. - * - * @param src An integer value that specifies the source. - * @return This instance. - */ - L4MatchImplBuilder setSource(int src); - - /** - * Set an integer value that specifies the destination. - * - * @param dst An integer value that specifies the destination. - * @return This instance. - */ - L4MatchImplBuilder setDestination(int dst); -} - -/** - * Utility class to create {@link TcpMatchImpl} or instance. - */ -final class TcpMatchImplBuilder extends TestBase - implements L4MatchImplBuilder { - /** - * The minimum source port number to match. - */ - private Integer sourceFrom; - - /** - * The maximum source port number to match. - */ - private Integer sourceTo; - - /** - * The minimum destination port number to match. - */ - private Integer destinationFrom; - - /** - * The maximum destination port number to match. - */ - private Integer destinationTo; - - /** - * Created {@link TcpMatch} instance. - */ - private TcpMatch tcpMatch; - - /** - * Set the minumum source port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setSourcePortFrom(int port) { - sourceFrom = (port == -1) ? null : Integer.valueOf(port); - tcpMatch = null; - return this; - } - - /** - * Set the minumum source port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setSourcePortFrom(Integer port) { - sourceFrom = port; - tcpMatch = null; - return this; - } - - /** - * Set the maximum source port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setSourcePortTo(int port) { - sourceTo = (port == -1) ? null : Integer.valueOf(port); - tcpMatch = null; - return this; - } - - /** - * Set the maximum source port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setSourcePortTo(Integer port) { - sourceTo = port; - tcpMatch = null; - return this; - } - - /** - * Set the minumum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setDestinationPortFrom(int port) { - destinationFrom = (port == -1) ? null : Integer.valueOf(port); - tcpMatch = null; - return this; - } - - /** - * Set the minumum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setDestinationPortFrom(Integer port) { - destinationFrom = port; - tcpMatch = null; - return this; - } - - /** - * Set the maximum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setDestinationPortTo(int port) { - destinationTo = (port == -1) ? null : Integer.valueOf(port); - tcpMatch = null; - return this; - } - - /** - * Set the maximum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public TcpMatchImplBuilder setDestinationPortTo(Integer port) { - destinationTo = port; - tcpMatch = null; - return this; - } - - /** - * Reset to the initial state. - * - * @return This instance. - */ - public TcpMatchImplBuilder reset() { - sourceFrom = null; - sourceTo = null; - destinationFrom = null; - destinationTo = null; - tcpMatch = null; - - return this; - } - - /** - * Construct an {@link TcpMatch} instance. - * - * @return An {@link TcpMatch} instance. - */ - public TcpMatch getTcpMatch() { - TcpMatch tm = tcpMatch; - if (tm == null) { - PortMatch src = (sourceFrom == null) - ? null : new PortMatch(sourceFrom, sourceTo); - PortMatch dst = (destinationFrom == null) - ? null : new PortMatch(destinationFrom, destinationTo); - tm = new TcpMatch(src, dst); - tcpMatch = tm; - } - - return tm; - } - - /** - * Construct an {@link TcpMatchImpl} instance. - * - * @return An {@link TcpMatchImpl} instance. - * @throws VTNException An error occurred. - */ - public TcpMatchImpl build() throws VTNException { - TcpMatch tm = getTcpMatch(); - return new TcpMatchImpl(tm); - } - - /** - * Construct an {@link TcpMatchImpl} instance and ensure that it was - * constructed successfully. - * - * @return An {@link TcpMatchImpl} instance. - */ - public TcpMatchImpl create() { - TcpMatchImpl tmi = null; - try { - tmi = build(); - } catch (Exception e) { - unexpected(e); - } - - return tmi; - } - - /** - * Construct an {@link TcpMatchImpl} instance, and verify it. - */ - public void verify() { - TcpMatchImpl tmi = create(); - assertEquals(IPProtocols.TCP.shortValue(), tmi.getInetProtocol()); - - L4PortMatch src = tmi.getSourcePort(); - if (sourceFrom == null) { - assertEquals(null, src); - } else { - int from = sourceFrom.intValue(); - int to = (sourceTo == null) ? from : sourceTo.intValue(); - assertEquals(from, src.getPortFrom()); - assertEquals(to, src.getPortTo()); - } - - L4PortMatch dst = tmi.getDestinationPort(); - if (destinationFrom == null) { - assertEquals(null, dst); - } else { - int from = destinationFrom.intValue(); - int to = (destinationTo == null) ? from : destinationTo.intValue(); - assertEquals(from, dst.getPortFrom()); - assertEquals(to, dst.getPortTo()); - } - - // Instantiate using L4Match.create(). - TcpMatch tm = getTcpMatch(); - try { - assertEquals(tmi, L4MatchImpl.create(tm)); - } catch (Exception e) { - unexpected(e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public TcpMatch getLayer4Match() { - return getTcpMatch(); - } - - /** - * {@inheritDoc} - */ - @Override - public TcpMatchImplBuilder setSource(int src) { - return setSourcePortFrom(src); - } - - /** - * {@inheritDoc} - */ - @Override - public TcpMatchImplBuilder setDestination(int dst) { - return setDestinationPortFrom(dst); - } -} - -/** - * Interface for layer 4 protocol header parser. - */ -interface L4Parser { - /** - * Return an integer corresponding to the source. - * - * @return An integer corresponding to the source. - */ - int getSource(); - - /** - * Return an integer corresponding to the destination. - * - * @return An integer corresponding to the destination. - */ - int getDestination(); - - /** - * Return an integer corresponding to the source that does not match - * the packet. - * - * @return An integer corresponding to the source. - */ - int getAnotherSource(); - - /** - * Return an integer corresponding to the destination that does not match - * the packet. - * - * @return An integer corresponding to the destination. - */ - int getAnotherDestination(); -}; - -/** - * TCP header parser. - */ -final class TcpParser implements L4Parser { - /** - * TCP packet. - */ - private final TCP packet; - - /** - * Source port number. - */ - private final int sourcePort; - - /** - * Destination port number. - */ - private final int destinationPort; - - /** - * Construct a new instance. - * - * @param tcp A {@link TCP} instance. - */ - TcpParser(TCP tcp) { - packet = tcp; - sourcePort = NumberUtils.getUnsigned(tcp.getSourcePort()); - destinationPort = NumberUtils.getUnsigned(tcp.getDestinationPort()); - } - - /** - * Return the TCP packet. - * - * @return An {@link TCP} instance. - */ - public TCP getPacket() { - return packet; - } - - /** - * Return the source port number of this TCP packet. - * - * @return The source port number. - */ - public int getSourcePort() { - return sourcePort; - } - - /** - * Return the destination port number of this TCP packet. - * - * @return The destination port number. - */ - public int getDestinationPort() { - return destinationPort; - } - - /** - * Return a source port number that does not match this packet. - * - * @return A source port number that does not match this packet. - */ - public int getAnotherSourcePort() { - return (~sourcePort & 0xffff); - } - - /** - * Return a destination port number that does not match this packet. - * - * @return A destination port number that does not match this packet. - */ - public int getAnotherDestinationPort() { - return (~destinationPort & 0xffff); - } - - /** - * {@inheritDoc} - */ - @Override - public int getSource() { - return getSourcePort(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getDestination() { - return getDestinationPort(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getAnotherSource() { - return getAnotherSourcePort(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getAnotherDestination() { - return getAnotherDestinationPort(); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImplTest.java deleted file mode 100644 index 57a57c71..00000000 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/UdpMatchImplTest.java +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Copyright (c) 2014-2015 NEC Corporation - * 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.vtn.manager.internal.cluster; - -import java.net.InetAddress; -import java.util.HashSet; - -import org.junit.Test; - -import org.opendaylight.vtn.manager.VTNException; -import org.opendaylight.vtn.manager.flow.cond.PortMatch; -import org.opendaylight.vtn.manager.flow.cond.UdpMatch; -import org.opendaylight.vtn.manager.util.NumberUtils; - -import org.opendaylight.vtn.manager.internal.TestBase; - -import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.ICMP; -import org.opendaylight.controller.sal.packet.IEEE8021Q; -import org.opendaylight.controller.sal.packet.IPv4; -import org.opendaylight.controller.sal.packet.Packet; -import org.opendaylight.controller.sal.packet.UDP; -import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.IPProtocols; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; - -/** - * JUnit test for {@link UdpMatchImpl}. - */ -public class UdpMatchImplTest extends TestBase { - /** - * Test for {@link UdpMatchImpl#UdpMatchImpl(UdpMatch)}, - * {@link L4MatchImpl#create(org.opendaylight.vtn.manager.flow.cond.L4Match)}, - * and getter methods. - * - * @throws VTNException An error occurred. - */ - @Test - public void testConstructor() throws VTNException { - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int nranges = 3; - UdpMatchImplBuilder builder = new UdpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 0 : nranges; - int[] srcRange = new int[snr + 2]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i - 1; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 0 : nranges; - int[] dstRange = new int[dnr + 2]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i - 1; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - builder.verify(); - } - } - } - } - - // Specifying empty PortMatch. - PortMatch empty = new PortMatch((Integer)null); - UdpMatch um = new UdpMatch(empty, null); - try { - new UdpMatchImpl(um); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("source: \"from\" is not specified.", - st.getDescription()); - } - - um = new UdpMatch(null, empty); - try { - new UdpMatchImpl(um); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("destination: \"from\" is not specified.", - st.getDescription()); - } - - // Specifying bad port number. - Integer badPort = Integer.valueOf(-1); - um = new UdpMatch(badPort, null); - try { - new UdpMatchImpl(um); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("source: from: Invalid port number: " + badPort, - st.getDescription()); - } - - um = new UdpMatch(null, badPort); - try { - new UdpMatchImpl(um); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("destination: from: Invalid port number: " + badPort, - st.getDescription()); - } - - // Specifying invalid port range. - Integer badFrom = Integer.valueOf(3); - Integer badTo = Integer.valueOf(2); - PortMatch badRange = new PortMatch(badFrom, badTo); - um = new UdpMatch(badRange, null); - try { - new UdpMatchImpl(um); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("source: Invalid port range: from=" + badFrom + - ", to=" + badTo, st.getDescription()); - } - - um = new UdpMatch(null, badRange); - try { - new UdpMatchImpl(um); - unexpected(); - } catch (VTNException e) { - Status st = e.getStatus(); - assertEquals(StatusCode.BADREQUEST, st.getCode()); - assertEquals("destination: Invalid port range: from=" + badFrom + - ", to=" + badTo, st.getDescription()); - } - } - - /** - * Test case for {@link UdpMatchImpl#equals(Object)} and - * {@link UdpMatchImpl#hashCode()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testEquals() throws VTNException { - HashSet set = new HashSet(); - - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int count = 0; - int nranges = 3; - UdpMatchImplBuilder builder = new UdpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 1 : nranges; - int[] srcRange = new int[snr]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 1 : nranges; - int[] dstRange = new int[dnr]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - UdpMatchImpl umi1 = builder.create(); - UdpMatchImpl umi2 = builder.create(); - testEquals(set, umi1, umi2); - count++; - } - } - } - } - - assertEquals(count, set.size()); - } - - /** - * Test case for {@link UdpMatchImpl#toString()}. - * - * @throws VTNException An error occurred. - */ - @Test - public void testToString() throws VTNException { - String prefix = "UdpMatchImpl["; - String suffix = "]"; - - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int nranges = 3; - UdpMatchImplBuilder builder = new UdpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 1 : nranges; - int[] srcRange = new int[snr]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 1 : nranges; - int[] dstRange = new int[dnr]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - UdpMatchImpl umi = builder.create(); - - String s; - if (src == -1) { - s = null; - } else if (srcTo == -1 || src == srcTo) { - s = "src=" + src; - } else { - s = "src=" + src + "-" + srcTo; - } - - String d; - if (dst == -1) { - d = null; - } else if (dstTo == -1 || dst == dstTo) { - d = "dst=" + dst; - } else { - d = "dst=" + dst + "-" + dstTo; - } - - String required = joinStrings(prefix, suffix, ",", - s, d); - assertEquals(required, umi.toString()); - } - } - } - } - } - - /** - * Ensure that {@link UdpMatchImpl} is serializable. - * - * @throws VTNException An error occurred. - */ - @Test - public void testSerialize() throws VTNException { - int[] srcs = { - -1, 0, 4, 100, 678, 1357, 33445, 65535, - }; - int[] dsts = { - -1, 0, 8, 193, 783, 2674, 45678, 65535, - }; - - int nranges = 3; - UdpMatchImplBuilder builder = new UdpMatchImplBuilder(); - for (int src: srcs) { - builder.setSourcePortFrom(src); - - int snr = (src == -1 || src == 65535) ? 1 : nranges; - int[] srcRange = new int[snr]; - srcRange[0] = -1; - for (int i = 1; i < srcRange.length; i++) { - srcRange[i] = src + i; - } - for (int srcTo: srcRange) { - builder.setSourcePortTo(srcTo); - for (int dst: dsts) { - builder.setDestinationPortFrom(dst); - - int dnr = (dst == -1 || dst == 65535) ? 1 : nranges; - int[] dstRange = new int[dnr]; - dstRange[0] = -1; - for (int i = 1; i < dstRange.length; i++) { - dstRange[i] = dst + i; - } - for (int dstTo: dstRange) { - builder.setDestinationPortTo(dstTo); - UdpMatchImpl umi = builder.create(); - serializeTest(umi); - } - } - } - } - } - - /** - * Test case for {@link UdpMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)}. - * - * @throws Exception An error occurred. - */ - @Test - public void testMatch() throws Exception { - int srcPort = 123; - int dstPort = 65000; - byte[] payload = { - (byte)0x04, (byte)0xce, (byte)0xfe, (byte)0x21, - (byte)0xdc, (byte)0xb1, (byte)0x16, (byte)0x3b, - }; - UDP udp = new UDP(); - udp.setSourcePort((short)srcPort).setDestinationPort((short)dstPort). - setLength((short)123).setChecksum((short)0x1234); - - String saddr = "10.234.198.83"; - String daddr = "192.168.238.254"; - InetAddress src = InetAddress.getByName(saddr); - InetAddress dst = InetAddress.getByName(daddr); - short proto = IPProtocols.UDP.shortValue(); - byte dscp = 0; - IPv4 ipv4 = createIPv4(src, dst, proto, dscp); - ipv4.setPayload(udp); - - IPv4 nonUdp1 = createIPv4(src, dst, (short)100, dscp); - nonUdp1.setRawPayload(payload); - - ICMP icmp = new ICMP(); - icmp.setType((byte)0).setCode((byte)1).setIdentifier((short)0x1234). - setSequenceNumber((short)0x5678).setRawPayload(payload); - IPv4 nonUdp2 = createIPv4(src, dst, IPProtocols.ICMP.shortValue(), - dscp); - nonUdp2.setPayload(icmp); - IPv4[] nonUdp = {nonUdp1, nonUdp2}; - - // Run tests with changing VLAN ID. - short[] vlans = { - MatchType.DL_VLAN_NONE, 10, - }; - - byte[] srcMac = { - (byte)0x10, (byte)0x20, (byte)0x30, - (byte)0x40, (byte)0x50, (byte)0x60, - }; - byte[] dstMac = { - (byte)0xf0, (byte)0xf1, (byte)0xf2, - (byte)0xfa, (byte)0xfb, (byte)0xfc, - }; - int ethType = EtherTypes.IPv4.intValue(); - byte pcp = 0; - for (short vlan: vlans) { - Ethernet pkt = createEthernet(srcMac, dstMac, ethType, vlan, pcp, - ipv4); - matchTest(pkt); - - // Test non-IPv4 packet. - pkt = createEthernet(srcMac, dstMac, (short)100, vlan, pcp, - payload); - matchTest(pkt); - - // Test non-UDP packet. - for (IPv4 p: nonUdp) { - pkt = createEthernet(srcMac, dstMac, ethType, vlan, pcp, p); - matchTest(pkt); - } - } - } - - /** - * Run tests for {@link UdpMatchImpl#match(org.opendaylight.vtn.manager.internal.PacketContext)} - * using the given packet. - * - * @param pkt An {@link Ethernet} instance for test. - */ - private void matchTest(Ethernet pkt) { - PacketMatchTest test = new PacketMatchTest(); - UdpMatchImplBuilder builder = new UdpMatchImplBuilder(); - - UDP udp = getUdpPacket(pkt); - if (udp == null) { - // Should not match non-UDP packet. - assertEquals(false, test.run(builder.create(), pkt)); - - builder.setSourcePortFrom(123).setDestinationPortFrom(65000); - assertEquals(false, test.run(builder.create(), pkt)); - return; - } - - UdpParser udpParser = new UdpParser(udp); - int src = udpParser.getSourcePort(); - int dst = udpParser.getDestinationPort(); - - int anotherSrc = udpParser.getAnotherSourcePort(); - int anotherDst = udpParser.getAnotherDestinationPort(); - - // Empty match should match every packet. - assertEquals(true, test.run(builder.create(), pkt)); - - // Specify single field in UDP header. - UdpMatchImpl umi = builder.reset().setSourcePortFrom(src).create(); - assertEquals(true, test.setMatchType(MatchType.TP_SRC).run(umi, pkt)); - umi = builder.reset().setSourcePortFrom(anotherSrc).create(); - assertEquals(false, test.run(umi, pkt)); - - test.reset().setMatchType(MatchType.TP_DST); - umi = builder.reset().setDestinationPortFrom(dst).create(); - assertEquals(true, test.run(umi, pkt)); - umi = builder.reset().setDestinationPortFrom(anotherDst).create(); - assertEquals(false, test.run(umi, pkt)); - - // Specify port number by range. - int nrange = 100; - int srcFrom = src - nrange; - int srcTo = src + nrange; - test.reset().setMatchType(MatchType.TP_SRC); - umi = builder.reset().setSourcePortFrom(srcFrom). - setSourcePortTo(srcTo).create(); - assertEquals(true, test.run(umi, pkt)); - int bad = src + 1; - umi = builder.setSourcePortFrom(bad).create(); - assertEquals(false, test.run(umi, pkt)); - bad = src - 1; - umi = builder.setSourcePortFrom(srcFrom).setSourcePortTo(bad).create(); - assertEquals(false, test.run(umi, pkt)); - - int dstFrom = dst - nrange; - int dstTo = dst + nrange; - test.reset().setMatchType(MatchType.TP_DST); - umi = builder.reset().setDestinationPortFrom(dstFrom). - setDestinationPortTo(dstTo).create(); - assertEquals(true, test.run(umi, pkt)); - bad = dst + 1; - umi = builder.setDestinationPortFrom(bad).create(); - assertEquals(false, test.run(umi, pkt)); - bad = dst - 1; - umi = builder.setDestinationPortFrom(dstFrom). - setDestinationPortTo(bad).create(); - assertEquals(false, test.run(umi, pkt)); - - // Specify all fields. - test.reset().setMatchType(MatchType.TP_SRC, MatchType.TP_DST); - umi = builder.reset(). - setSourcePortFrom(srcFrom).setSourcePortTo(srcTo). - setDestinationPortFrom(dstFrom).setDestinationPortTo(dstTo). - create(); - assertEquals(true, test.run(umi, pkt)); - - test.reset().setMatchType(MatchType.TP_SRC); - umi = builder.setSourcePortFrom(src + 1).create(); - assertEquals(false, test.run(umi, pkt)); - - test.setMatchType(MatchType.TP_DST); - umi = builder.setSourcePortFrom(src).setDestinationPortTo(dst - 1). - create(); - assertEquals(false, test.run(umi, pkt)); - - umi = builder.reset().setSourcePortFrom(src). - setDestinationPortFrom(dst).create(); - assertEquals(true, test.run(umi, pkt)); - - test.reset().setMatchType(MatchType.TP_SRC); - umi = builder.setSourcePortFrom(src + 1).create(); - assertEquals(false, test.run(umi, pkt)); - - test.setMatchType(MatchType.TP_DST); - umi = builder.setSourcePortFrom(src).setDestinationPortFrom(dst + 1). - create(); - assertEquals(false, test.run(umi, pkt)); - } - - /** - * Return an {@link UDP} instance configured in the given packet. - * - * @param pkt An {@link Ethernet} instance. - * @return An {@link UDP} instance if found. - * {@code null} if not found. - */ - private UDP getUdpPacket(Ethernet pkt) { - Packet payload = pkt.getPayload(); - if (payload instanceof IEEE8021Q) { - IEEE8021Q tag = (IEEE8021Q)payload; - payload = tag.getPayload(); - } - - if (payload instanceof IPv4) { - IPv4 ipv4 = (IPv4)payload; - payload = ipv4.getPayload(); - if (payload instanceof UDP) { - return (UDP)payload; - } - } - - return null; - } -} - -/** - * Utility class to create {@link UdpMatchImpl} or instance. - */ -final class UdpMatchImplBuilder extends TestBase - implements L4MatchImplBuilder { - /** - * The minimum source port number to match. - */ - private Integer sourceFrom; - - /** - * The maximum source port number to match. - */ - private Integer sourceTo; - - /** - * The minimum destination port number to match. - */ - private Integer destinationFrom; - - /** - * The maximum destination port number to match. - */ - private Integer destinationTo; - - /** - * Created {@link UdpMatch} instance. - */ - private UdpMatch udpMatch; - - /** - * Set the minumum source port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setSourcePortFrom(int port) { - sourceFrom = (port == -1) ? null : Integer.valueOf(port); - udpMatch = null; - return this; - } - - /** - * Set the minumum source port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setSourcePortFrom(Integer port) { - sourceFrom = port; - udpMatch = null; - return this; - } - - /** - * Set the maximum source port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setSourcePortTo(int port) { - sourceTo = (port == -1) ? null : Integer.valueOf(port); - udpMatch = null; - return this; - } - - /** - * Set the maximum source port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setSourcePortTo(Integer port) { - sourceTo = port; - udpMatch = null; - return this; - } - - /** - * Set the minumum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setDestinationPortFrom(int port) { - destinationFrom = (port == -1) ? null : Integer.valueOf(port); - udpMatch = null; - return this; - } - - /** - * Set the minumum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setDestinationPortFrom(Integer port) { - destinationFrom = port; - udpMatch = null; - return this; - } - - /** - * Set the maximum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setDestinationPortTo(int port) { - destinationTo = (port == -1) ? null : Integer.valueOf(port); - udpMatch = null; - return this; - } - - /** - * Set the maximum destination port number. - * - * @param port Port number. - * @return This instance. - */ - public UdpMatchImplBuilder setDestinationPortTo(Integer port) { - destinationTo = port; - udpMatch = null; - return this; - } - - /** - * Reset to the initial state. - * - * @return This instance. - */ - public UdpMatchImplBuilder reset() { - sourceFrom = null; - sourceTo = null; - destinationFrom = null; - destinationTo = null; - udpMatch = null; - - return this; - } - - /** - * Construct an {@link UdpMatch} instance. - * - * @return An {@link UdpMatch} instance. - */ - public UdpMatch getUdpMatch() { - UdpMatch um = udpMatch; - if (um == null) { - PortMatch src = (sourceFrom == null) - ? null : new PortMatch(sourceFrom, sourceTo); - PortMatch dst = (destinationFrom == null) - ? null : new PortMatch(destinationFrom, destinationTo); - um = new UdpMatch(src, dst); - udpMatch = um; - } - - return um; - } - - /** - * Construct an {@link UdpMatchImpl} instance. - * - * @return An {@link UdpMatchImpl} instance. - * @throws VTNException An error occurred. - */ - public UdpMatchImpl build() throws VTNException { - UdpMatch um = getUdpMatch(); - return new UdpMatchImpl(um); - } - - /** - * Construct an {@link UdpMatchImpl} instance and ensure that it was - * constructed successfully. - * - * @return An {@link UdpMatchImpl} instance. - */ - public UdpMatchImpl create() { - UdpMatchImpl umi = null; - try { - umi = build(); - } catch (Exception e) { - unexpected(e); - } - - return umi; - } - - /** - * Construct an {@link UdpMatchImpl} instance, and verify it. - */ - public void verify() { - UdpMatchImpl umi = create(); - assertEquals(IPProtocols.UDP.shortValue(), umi.getInetProtocol()); - - L4PortMatch src = umi.getSourcePort(); - if (sourceFrom == null) { - assertEquals(null, src); - } else { - int from = sourceFrom.intValue(); - int to = (sourceTo == null) ? from : sourceTo.intValue(); - assertEquals(from, src.getPortFrom()); - assertEquals(to, src.getPortTo()); - } - - L4PortMatch dst = umi.getDestinationPort(); - if (destinationFrom == null) { - assertEquals(null, dst); - } else { - int from = destinationFrom.intValue(); - int to = (destinationTo == null) ? from : destinationTo.intValue(); - assertEquals(from, dst.getPortFrom()); - assertEquals(to, dst.getPortTo()); - } - - // Instantiate using L4Match.create(). - UdpMatch um = getUdpMatch(); - try { - assertEquals(umi, L4MatchImpl.create(um)); - } catch (Exception e) { - unexpected(e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public UdpMatch getLayer4Match() { - return getUdpMatch(); - } - - /** - * {@inheritDoc} - */ - @Override - public UdpMatchImplBuilder setSource(int src) { - return setSourcePortFrom(src); - } - - /** - * {@inheritDoc} - */ - @Override - public UdpMatchImplBuilder setDestination(int dst) { - return setDestinationPortFrom(dst); - } -} - -/** - * UDP header parser. - */ -final class UdpParser implements L4Parser { - /** - * UDP packet. - */ - private final UDP packet; - - /** - * Source port number. - */ - private final int sourcePort; - - /** - * Destination port number. - */ - private final int destinationPort; - - /** - * Construct a new instance. - * - * @param udp A {@link UDP} instance. - */ - UdpParser(UDP udp) { - packet = udp; - sourcePort = NumberUtils.getUnsigned(udp.getSourcePort()); - destinationPort = NumberUtils.getUnsigned(udp.getDestinationPort()); - } - - /** - * Return the UDP packet. - * - * @return An {@link UDP} instance. - */ - public UDP getPacket() { - return packet; - } - - /** - * Return the source port number of this UDP packet. - * - * @return The source port number. - */ - public int getSourcePort() { - return sourcePort; - } - - /** - * Return the destination port number of this UDP packet. - * - * @return The destination port number. - */ - public int getDestinationPort() { - return destinationPort; - } - - /** - * Return a source port number that does not match this packet. - * - * @return A source port number that does not match this packet. - */ - public int getAnotherSourcePort() { - return (~sourcePort & 0xffff); - } - - /** - * Return a destination port number that does not match this packet. - * - * @return A destination port number that does not match this packet. - */ - public int getAnotherDestinationPort() { - return (~destinationPort & 0xffff); - } - - /** - * {@inheritDoc} - */ - @Override - public int getSource() { - return getSourcePort(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getDestination() { - return getDestinationPort(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getAnotherSource() { - return getAnotherSourcePort(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getAnotherDestination() { - return getAnotherDestinationPort(); - } -} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacketTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacketTest.java index 04ae4ebc..0dfbc191 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacketTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacketTest.java @@ -22,6 +22,8 @@ import org.junit.Test; import org.opendaylight.vtn.manager.util.EtherAddress; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; import org.opendaylight.vtn.manager.internal.TestBase; @@ -101,7 +103,7 @@ public class EtherPacketTest extends TestBase { /** * VLAN priority for test. */ - private byte vlanPcp; + private short vlanPcp; /** * Test case for getter methods. @@ -112,59 +114,40 @@ public class EtherPacketTest extends TestBase { (byte)0x00, (byte)0x0a, (byte)0x7f, (byte)0x88, (byte)0xff, }; int[] types = {0x0001, 0x0815, 0x9999}; - short[] vlans = {0, 1, 2, 4095}; - boolean arrayFirst = true; + int[] vlans = {0, 1, 2, 4095}; ARP arp = createArp(); for (byte src: bytes) { byte[] srcAddr = { (byte)0x00, (byte)0x11, (byte)0x22, (byte)0x33, (byte)0x44, src, }; - long srcMac = EtherAddress.toLong(srcAddr); + EtherAddress srcMac = new EtherAddress(srcAddr); for (byte dst: bytes) { byte[] dstAddr = { (byte)0xf0, (byte)0xf1, (byte)0xf2, (byte)0xf3, (byte)0xf4, dst, }; - long dstMac = EtherAddress.toLong(dstAddr); + EtherAddress dstMac = new EtherAddress(dstAddr); for (int type: types) { - for (short vlan: vlans) { + for (int vlan: vlans) { // Create Ethernet frame using ARP packet. Ethernet pkt = createEthernet(srcAddr, dstAddr, type, - vlan, arp); + (short)vlan, arp); EtherPacket ether = new EtherPacket(pkt); - if (arrayFirst) { - assertArrayEquals(srcAddr, - ether.getSourceAddress()); - assertArrayEquals(dstAddr, - ether.getDestinationAddress()); - assertEquals(srcMac, ether.getSourceMacAddress()); - assertEquals(dstMac, - ether.getDestinationMacAddress()); - arrayFirst = false; - } else { - assertEquals(srcMac, ether.getSourceMacAddress()); - assertEquals(dstMac, - ether.getDestinationMacAddress()); - assertArrayEquals(srcAddr, - ether.getSourceAddress()); - assertArrayEquals(dstAddr, - ether.getDestinationAddress()); - arrayFirst = true; - } - + assertEquals(srcMac, ether.getSourceAddress()); + assertEquals(dstMac, ether.getDestinationAddress()); assertEquals(type, ether.getEtherType()); assertEquals(vlan, ether.getOriginalVlan()); - assertEquals(vlan, ether.getVlan()); + assertEquals(vlan, ether.getVlanId()); IEEE8021Q vlanTag; - if (vlan == MatchType.DL_VLAN_NONE) { + if (vlan == EtherHeader.VLAN_NONE) { assertTrue(ether.getVlanPriority() < 0); vlanTag = null; } else { assertEquals(vlanPcp, ether.getVlanPriority()); vlanTag = new IEEE8021Q(); - vlanTag.setCfi((byte)0).setPcp(vlanPcp). - setVid(vlan).setEtherType((short)type); + vlanTag.setCfi((byte)0).setPcp((byte)vlanPcp). + setVid((short)vlan).setEtherType((short)type); } assertEquals(vlanTag, ether.getVlanTag()); assertEquals(arp, ether.getPayload()); @@ -175,21 +158,18 @@ public class EtherPacketTest extends TestBase { pkt = createEthernet(srcAddr, dstAddr, type, vlan, RAW_PAYLOAD); ether = new EtherPacket(pkt); - assertArrayEquals(srcAddr, ether.getSourceAddress()); - assertArrayEquals(dstAddr, - ether.getDestinationAddress()); - assertEquals(srcMac, ether.getSourceMacAddress()); - assertEquals(dstMac, ether.getDestinationMacAddress()); + assertEquals(srcMac, ether.getSourceAddress()); + assertEquals(dstMac, ether.getDestinationAddress()); assertEquals(type, ether.getEtherType()); assertEquals(vlan, ether.getOriginalVlan()); - if (vlan == MatchType.DL_VLAN_NONE) { + if (vlan == EtherHeader.VLAN_NONE) { assertTrue(ether.getVlanPriority() < 0); vlanTag = null; } else { assertEquals(vlanPcp, ether.getVlanPriority()); vlanTag = new IEEE8021Q(); - vlanTag.setCfi((byte)0).setPcp(vlanPcp). - setVid(vlan).setEtherType((short)type); + vlanTag.setCfi((byte)0).setPcp((byte)vlanPcp). + setVid((short)vlan).setEtherType((short)type); } assertEquals(vlanTag, ether.getVlanTag()); assertEquals(null, ether.getPayload()); @@ -202,7 +182,7 @@ public class EtherPacketTest extends TestBase { assertFalse(ether.commit(pctx)); assertEquals(null, pctx.getFilterActions()); - for (MatchType mtype: MatchType.values()) { + for (FlowMatchType mtype: FlowMatchType.values()) { assertFalse(pctx.hasMatchField(mtype)); } } @@ -217,30 +197,30 @@ public class EtherPacketTest extends TestBase { @Test public void testSetter() { int type = 0x0806; - short[] vids = {MatchType.DL_VLAN_NONE, (short)1, (short)4095}; + short[] vids = {EtherHeader.VLAN_NONE, (short)1, (short)4095}; short vid1 = (short)1000; byte[] src0 = { (byte)0x10, (byte)0x20, (byte)0x30, (byte)0x40, (byte)0x50, (byte)0x60, }; - long srcMac0 = EtherAddress.toLong(src0); + EtherAddress srcMac0 = new EtherAddress(src0); byte[] dst0 = { (byte)0xf0, (byte)0xf1, (byte)0xf2, (byte)0xfa, (byte)0xfb, (byte)0xfc, }; - long dstMac0 = EtherAddress.toLong(dst0); + EtherAddress dstMac0 = new EtherAddress(dst0); byte[] src1 = { (byte)0xf0, (byte)0xf1, (byte)0xf2, (byte)0xf3, (byte)0xf4, (byte)0xf5, }; - long srcMac1 = EtherAddress.toLong(src1); + EtherAddress srcMac1 = new EtherAddress(src1); byte[] dst1 = { (byte)0xa0, (byte)0xbc, (byte)0xde, (byte)0xf1, (byte)0x23, (byte)0x45, }; - long dstMac1 = EtherAddress.toLong(dst1); + EtherAddress dstMac1 = new EtherAddress(dst1); byte[] src2 = { (byte)0xe0, (byte)0xe1, (byte)0xe2, @@ -271,10 +251,10 @@ public class EtherPacketTest extends TestBase { byte[] src = src0; byte[] dst = dst0; - long srcMac = srcMac0; - long dstMac = dstMac0; - short vlan = vid; - byte pcp = vlanPcp; + EtherAddress srcMac = srcMac0; + EtherAddress dstMac = dstMac0; + int vlan = vid; + short pcp = vlanPcp; boolean setPcp = false; boolean mod = false; @@ -288,21 +268,21 @@ public class EtherPacketTest extends TestBase { if ((flags & ETH_SRC) != 0) { // Modify source address. - ether1.setSourceAddress(src1); + ether1.setSourceAddress(srcMac1); src = src1; srcMac = srcMac1; mod = true; } if ((flags & ETH_DST) != 0) { // Modify destination address. - ether1.setDestinationAddress(dst1); + ether1.setDestinationAddress(dstMac1); dst = dst1; dstMac = dstMac1; mod = true; } if ((flags & ETH_VLAN_VID) != 0) { // Modify VLAN ID. - ether1.setVlan(outVid); + ether1.setVlanId(outVid); vlan = outVid; } if ((flags & ETH_VLAN_PCP) != 0) { @@ -310,21 +290,19 @@ public class EtherPacketTest extends TestBase { pcp = (byte)((pcp + 1) & 0x7); ether1.setVlanPriority(pcp); setPcp = true; - if (vlan != MatchType.DL_VLAN_NONE) { + if (vlan != EtherHeader.VLAN_NONE) { mod = true; } } ether1.setPayload(anotherArp); assertSame(anotherArp, ether1.getPayload()); - assertArrayEquals(src, ether1.getSourceAddress()); - assertEquals(srcMac, ether1.getSourceMacAddress()); - assertArrayEquals(dst, ether1.getDestinationAddress()); - assertEquals(dstMac, ether1.getDestinationMacAddress()); + assertEquals(srcMac, ether1.getSourceAddress()); + assertEquals(dstMac, ether1.getDestinationAddress()); assertEquals(type, ether1.getEtherType()); - assertEquals(vlan, ether1.getVlan()); + assertEquals(vlan, ether1.getVlanId()); assertEquals(vid, ether1.getOriginalVlan()); - if (vid == MatchType.DL_VLAN_NONE && !setPcp) { + if (vid == EtherHeader.VLAN_NONE && !setPcp) { assertTrue(ether1.getVlanPriority() < 0); } else { assertEquals(pcp, ether1.getVlanPriority()); @@ -334,7 +312,7 @@ public class EtherPacketTest extends TestBase { // not configured in outgoing packet. List actions = new ArrayList(); for (Action act: salActions.values()) { - if (!(vlan == MatchType.DL_VLAN_NONE && + if (!(vlan == EtherHeader.VLAN_NONE && SetVlanPcp.class.isInstance(act))) { actions.add(act); } @@ -354,11 +332,11 @@ public class EtherPacketTest extends TestBase { if ((flags & ETH_DST) != 0) { actions.add(salActions.get(SetDlDst.class)); } - if (vlan != MatchType.DL_VLAN_NONE && + if (vlan != EtherHeader.VLAN_NONE && (flags & ETH_VLAN_PCP) != 0) { actions.add(salActions.get(SetVlanPcp.class)); } - for (MatchType mt: MatchType.values()) { + for (FlowMatchType mt: FlowMatchType.values()) { pctx.addMatchField(mt); } @@ -371,7 +349,7 @@ public class EtherPacketTest extends TestBase { assertSame(pkt, ether1.getPacket()); assertArrayEquals(src0, pkt.getSourceMACAddress()); assertArrayEquals(dst0, pkt.getDestinationMACAddress()); - if (vid == MatchType.DL_VLAN_NONE) { + if (vid == EtherHeader.VLAN_NONE) { assertEquals((short)type, pkt.getEtherType()); assertSame(arp, pkt.getPayload()); } else { @@ -384,64 +362,52 @@ public class EtherPacketTest extends TestBase { } // The original packet should not be affected. - assertArrayEquals(src0, ether.getSourceAddress()); - assertEquals(srcMac0, ether.getSourceMacAddress()); - assertArrayEquals(dst0, ether.getDestinationAddress()); - assertEquals(dstMac0, ether.getDestinationMacAddress()); + assertEquals(srcMac0, ether.getSourceAddress()); + assertEquals(dstMac0, ether.getDestinationAddress()); assertEquals(type, ether.getEtherType()); assertSame(arp, ether.getPayload()); - if (vid == MatchType.DL_VLAN_NONE) { + if (vid == EtherHeader.VLAN_NONE) { assertTrue(ether.getVlanPriority() < 0); } else { assertEquals(vlanPcp, ether.getVlanPriority()); } // Set values in the original packet. - ether1.setSourceAddress(src0); - ether1.setDestinationAddress(dst0); - ether1.setVlan(vid); + ether1.setSourceAddress(srcMac0); + ether1.setDestinationAddress(dstMac0); + ether1.setVlanId(vid); ether1.setVlanPriority(vlanPcp); assertEquals(false, ether1.commit(pctx)); - assertArrayEquals(src0, ether1.getSourceAddress()); - assertEquals(srcMac0, ether1.getSourceMacAddress()); - assertArrayEquals(dst0, ether1.getDestinationAddress()); - assertEquals(dstMac0, ether1.getDestinationMacAddress()); - assertEquals(vid, ether1.getVlan()); + assertEquals(srcMac0, ether1.getSourceAddress()); + assertEquals(dstMac0, ether1.getDestinationAddress()); + assertEquals(vid, ether1.getVlanId()); assertEquals(vlanPcp, ether1.getVlanPriority()); assertEquals(type, ether1.getEtherType()); // Ensure that a set of modified values is deeply cloned. EtherPacket ether2 = ether1.clone(); - assertArrayEquals(src0, ether1.getSourceAddress()); - assertEquals(srcMac0, ether1.getSourceMacAddress()); - assertArrayEquals(dst0, ether1.getDestinationAddress()); - assertEquals(dstMac0, ether1.getDestinationMacAddress()); - assertEquals(vid, ether1.getVlan()); + assertEquals(srcMac0, ether1.getSourceAddress()); + assertEquals(dstMac0, ether1.getDestinationAddress()); + assertEquals(vid, ether1.getVlanId()); assertEquals(vlanPcp, ether1.getVlanPriority()); assertEquals(type, ether1.getEtherType()); - assertArrayEquals(src0, ether2.getSourceAddress()); - assertEquals(srcMac0, ether2.getSourceMacAddress()); - assertArrayEquals(dst0, ether2.getDestinationAddress()); - assertEquals(dstMac0, ether2.getDestinationMacAddress()); - assertEquals(vid, ether2.getVlan()); + assertEquals(srcMac0, ether2.getSourceAddress()); + assertEquals(dstMac0, ether2.getDestinationAddress()); + assertEquals(vid, ether2.getVlanId()); assertEquals(vlanPcp, ether2.getVlanPriority()); assertEquals(type, ether2.getEtherType()); - ether2.setSourceAddress(src1); - ether2.setDestinationAddress(dst1); - ether2.setVlan(vid1); + ether2.setSourceAddress(srcMac1); + ether2.setDestinationAddress(dstMac1); + ether2.setVlanId(vid1); ether2.setVlanPriority(pcp); - assertArrayEquals(src0, ether1.getSourceAddress()); - assertEquals(srcMac0, ether1.getSourceMacAddress()); - assertArrayEquals(dst0, ether1.getDestinationAddress()); - assertEquals(dstMac0, ether1.getDestinationMacAddress()); - assertEquals(vid, ether1.getVlan()); + assertEquals(srcMac0, ether1.getSourceAddress()); + assertEquals(dstMac0, ether1.getDestinationAddress()); + assertEquals(vid, ether1.getVlanId()); assertEquals(vlanPcp, ether1.getVlanPriority()); assertEquals(type, ether1.getEtherType()); - assertArrayEquals(src1, ether2.getSourceAddress()); - assertEquals(srcMac1, ether2.getSourceMacAddress()); - assertArrayEquals(dst1, ether2.getDestinationAddress()); - assertEquals(dstMac1, ether2.getDestinationMacAddress()); - assertEquals(vid1, ether2.getVlan()); + assertEquals(srcMac1, ether2.getSourceAddress()); + assertEquals(dstMac1, ether2.getDestinationAddress()); + assertEquals(vid1, ether2.getVlanId()); assertEquals(pcp, ether2.getVlanPriority()); assertEquals(type, ether2.getEtherType()); } @@ -463,12 +429,13 @@ public class EtherPacketTest extends TestBase { (byte)0xfa, (byte)0xfb, (byte)0xfc, }; int type = 0x0806; - short[] vids = {MatchType.DL_VLAN_NONE, (short)1, (short)4095}; - Map dlFields = - new HashMap(); - dlFields.put(MatchType.DL_SRC, new MatchField(MatchType.DL_SRC, src)); - dlFields.put(MatchType.DL_DST, new MatchField(MatchType.DL_DST, dst)); - dlFields.put(MatchType.DL_TYPE, + short[] vids = {EtherHeader.VLAN_NONE, (short)1, (short)4095}; + Map dlFields = new HashMap<>(); + dlFields.put(FlowMatchType.DL_SRC, + new MatchField(MatchType.DL_SRC, src)); + dlFields.put(FlowMatchType.DL_DST, + new MatchField(MatchType.DL_DST, dst)); + dlFields.put(FlowMatchType.DL_TYPE, new MatchField(MatchType.DL_TYPE, Short.valueOf((short)type))); @@ -490,31 +457,33 @@ public class EtherPacketTest extends TestBase { // VLAN ID must be configured even if the type set is empty. MatchField vlanVid = new MatchField(MatchType.DL_VLAN, Short.valueOf(vid)); - dlFields.put(MatchType.DL_VLAN_PR, + dlFields.put(FlowMatchType.DL_VLAN_PCP, new MatchField(MatchType.DL_VLAN_PR, - Byte.valueOf(vlanPcp))); + Byte.valueOf((byte)vlanPcp))); Match match = new Match(); - Set fields = EnumSet.noneOf(MatchType.class); + Set fields = EnumSet.noneOf(FlowMatchType.class); ether.setMatch(match, fields); List matches = match.getMatchesList(); assertEquals(1, matches.size()); assertEquals(vlanVid, match.getField(MatchType.DL_VLAN)); - for (Map.Entry entry: dlFields.entrySet()) { - MatchType mtype = entry.getKey(); + for (Map.Entry entry: + dlFields.entrySet()) { + FlowMatchType fmtype = entry.getKey(); + MatchField mfield = entry.getValue(); + MatchType mtype = mfield.getType(); match = new Match(); - fields = EnumSet.of(mtype); + fields = EnumSet.of(fmtype); ether.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(vlanVid, match.getField(MatchType.DL_VLAN)); - if (vid == MatchType.DL_VLAN_NONE && - mtype == MatchType.DL_VLAN_PR) { + if (vid == EtherHeader.VLAN_NONE && + fmtype == FlowMatchType.DL_VLAN_PCP) { assertEquals(1, matches.size()); assertEquals(null, match.getField(mtype)); } else { - MatchField mfield = entry.getValue(); assertEquals(2, matches.size()); assertEquals(mfield, match.getField(mtype)); } @@ -522,26 +491,24 @@ public class EtherPacketTest extends TestBase { // setMatch() always has to see the original. byte pri = (byte)((vlanPcp + 1) & 0x7); - ether.setSourceAddress(src1); - ether.setDestinationAddress(dst1); - ether.setVlan((short)((vid + 1) & 0xfff)); + ether.setSourceAddress(new EtherAddress(src1)); + ether.setDestinationAddress(new EtherAddress(dst1)); + ether.setVlanId((vid + 1) & 0xfff); ether.setVlanPriority(vlanPcp); - fields = EnumSet.noneOf(MatchType.class); + fields = EnumSet.noneOf(FlowMatchType.class); fields.addAll(dlFields.keySet()); - fields.add(MatchType.DL_VLAN); + fields.add(FlowMatchType.DL_VLAN); match = new Match(); ether.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(vlanVid, match.getField(MatchType.DL_VLAN)); - if (vid == MatchType.DL_VLAN_NONE) { + if (vid == EtherHeader.VLAN_NONE) { assertEquals(dlFields.size(), matches.size()); assertEquals(null, match.getField(MatchType.DL_VLAN_PR)); } else { assertEquals(dlFields.size() + 1, matches.size()); - for (Map.Entry entry: - dlFields.entrySet()) { - MatchType mtype = entry.getKey(); - MatchField mfield = entry.getValue(); + for (MatchField mfield: dlFields.values()) { + MatchType mtype = mfield.getType(); assertEquals(mfield, match.getField(mtype)); } } @@ -559,16 +526,16 @@ public class EtherPacketTest extends TestBase { * @return An {@link Ethernet} instance. */ private Ethernet createEthernet(byte[] src, byte[] dst, int type, - short vid, Packet payload) { - byte pcp; - if (vid == MatchType.DL_VLAN_NONE) { + int vid, Packet payload) { + short pcp; + if (vid == EtherHeader.VLAN_NONE) { pcp = 0; } else { - pcp = (byte)((vlanPcp + 1) & 7); + pcp = (short)((vlanPcp + 1) & 7); vlanPcp = pcp; } - return createEthernet(src, dst, type, vid, pcp, payload); + return createEthernet(src, dst, type, (short)vid, (byte)pcp, payload); } /** @@ -582,16 +549,16 @@ public class EtherPacketTest extends TestBase { * @return An {@link Ethernet} instance. */ private Ethernet createEthernet(byte[] src, byte[] dst, int type, - short vid, byte[] raw) { - byte pcp; - if (vid == MatchType.DL_VLAN_NONE) { + int vid, byte[] raw) { + short pcp; + if (vid == EtherHeader.VLAN_NONE) { pcp = 0; } else { - pcp = (byte)((vlanPcp + 1) & 7); + pcp = (short)((vlanPcp + 1) & 7); vlanPcp = pcp; } - return createEthernet(src, dst, type, vid, pcp, raw); + return createEthernet(src, dst, type, (short)vid, (byte)pcp, raw); } /** diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacketTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacketTest.java index 861ab22e..8aa6d669 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacketTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacketTest.java @@ -20,6 +20,7 @@ import java.util.Set; import org.junit.Test; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; import org.opendaylight.vtn.manager.internal.TestBase; @@ -76,8 +77,8 @@ public class IcmpPacketTest extends TestBase { for (short code: codes) { ICMP pkt = createICMP(type, code); IcmpPacket icmp = new IcmpPacket(pkt); - assertEquals(type, icmp.getType()); - assertEquals(code, icmp.getCode()); + assertEquals(type, icmp.getIcmpType()); + assertEquals(code, icmp.getIcmpCode()); // commit() should return false. Ethernet ether = createEthernet(pkt); @@ -85,7 +86,7 @@ public class IcmpPacketTest extends TestBase { ether, EtherPacketTest.NODE_CONNECTOR); assertFalse(icmp.commit(pctx)); assertEquals(null, pctx.getFilterActions()); - for (MatchType mtype: MatchType.values()) { + for (FlowMatchType mtype: FlowMatchType.values()) { assertFalse(pctx.hasMatchField(mtype)); } } @@ -133,17 +134,17 @@ public class IcmpPacketTest extends TestBase { if ((flags & ICMP_TYPE) != 0) { // Modify ICMP type. - icmp1.setType(type1); + icmp1.setIcmpType(type1); type = type1; } if ((flags & ICMP_CODE) != 0) { // Modify ICMP code. - icmp1.setCode(code1); + icmp1.setIcmpCode(code1); code = code1; } - assertEquals(type, icmp1.getType()); - assertEquals(code, icmp1.getCode()); + assertEquals(type, icmp1.getIcmpType()); + assertEquals(code, icmp1.getIcmpCode()); // The packet should not be modified until commit() is called. assertSame(pkt, icmp1.getPacket()); @@ -162,8 +163,8 @@ public class IcmpPacketTest extends TestBase { assertEquals(identifier, pkt.getIdentifier()); assertEquals(sequenceNumber, pkt.getSequenceNumber()); - assertTrue(pctx.hasMatchField(MatchType.DL_TYPE)); - assertTrue(pctx.hasMatchField(MatchType.NW_PROTO)); + assertTrue(pctx.hasMatchField(FlowMatchType.DL_TYPE)); + assertTrue(pctx.hasMatchField(FlowMatchType.IP_PROTO)); // updateChecksum() must return false. assertFalse(icmp.updateChecksum(null)); @@ -184,7 +185,7 @@ public class IcmpPacketTest extends TestBase { } pctx = createPacketContext(ether, EtherPacketTest.NODE_CONNECTOR); - for (MatchType mt: MatchType.values()) { + for (FlowMatchType mt: FlowMatchType.values()) { pctx.addMatchField(mt); } for (Action act: salActions.values()) { @@ -196,8 +197,8 @@ public class IcmpPacketTest extends TestBase { assertEquals(actions, filterActions); // The original packet should not be affected. - assertEquals(type0, icmp.getType()); - assertEquals(code0, icmp.getCode()); + assertEquals(type0, icmp.getIcmpType()); + assertEquals(code0, icmp.getIcmpCode()); assertSame(pkt, icmp.getPacket()); assertEquals((byte)type0, pkt.getType()); @@ -207,24 +208,24 @@ public class IcmpPacketTest extends TestBase { assertEquals(sequenceNumber, pkt.getSequenceNumber()); // Set values in the original packet. - icmp1.setType(type0); - icmp1.setCode(code0); + icmp1.setIcmpType(type0); + icmp1.setIcmpCode(code0); assertEquals(false, icmp1.commit(pctx)); - assertEquals(type0, icmp1.getType()); - assertEquals(code0, icmp1.getCode()); + assertEquals(type0, icmp1.getIcmpType()); + assertEquals(code0, icmp1.getIcmpCode()); // Ensure that a set of modified values is deeply cloned. IcmpPacket icmp2 = icmp1.clone(); - assertEquals(type0, icmp1.getType()); - assertEquals(code0, icmp1.getCode()); - assertEquals(type0, icmp2.getType()); - assertEquals(code0, icmp2.getCode()); - icmp2.setType(type1); - icmp2.setCode(code1); - assertEquals(type0, icmp1.getType()); - assertEquals(code0, icmp1.getCode()); - assertEquals(type1, icmp2.getType()); - assertEquals(code1, icmp2.getCode()); + assertEquals(type0, icmp1.getIcmpType()); + assertEquals(code0, icmp1.getIcmpCode()); + assertEquals(type0, icmp2.getIcmpType()); + assertEquals(code0, icmp2.getIcmpCode()); + icmp2.setIcmpType(type1); + icmp2.setIcmpCode(code1); + assertEquals(type0, icmp1.getIcmpType()); + assertEquals(code0, icmp1.getIcmpCode()); + assertEquals(type1, icmp2.getIcmpType()); + assertEquals(code1, icmp2.getIcmpCode()); } } @@ -235,10 +236,11 @@ public class IcmpPacketTest extends TestBase { public void testSetMatch() { short type = 33; short code = 66; - Map tpFields = - new HashMap(); - tpFields.put(MatchType.TP_SRC, new MatchField(MatchType.TP_SRC, type)); - tpFields.put(MatchType.TP_DST, new MatchField(MatchType.TP_DST, code)); + Map tpFields = new HashMap<>(); + tpFields.put(FlowMatchType.ICMP_TYPE, + new MatchField(MatchType.TP_SRC, type)); + tpFields.put(FlowMatchType.ICMP_CODE, + new MatchField(MatchType.TP_DST, code)); short type1 = 29; short code1 = 1; @@ -246,17 +248,18 @@ public class IcmpPacketTest extends TestBase { IcmpPacket icmp = new IcmpPacket(pkt); Match match = new Match(); - Set fields = EnumSet.noneOf(MatchType.class); + Set fields = EnumSet.noneOf(FlowMatchType.class); icmp.setMatch(match, fields); List matches = match.getMatchesList(); assertEquals(0, matches.size()); - for (Map.Entry entry: tpFields.entrySet()) { - MatchType mtype = entry.getKey(); + for (Map.Entry entry: tpFields.entrySet()) { + FlowMatchType fmtype = entry.getKey(); MatchField mfield = entry.getValue(); + MatchType mtype = mfield.getType(); match = new Match(); - fields = EnumSet.of(mtype); + fields = EnumSet.of(fmtype); icmp.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(1, matches.size()); @@ -264,17 +267,16 @@ public class IcmpPacketTest extends TestBase { } // setMatch() always has to see the original. - icmp.setType(type1); - icmp.setCode(code1); - fields = EnumSet.noneOf(MatchType.class); + icmp.setIcmpType(type1); + icmp.setIcmpCode(code1); + fields = EnumSet.noneOf(FlowMatchType.class); fields.addAll(tpFields.keySet()); match = new Match(); icmp.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(tpFields.size(), matches.size()); - for (Map.Entry entry: tpFields.entrySet()) { - MatchType mtype = entry.getKey(); - MatchField mfield = entry.getValue(); + for (MatchField mfield: tpFields.values()) { + MatchType mtype = mfield.getType(); assertEquals(mfield, match.getField(mtype)); } } diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4PacketTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4PacketTest.java index 83adc6e7..e72a22ca 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4PacketTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4PacketTest.java @@ -9,7 +9,6 @@ package org.opendaylight.vtn.manager.internal.packet.cache; -import java.net.InetAddress; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -21,9 +20,11 @@ import java.util.Set; import org.junit.Test; +import org.opendaylight.vtn.manager.util.Ip4Network; import org.opendaylight.vtn.manager.util.NumberUtils; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; import org.opendaylight.vtn.manager.internal.TestBase; @@ -73,33 +74,18 @@ public class Inet4PacketTest extends TestBase { }; short[] protocols = {3, 15, 100, 255}; byte[] dscps = {(byte)0, (byte)1, (byte)10, (byte)40, (byte)63}; - boolean inetFirst = true; for (byte s: bytes) { byte[] srcBytes = {(byte)10, (byte)1, (byte)2, s}; - InetAddress src = createInetAddress(srcBytes); - int srcAddr = NumberUtils.toInteger(srcBytes); + Ip4Network src = new Ip4Network(srcBytes); for (byte d: bytes) { byte[] dstBytes = {(byte)192, (byte)168, (byte)200, d}; - InetAddress dst = createInetAddress(dstBytes); - int dstAddr = NumberUtils.toInteger(dstBytes); + Ip4Network dst = new Ip4Network(dstBytes); for (short proto: protocols) { for (byte dscp: dscps) { IPv4 pkt = createIPv4Packet(src, dst, proto, dscp); Inet4Packet ipv4 = new Inet4Packet(pkt); - if (inetFirst) { - assertEquals(src, ipv4.getSourceInetAddress()); - assertEquals(dst, ipv4.getDestinationInetAddress()); - assertEquals(srcAddr, ipv4.getSourceAddress()); - assertEquals(dstAddr, ipv4.getDestinationAddress()); - inetFirst = false; - } else { - assertEquals(srcAddr, ipv4.getSourceAddress()); - assertEquals(dstAddr, ipv4.getDestinationAddress()); - assertEquals(src, ipv4.getSourceInetAddress()); - assertEquals(dst, ipv4.getDestinationInetAddress()); - inetFirst = true; - } - + assertEquals(src, ipv4.getSourceAddress()); + assertEquals(dst, ipv4.getDestinationAddress()); assertEquals(proto, ipv4.getProtocol()); assertEquals(dscp, ipv4.getDscp()); assertEquals(false, ipv4.isAddressModified()); @@ -111,7 +97,7 @@ public class Inet4PacketTest extends TestBase { assertFalse(ipv4.commit(pctx)); assertEquals(null, pctx.getFilterActions()); - for (MatchType mtype: MatchType.values()) { + for (FlowMatchType mtype: FlowMatchType.values()) { assertFalse(pctx.hasMatchField(mtype)); } } @@ -133,40 +119,32 @@ public class Inet4PacketTest extends TestBase { byte[] srcBytes0 = {(byte)192, (byte)168, (byte)33, (byte)44}; byte[] dstBytes0 = {(byte)172, (byte)30, (byte)40, (byte)50}; - InetAddress src0 = createInetAddress(srcBytes0); - InetAddress dst0 = createInetAddress(dstBytes0); - int srcAddr0 = NumberUtils.toInteger(srcBytes0); - int dstAddr0 = NumberUtils.toInteger(dstBytes0); + Ip4Network src0 = new Ip4Network(srcBytes0); + Ip4Network dst0 = new Ip4Network(dstBytes0); byte[] srcBytes1 = {(byte)127, (byte)0, (byte)0, (byte)1}; byte[] dstBytes1 = {(byte)10, (byte)100, (byte)220, (byte)254}; - InetAddress src1 = createInetAddress(srcBytes1); - InetAddress dst1 = createInetAddress(dstBytes1); - int srcAddr1 = NumberUtils.toInteger(srcBytes1); - int dstAddr1 = NumberUtils.toInteger(dstBytes1); + Ip4Network src1 = new Ip4Network(srcBytes1); + Ip4Network dst1 = new Ip4Network(dstBytes1); byte[] srcBytes2 = {(byte)127, (byte)0, (byte)0, (byte)1}; byte[] dstBytes2 = {(byte)10, (byte)100, (byte)220, (byte)254}; - InetAddress src2 = createInetAddress(srcBytes1); - InetAddress dst2 = createInetAddress(dstBytes2); - int srcAddr2 = NumberUtils.toInteger(srcBytes2); - int dstAddr2 = NumberUtils.toInteger(dstBytes2); + Ip4Network src2 = new Ip4Network(srcBytes1); + Ip4Network dst2 = new Ip4Network(dstBytes2); byte dscp2 = 30; Map, Action> salActions = new LinkedHashMap, Action>(); - salActions.put(SetNwSrc.class, new SetNwSrc(src2)); - salActions.put(SetNwDst.class, new SetNwDst(dst2)); + salActions.put(SetNwSrc.class, new SetNwSrc(src2.getInetAddress())); + salActions.put(SetNwDst.class, new SetNwDst(dst2.getInetAddress())); salActions.put(SetNwTos.class, new SetNwTos(dscp2)); for (int flags = IPV4_SRC; flags <= IPV4_ALL; flags++) { IPv4 pkt = createIPv4Packet(src0, dst0, proto, dscp0); Inet4Packet ipv4 = new Inet4Packet(pkt); - InetAddress src = src0; - InetAddress dst = dst0; - int srcAddr = srcAddr0; - int dstAddr = dstAddr0; + Ip4Network src = src0; + Ip4Network dst = dst0; byte dscp = dscp0; Ethernet ether = createEthernet(pkt); @@ -182,14 +160,12 @@ public class Inet4PacketTest extends TestBase { // Modify source address. ip.setSourceAddress(src1); src = src1; - srcAddr = srcAddr1; addrModified = true; } if ((flags & IPV4_DST) != 0) { // Modify destination address. ip.setDestinationAddress(dst1); dst = dst1; - dstAddr = dstAddr1; addrModified = true; } if ((flags & IPV4_DSCP) != 0) { @@ -198,10 +174,8 @@ public class Inet4PacketTest extends TestBase { dscp = dscp1; } - assertEquals(src, ip.getSourceInetAddress()); - assertEquals(srcAddr, ip.getSourceAddress()); - assertEquals(dst, ip.getDestinationInetAddress()); - assertEquals(dstAddr, ip.getDestinationAddress()); + assertEquals(src, ip.getSourceAddress()); + assertEquals(dst, ip.getDestinationAddress()); assertEquals(proto, ip.getProtocol()); assertEquals(dscp, ip.getDscp()); assertEquals(addrModified, ip.isAddressModified()); @@ -212,8 +186,8 @@ public class Inet4PacketTest extends TestBase { assertEquals(true, ip.commit(pctx)); IPv4 newPkt = ip.getPacket(); assertNotSame(pkt, newPkt); - assertEquals(srcAddr, newPkt.getSourceAddress()); - assertEquals(dstAddr, newPkt.getDestinationAddress()); + assertEquals(src.getAddress(), newPkt.getSourceAddress()); + assertEquals(dst.getAddress(), newPkt.getDestinationAddress()); assertEquals((byte)proto, newPkt.getProtocol()); assertEquals(dscp, newPkt.getDiffServ()); @@ -221,7 +195,7 @@ public class Inet4PacketTest extends TestBase { new ArrayList(pctx.getFilterActions()); assertEquals(new ArrayList(salActions.values()), filterActions); - assertTrue(pctx.hasMatchField(MatchType.DL_TYPE)); + assertTrue(pctx.hasMatchField(FlowMatchType.DL_TYPE)); // Actions for unchanged field will be removed if corresponding // match type is configured in PacketContext. @@ -237,7 +211,7 @@ public class Inet4PacketTest extends TestBase { } pctx = createPacketContext(ether, EtherPacketTest.NODE_CONNECTOR); - for (MatchType mt: MatchType.values()) { + for (FlowMatchType mt: FlowMatchType.values()) { pctx.addMatchField(mt); } for (Action act: salActions.values()) { @@ -249,14 +223,14 @@ public class Inet4PacketTest extends TestBase { assertEquals(actions, filterActions); // The original packet should not be affected. - assertEquals(srcAddr0, ipv4.getSourceAddress()); - assertEquals(dstAddr0, ipv4.getDestinationAddress()); + assertEquals(src0, ipv4.getSourceAddress()); + assertEquals(dst0, ipv4.getDestinationAddress()); assertEquals(proto, ipv4.getProtocol()); assertEquals(dscp0, ipv4.getDscp()); assertSame(pkt, ipv4.getPacket()); - assertEquals(srcAddr0, pkt.getSourceAddress()); - assertEquals(dstAddr0, pkt.getDestinationAddress()); + assertEquals(src0.getAddress(), pkt.getSourceAddress()); + assertEquals(dst0.getAddress(), pkt.getDestinationAddress()); assertEquals((byte)proto, pkt.getProtocol()); assertEquals(dscp0, pkt.getDiffServ()); @@ -265,40 +239,31 @@ public class Inet4PacketTest extends TestBase { ip.setDestinationAddress(dst0); ip.setDscp(dscp0); assertEquals(false, ip.commit(pctx)); - assertEquals(src0, ip.getSourceInetAddress()); - assertEquals(srcAddr0, ip.getSourceAddress()); - assertEquals(dst0, ip.getDestinationInetAddress()); - assertEquals(dstAddr0, ip.getDestinationAddress()); + assertEquals(src0, ip.getSourceAddress()); + assertEquals(dst0, ip.getDestinationAddress()); assertEquals(proto, ip.getProtocol()); assertEquals(dscp0, ip.getDscp()); // Ensure that a set of modified values is deeply cloned. Inet4Packet ip1 = ip.clone(); - assertEquals(src0, ip.getSourceInetAddress()); - assertEquals(srcAddr0, ip.getSourceAddress()); - assertEquals(dst0, ip.getDestinationInetAddress()); - assertEquals(dstAddr0, ip.getDestinationAddress()); + assertEquals(src0, ip.getSourceAddress()); + assertEquals(dst0, ip.getDestinationAddress()); assertEquals(proto, ip.getProtocol()); assertEquals(dscp0, ip.getDscp()); - assertEquals(src0, ip1.getSourceInetAddress()); - assertEquals(srcAddr0, ip1.getSourceAddress()); - assertEquals(dst0, ip1.getDestinationInetAddress()); - assertEquals(dstAddr0, ip1.getDestinationAddress()); + assertEquals(src0, ip1.getSourceAddress()); + assertEquals(dst0, ip1.getDestinationAddress()); assertEquals(proto, ip1.getProtocol()); assertEquals(dscp0, ip1.getDscp()); + ip1.setSourceAddress(src1); ip1.setDestinationAddress(dst1); ip1.setDscp(dscp1); - assertEquals(src0, ip.getSourceInetAddress()); - assertEquals(srcAddr0, ip.getSourceAddress()); - assertEquals(dst0, ip.getDestinationInetAddress()); - assertEquals(dstAddr0, ip.getDestinationAddress()); + assertEquals(src0, ip.getSourceAddress()); + assertEquals(dst0, ip.getDestinationAddress()); assertEquals(proto, ip.getProtocol()); assertEquals(dscp0, ip.getDscp()); - assertEquals(src1, ip1.getSourceInetAddress()); - assertEquals(srcAddr1, ip1.getSourceAddress()); - assertEquals(dst1, ip1.getDestinationInetAddress()); - assertEquals(dstAddr1, ip1.getDestinationAddress()); + assertEquals(src1, ip1.getSourceAddress()); + assertEquals(dst1, ip1.getDestinationAddress()); assertEquals(proto, ip1.getProtocol()); assertEquals(dscp1, ip1.getDscp()); } @@ -311,41 +276,43 @@ public class Inet4PacketTest extends TestBase { public void testSetMatch() { byte[] srcAddr = {(byte)10, (byte)1, (byte)2, (byte)3}; byte[] dstAddr = {(byte)192, (byte)168, (byte)111, (byte)222}; - InetAddress src = createInetAddress(srcAddr); - InetAddress dst = createInetAddress(dstAddr); + Ip4Network src = new Ip4Network(srcAddr); + Ip4Network dst = new Ip4Network(dstAddr); byte dscp = 0; short proto = 100; - Map nwFields = - new HashMap(); - nwFields.put(MatchType.NW_SRC, new MatchField(MatchType.NW_SRC, src)); - nwFields.put(MatchType.NW_DST, new MatchField(MatchType.NW_DST, dst)); - nwFields.put(MatchType.NW_PROTO, + Map nwFields = new HashMap<>(); + nwFields.put(FlowMatchType.IP_SRC, + new MatchField(MatchType.NW_SRC, src.getInetAddress())); + nwFields.put(FlowMatchType.IP_DST, + new MatchField(MatchType.NW_DST, dst.getInetAddress())); + nwFields.put(FlowMatchType.IP_PROTO, new MatchField(MatchType.NW_PROTO, Byte.valueOf((byte)proto))); - nwFields.put(MatchType.NW_TOS, + nwFields.put(FlowMatchType.IP_DSCP, new MatchField(MatchType.NW_TOS, Byte.valueOf(dscp))); byte[] srcAddr1 = {(byte)100, (byte)200, (byte)33, (byte)44}; byte[] dstAddr1 = {(byte)172, (byte)16, (byte)123, (byte)234}; - InetAddress src1 = createInetAddress(srcAddr1); - InetAddress dst1 = createInetAddress(dstAddr1); + Ip4Network src1 = new Ip4Network(srcAddr1); + Ip4Network dst1 = new Ip4Network(dstAddr1); byte dscp1 = 63; IPv4 pkt = createIPv4Packet(src, dst, proto, dscp); Inet4Packet ipv4 = new Inet4Packet(pkt); Match match = new Match(); - Set fields = EnumSet.noneOf(MatchType.class); + Set fields = EnumSet.noneOf(FlowMatchType.class); ipv4.setMatch(match, fields); List matches = match.getMatchesList(); assertEquals(0, matches.size()); - for (Map.Entry entry: nwFields.entrySet()) { - MatchType mtype = entry.getKey(); + for (Map.Entry entry: nwFields.entrySet()) { + FlowMatchType fmtype = entry.getKey(); MatchField mfield = entry.getValue(); + MatchType mtype = mfield.getType(); match = new Match(); - fields = EnumSet.of(mtype); + fields = EnumSet.of(fmtype); ipv4.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(1, matches.size()); @@ -356,15 +323,14 @@ public class Inet4PacketTest extends TestBase { ipv4.setSourceAddress(src1); ipv4.setDestinationAddress(dst1); ipv4.setDscp(dscp1); - fields = EnumSet.noneOf(MatchType.class); + fields = EnumSet.noneOf(FlowMatchType.class); fields.addAll(nwFields.keySet()); match = new Match(); ipv4.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(nwFields.size(), matches.size()); - for (Map.Entry entry: nwFields.entrySet()) { - MatchType mtype = entry.getKey(); - MatchField mfield = entry.getValue(); + for (MatchField mfield: nwFields.values()) { + MatchType mtype = mfield.getType(); assertEquals(mfield, match.getField(mtype)); } } @@ -376,8 +342,8 @@ public class Inet4PacketTest extends TestBase { public void testGetHeaderForChecksum() { byte[] srcAddr = {(byte)100, (byte)200, (byte)33, (byte)44}; byte[] dstAddr = {(byte)172, (byte)16, (byte)123, (byte)234}; - InetAddress src = createInetAddress(srcAddr); - InetAddress dst = createInetAddress(dstAddr); + Ip4Network src = new Ip4Network(srcAddr); + Ip4Network dst = new Ip4Network(dstAddr); short protocol = 100; short len = 60; IPv4 pkt = createIPv4Packet(src, dst, protocol, (byte)0); @@ -390,8 +356,8 @@ public class Inet4PacketTest extends TestBase { for (int i = 0; i < 30; i++) { srcAddr = NumberUtils.toBytes(rand.nextInt()); dstAddr = NumberUtils.toBytes(rand.nextInt()); - src = createInetAddress(srcAddr); - dst = createInetAddress(dstAddr); + src = new Ip4Network(srcAddr); + dst = new Ip4Network(dstAddr); short proto = (short)(rand.nextInt() & 0xff); do { len = (short)(rand.nextInt() & 0xffff); @@ -413,9 +379,10 @@ public class Inet4PacketTest extends TestBase { * @param dscp DSCP field value. * @return An {@link IPv4} instance. */ - private IPv4 createIPv4Packet(InetAddress src, InetAddress dst, - short proto, byte dscp) { - IPv4 pkt = createIPv4(src, dst, proto, dscp); + private IPv4 createIPv4Packet(Ip4Network src, Ip4Network dst, short proto, + byte dscp) { + IPv4 pkt = createIPv4(src.getInetAddress(), dst.getInetAddress(), + proto, dscp); pkt.setRawPayload(EtherPacketTest.RAW_PAYLOAD); return pkt; diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacketTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacketTest.java index 1586e6d8..ae5281ae 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacketTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacketTest.java @@ -21,8 +21,10 @@ import java.util.Set; import org.junit.Test; import org.opendaylight.vtn.manager.VTNException; +import org.opendaylight.vtn.manager.util.Ip4Network; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; import org.opendaylight.vtn.manager.internal.TestBase; @@ -119,7 +121,7 @@ public class TcpPacketTest extends TestBase { ether, EtherPacketTest.NODE_CONNECTOR); assertFalse(tcp.commit(pctx)); assertEquals(null, pctx.getFilterActions()); - for (MatchType mtype: MatchType.values()) { + for (FlowMatchType mtype: FlowMatchType.values()) { assertFalse(pctx.hasMatchField(mtype)); } } @@ -191,8 +193,8 @@ public class TcpPacketTest extends TestBase { assertEquals((short)dst0, pkt.getDestinationPort()); assertEquals(original, pkt); - assertTrue(pctx.hasMatchField(MatchType.DL_TYPE)); - assertTrue(pctx.hasMatchField(MatchType.NW_PROTO)); + assertTrue(pctx.hasMatchField(FlowMatchType.DL_TYPE)); + assertTrue(pctx.hasMatchField(FlowMatchType.IP_PROTO)); List filterActions = new ArrayList(pctx.getFilterActions()); @@ -210,7 +212,7 @@ public class TcpPacketTest extends TestBase { } pctx = createPacketContext(ether, EtherPacketTest.NODE_CONNECTOR); - for (MatchType mt: MatchType.values()) { + for (FlowMatchType mt: FlowMatchType.values()) { pctx.addMatchField(mt); } for (Action act: salActions.values()) { @@ -257,12 +259,11 @@ public class TcpPacketTest extends TestBase { public void testSetMatch() { int src = 12345; int dst = 65432; - Map tpFields = - new HashMap(); - tpFields.put(MatchType.TP_SRC, + Map tpFields = new HashMap<>(); + tpFields.put(FlowMatchType.TCP_SRC, new MatchField(MatchType.TP_SRC, Short.valueOf((short)src))); - tpFields.put(MatchType.TP_DST, + tpFields.put(FlowMatchType.TCP_DST, new MatchField(MatchType.TP_DST, Short.valueOf((short)dst))); @@ -272,17 +273,18 @@ public class TcpPacketTest extends TestBase { TcpPacket tcp = new TcpPacket(pkt); Match match = new Match(); - Set fields = EnumSet.noneOf(MatchType.class); + Set fields = EnumSet.noneOf(FlowMatchType.class); tcp.setMatch(match, fields); List matches = match.getMatchesList(); assertEquals(0, matches.size()); - for (Map.Entry entry: tpFields.entrySet()) { - MatchType mtype = entry.getKey(); + for (Map.Entry entry: tpFields.entrySet()) { + FlowMatchType fmtype = entry.getKey(); MatchField mfield = entry.getValue(); + MatchType mtype = mfield.getType(); match = new Match(); - fields = EnumSet.of(mtype); + fields = EnumSet.of(fmtype); tcp.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(1, matches.size()); @@ -292,15 +294,14 @@ public class TcpPacketTest extends TestBase { // setMatch() always has to see the original. tcp.setSourcePort(src1); tcp.setDestinationPort(dst1); - fields = EnumSet.noneOf(MatchType.class); + fields = EnumSet.noneOf(FlowMatchType.class); fields.addAll(tpFields.keySet()); match = new Match(); tcp.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(tpFields.size(), matches.size()); - for (Map.Entry entry: tpFields.entrySet()) { - MatchType mtype = entry.getKey(); - MatchField mfield = entry.getValue(); + for (MatchField mfield: tpFields.values()) { + MatchType mtype = mfield.getType(); assertEquals(mfield, match.getField(mtype)); } } @@ -424,9 +425,9 @@ public class TcpPacketTest extends TestBase { pkt.setRawPayload(empty); srcIp = new byte[]{(byte)212, (byte)39, (byte)43, (byte)254}; dstIp = new byte[]{(byte)127, (byte)0, (byte)0, (byte)1}; - inet4.setSourceAddress(createInetAddress(srcIp)); + inet4.setSourceAddress(new Ip4Network(srcIp)); assertTrue(inet4.isAddressModified()); - inet4.setDestinationAddress(createInetAddress(dstIp)); + inet4.setDestinationAddress(new Ip4Network(dstIp)); assertTrue(inet4.isAddressModified()); list.clear(); diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacketTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacketTest.java index 69c64b0a..cf973b0f 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacketTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacketTest.java @@ -21,8 +21,10 @@ import java.util.Set; import org.junit.Test; import org.opendaylight.vtn.manager.VTNException; +import org.opendaylight.vtn.manager.util.Ip4Network; import org.opendaylight.vtn.manager.internal.PacketContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; import org.opendaylight.vtn.manager.internal.TestBase; @@ -84,7 +86,7 @@ public class UdpPacketTest extends TestBase { ether, EtherPacketTest.NODE_CONNECTOR); assertFalse(udp.commit(pctx)); assertEquals(null, pctx.getFilterActions()); - for (MatchType mtype: MatchType.values()) { + for (FlowMatchType mtype: FlowMatchType.values()) { assertFalse(pctx.hasMatchField(mtype)); } } @@ -156,8 +158,8 @@ public class UdpPacketTest extends TestBase { assertEquals((short)dst0, pkt.getDestinationPort()); assertEquals(original, pkt); - assertTrue(pctx.hasMatchField(MatchType.DL_TYPE)); - assertTrue(pctx.hasMatchField(MatchType.NW_PROTO)); + assertTrue(pctx.hasMatchField(FlowMatchType.DL_TYPE)); + assertTrue(pctx.hasMatchField(FlowMatchType.IP_PROTO)); List filterActions = new ArrayList(pctx.getFilterActions()); @@ -175,7 +177,7 @@ public class UdpPacketTest extends TestBase { } pctx = createPacketContext(ether, EtherPacketTest.NODE_CONNECTOR); - for (MatchType mt: MatchType.values()) { + for (FlowMatchType mt: FlowMatchType.values()) { pctx.addMatchField(mt); } for (Action act: salActions.values()) { @@ -222,12 +224,11 @@ public class UdpPacketTest extends TestBase { public void testSetMatch() { int src = 34567; int dst = 4321; - Map tpFields = - new HashMap(); - tpFields.put(MatchType.TP_SRC, + Map tpFields = new HashMap<>(); + tpFields.put(FlowMatchType.UDP_SRC, new MatchField(MatchType.TP_SRC, Short.valueOf((short)src))); - tpFields.put(MatchType.TP_DST, + tpFields.put(FlowMatchType.UDP_DST, new MatchField(MatchType.TP_DST, Short.valueOf((short)dst))); @@ -237,17 +238,18 @@ public class UdpPacketTest extends TestBase { UdpPacket udp = new UdpPacket(pkt); Match match = new Match(); - Set fields = EnumSet.noneOf(MatchType.class); + Set fields = EnumSet.noneOf(FlowMatchType.class); udp.setMatch(match, fields); List matches = match.getMatchesList(); assertEquals(0, matches.size()); - for (Map.Entry entry: tpFields.entrySet()) { - MatchType mtype = entry.getKey(); + for (Map.Entry entry: tpFields.entrySet()) { + FlowMatchType fmtype = entry.getKey(); MatchField mfield = entry.getValue(); + MatchType mtype = mfield.getType(); match = new Match(); - fields = EnumSet.of(mtype); + fields = EnumSet.of(fmtype); udp.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(1, matches.size()); @@ -257,15 +259,14 @@ public class UdpPacketTest extends TestBase { // setMatch() always has to see the original. udp.setSourcePort(src1); udp.setDestinationPort(dst1); - fields = EnumSet.noneOf(MatchType.class); + fields = EnumSet.noneOf(FlowMatchType.class); fields.addAll(tpFields.keySet()); match = new Match(); udp.setMatch(match, fields); matches = match.getMatchesList(); assertEquals(tpFields.size(), matches.size()); - for (Map.Entry entry: tpFields.entrySet()) { - MatchType mtype = entry.getKey(); - MatchField mfield = entry.getValue(); + for (MatchField mfield: tpFields.values()) { + MatchType mtype = mfield.getType(); assertEquals(mfield, match.getField(mtype)); } } @@ -378,9 +379,9 @@ public class UdpPacketTest extends TestBase { pkt.setRawPayload(empty); srcIp = new byte[]{(byte)123, (byte)89, (byte)118, (byte)91}; dstIp = new byte[]{(byte)100, (byte)200, (byte)73, (byte)183}; - inet4.setSourceAddress(createInetAddress(srcIp)); + inet4.setSourceAddress(new Ip4Network(srcIp)); assertTrue(inet4.isAddressModified()); - inet4.setDestinationAddress(createInetAddress(dstIp)); + inet4.setDestinationAddress(new Ip4Network(dstIp)); assertTrue(inet4.isAddressModified()); list.clear(); diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/MiscUtilsTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/MiscUtilsTest.java index 170b2bb2..d1ac0861 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/MiscUtilsTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/MiscUtilsTest.java @@ -45,6 +45,8 @@ import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + /** * JUnit test for {@link MiscUtils}. */ @@ -87,8 +89,8 @@ public class MiscUtilsTest extends TestBase { badRequests.put(null, "%s name cannot be null"); badRequests.put("", "%s name cannot be empty"); badRequests.put("12345678901234567890123456789012", - "%s name is too long"); - badRequests.put("_name", "%s name contains invalid character"); + "%s name is invalid"); + badRequests.put("_name", "%s name is invalid"); List badCharacters = new ArrayList(); for (char c = 0; c < 0x80; c++) { @@ -124,11 +126,8 @@ public class MiscUtilsTest extends TestBase { for (String desc: descriptions) { for (String name: good) { - try { - MiscUtils.checkName(desc, name); - } catch (Exception e) { - unexpected(e); - } + VnodeName vname = MiscUtils.checkName(desc, name); + assertEquals(name, vname.getValue()); } for (Map.Entry entry: badRequests.entrySet()) { @@ -147,7 +146,7 @@ public class MiscUtilsTest extends TestBase { } } - String msg = desc + " name contains invalid character"; + String msg = desc + " name is invalid"; for (String name: badNames) { try { MiscUtils.checkName(desc, name); diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondParams.java new file mode 100644 index 00000000..617fe942 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondParams.java @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.opendaylight.vtn.manager.flow.cond.FlowCondition; +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.SetFlowConditionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * {@code FlowCondParams} describes parameters for a flow condition. + */ +public final class FlowCondParams extends TestBase implements Cloneable { + /** + * A map that contains {@link FlowCondParams} instances for test. + */ + private static final Map COND_PARAMS; + + /** + * The name of the flow condition. + */ + private String name; + + /** + * A list of {@link FlowMatchParams} instances. + */ + private List matchParams; + + /** + * Initialize static fields. + */ + static { + Map map = new HashMap<>(); + Map matches = + FlowMatchParams.createFlowMatches(); + LinkedList paramList = new LinkedList<>(); + List expectedList = new ArrayList<>(matches.size()); + int count = 0; + for (Map.Entry entry: + matches.entrySet()) { + FlowMatchParams params = entry.getKey(); + FlowMatchParams expected = entry.getValue(); + String name = "fcond" + count; + paramList.addFirst(params); + expectedList.add(expected); + map.put(new FlowCondParams(name, paramList), + new FlowCondParams(name, expectedList)); + count++; + } + + String name = "empty"; + FlowCondParams empty = new FlowCondParams(name); + map.put(empty, empty); + + COND_PARAMS = map; + } + + /** + * Create a map that contains {@link FlowCondParams} instances for test. + * + *

+ * An instance of {@link FlowCondParams} to be used to construct + * {@link VTNFlowCondition} instance is set as a key, and an instance of + * {@link FlowCondParams} instances that contains conditions expected to + * be configured in {@link VTNFlowCondition} is set as a value. + *

+ * + * @return A map that contains {@link FlowCondParams} instances. + */ + public static Map createFlowConditions() { + Map map = + new HashMap<>(COND_PARAMS.size()); + for (Map.Entry entry: + COND_PARAMS.entrySet()) { + FlowCondParams params = entry.getKey(); + FlowCondParams expected = entry.getValue(); + map.put(params.clone(), expected.clone()); + } + + return map; + } + + /** + * Construct a new instance. + * + * @param nm The name of the flow condition. + */ + public FlowCondParams(String nm) { + name = nm; + } + + /** + * Construct a new instance. + * + * @param nm The name of the flow condition. + * @param matches A list of {@link FlowMatchParams} instances. + */ + public FlowCondParams(String nm, List matches) { + name = nm; + if (matches != null) { + matchParams = new ArrayList(matches); + } + } + + /** + * Return the name of the flow condition. + * + * @return The name of the flow condition. + */ + public String getName() { + return name; + } + + /** + * Set the name of the flow condition. + * + * @param nm The name of the flow condition. + * @return This instance. + */ + public FlowCondParams setName(String nm) { + name = nm; + return this; + } + + /** + * Add the given {@link FlowMatchParams}. + * + * @param fmp A {@link FlowMatchParams} instance. + * @return This instance. + */ + public FlowCondParams addMatch(FlowMatchParams fmp) { + if (matchParams == null) { + matchParams = new ArrayList(); + } + matchParams.add(fmp); + return this; + } + + /** + * Construct a new {@link VTNFlowCondition} instance. + * + * @return A {@link VTNFlowCondition} instance. + * @throws Exception An error occurred. + */ + public VTNFlowCondition toVTNFlowCondition() throws Exception { + return new VTNFlowCondition(name, toFlowCondition()); + } + + /** + * Return the path to the flow condition in the MD-SAL datastore. + * + * @return An {@link InstanceIdentifier} instance. + */ + public InstanceIdentifier getPath() { + VtnFlowConditionKey key = new VtnFlowConditionKey(new VnodeName(name)); + return InstanceIdentifier.builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, key).build(); + } + + /** + * Return a list of {@link VtnFlowMatch} instances. + * + * @return A list of {@link FlowMatch} instances. + */ + public List getFlowMatchList() { + if (matchParams == null) { + return null; + } + + Map map = new TreeMap<>(); + for (FlowMatchParams params: matchParams) { + FlowMatch fm = params.toFlowMatch(); + Integer index = fm.getIndex(); + assertEquals(null, map.put(index, fm)); + } + + return new ArrayList(map.values()); + } + + /** + * Return a list of {@link FlowMatch} instances. + * + * @return A list of {@link VtnFlowMatch} instances. + */ + public List getVtnFlowMatchList() { + if (matchParams == null) { + return null; + } + + List list = new ArrayList<>(matchParams.size()); + for (FlowMatchParams params: matchParams) { + list.add(params.toVtnFlowMatchBuilder().build()); + } + + return list; + } + + /** + * Construct a new {@link FlowCondition} instance. + * + * @return A {@link FlowCondition} instance. + */ + public FlowCondition toFlowCondition() { + return new FlowCondition(name, getFlowMatchList()); + } + + /** + * Construct a new {@link VtnFlowConditionBuilder} instance. + * + * @return A {@link VtnFlowConditionBuilder} instance. + */ + public VtnFlowConditionBuilder toVtnFlowConditionBuilder() { + return new VtnFlowConditionBuilder(). + setName(new VnodeName(name)). + setVtnFlowMatch(getVtnFlowMatchList()); + } + + /** + * Return a {@link XmlNode} instances which represents this instance. + * + * @param nm The name of the root node. + * @return A {@link XmlNode} instance. + */ + public XmlNode toXmlNode(String nm) { + XmlNode root = new XmlNode(nm); + if (name != null) { + root.add(new XmlNode("name", name)); + } + if (matchParams != null) { + XmlNode list = new XmlNode("vtn-flow-matches"); + for (FlowMatchParams params: matchParams) { + list.add(params.toXmlNode("vtn-flow-match")); + } + root.add(list); + } + + return root; + } + + /** + * Ensure that the given {@link VTNFlowCondition} instance contains the + * same conditions as this instance. + * + * @param vfcond A {@link VTNFlowCondition} instance. + * @throws Exception An error occurred. + */ + public void verify(VTNFlowCondition vfcond) throws Exception { + FlowCondition fc = vfcond.toFlowCondition(); + assertEquals(toFlowCondition(), fc); + assertEquals(getPath(), vfcond.getPath()); + + int prev = 0; + for (FlowMatch fm: fc.getMatches()) { + int idx = fm.getIndex().intValue(); + assertTrue(idx > prev); + prev = idx; + } + + VtnFlowCondition vfc = toVtnFlowConditionBuilder().build(); + assertEquals(vfcond, VTNFlowCondition.create(vfc)); + + SetFlowConditionInput input = + vfcond.toSetFlowConditionInputBuilder().build(); + assertEquals(vfcond, new VTNFlowCondition(input)); + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public FlowCondParams clone() { + try { + FlowCondParams params = (FlowCondParams)super.clone(); + if (matchParams != null) { + List list = + new ArrayList<>(matchParams.size()); + for (FlowMatchParams fmp: matchParams) { + list.add(fmp.clone()); + } + params.matchParams = list; + } + + return params; + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReaderTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReaderTest.java new file mode 100644 index 00000000..4218317c --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondReaderTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import org.mockito.Mockito; + +import org.opendaylight.vtn.manager.internal.TestBase; + +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * JUnit test for {@link FlowCondReader}. + */ +public class FlowCondReaderTest extends TestBase { + /** + * Test case for {@link FlowCondReader#get(String)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testGet() throws Exception { + // Set up mock-up of MD-SAL read transaction. + ReadTransaction rtx = Mockito.mock(ReadTransaction.class); + Map expected = new HashMap<>(); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + + // Valid flow conditions. + Map cases = + FlowCondParams.createFlowConditions(); + for (FlowCondParams params: cases.values()) { + VTNFlowCondition vfcond = params.toVTNFlowCondition(); + VtnFlowCondition vfc = params.toVtnFlowConditionBuilder().build(); + InstanceIdentifier path = vfcond.getPath(); + String name = params.getName(); + assertEquals(false, expected.containsKey(name)); + assertEquals(null, expected.put(name, vfcond)); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfc)); + } + + // Flow conditions that are not present. + VtnFlowCondition vfcNull = null; + for (int i = 0; i < 10; i++) { + String name = "notfound" + i; + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name); + assertEquals(false, expected.containsKey(name)); + assertEquals(null, expected.put(name, null)); + Mockito.when(rtx.read(oper, path)). + thenReturn(getReadResult(vfcNull)); + } + + // Broken flow conditions. + int badIndex = 5; + List vmatches = new ArrayList<>(); + for (int i = 1; i <= badIndex + 5; i++) { + vmatches.add(new VtnFlowMatchBuilder().setIndex(i).build()); + } + vmatches.add(new VtnFlowMatchBuilder().setIndex(badIndex).build()); + + for (int i = 0; i < 5; i++) { + String name = "broken" + i; + VnodeName vname = new VnodeName(name); + VtnFlowCondition vfc = new VtnFlowConditionBuilder(). + setName(vname). + setVtnFlowMatch(new ArrayList(vmatches)).build(); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(vname); + assertEquals(false, expected.containsKey(name)); + assertEquals(null, expected.put(name, null)); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfc)); + } + + // Run tests. + FlowCondReader reader = new FlowCondReader(rtx); + assertSame(rtx, reader.getReadTransaction()); + + for (int i = 0; i < 10; i++) { + for (Map.Entry entry: + expected.entrySet()) { + String name = entry.getKey(); + VTNFlowCondition vfcond = entry.getValue(); + assertEquals(vfcond, reader.get(name)); + } + } + + for (String name: expected.keySet()) { + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name); + Mockito.verify(rtx).read(oper, path); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtilsTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtilsTest.java new file mode 100644 index 00000000..b9977124 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowCondUtilsTest.java @@ -0,0 +1,811 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; + +import org.mockito.Mockito; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.util.SalPort; + +import org.opendaylight.vtn.manager.internal.TestBase; + +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowConditionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * JUnit test for {@link FlowCondUtils}. + */ +public class FlowCondUtilsTest extends TestBase { + /** + * Test case for thw following methods. + * + *
    + *
  • {@link FlowCondUtils#getNotFoundException(String)}
  • + *
  • {@link FlowCondUtils#getNotFoundException(String, Throwable)}
  • + *
  • {@link FlowCondUtils#getMatchIndexMissingException()}
  • + *
+ */ + @Test + public void testException() { + String[] names = { + "flow_cond", + "fcond", + "fc", + }; + + Throwable cause = new IllegalStateException(); + for (String name: names) { + String msg = name + ": Flow condition does not exist."; + RpcException e = FlowCondUtils.getNotFoundException(name); + assertEquals(null, e.getCause()); + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(msg, st.getDescription()); + + e = FlowCondUtils.getNotFoundException(name, cause); + assertSame(cause, e.getCause()); + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + String msg = "Match index cannot be null"; + RpcException e = FlowCondUtils.getMatchIndexMissingException(); + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + /** + * Test case for thw following methods. + * + *
    + *
  • {@link FlowCondUtils#checkName(String)}
  • + *
  • {@link FlowCondUtils#checkName(VnodeName)}
  • + *
  • {@link FlowCondUtils#getVnodeName(String)}
  • + *
  • {@link FlowCondUtils#getIdentifier(String)}
  • + *
  • {@link FlowCondUtils#getIdentifier(VnodeName)}
  • + *
  • {@link FlowCondUtils#getIdentifier(String, Integer)}
  • + *
  • {@link FlowCondUtils#getIdentifier(VnodeName, Integer)}
  • + *
  • {@link FlowCondUtils#getName(InstanceIdentifier)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testName() throws Exception { + // Valid name. + String[] names = { + "0", + "01", + "012", + "0123", + "012345678901234567890123456789", + "0123456789012345678901234567890", + "a", + "ab", + "abc", + "abcABC", + "abcABC_", + "abcABC_0123", + "abcABC_0123_XXXXXXXXXXXXXXXXXXX", + }; + Integer[] indices = { + 1, 2, 3, 444, 1000, 2000, 3333, 44444, 55555, 65534, 65535, + }; + + for (String name: names) { + VnodeName vname = new VnodeName(name); + assertEquals(vname, FlowCondUtils.checkName(name)); + assertEquals(name, FlowCondUtils.checkName(vname)); + assertEquals(vname, FlowCondUtils.getVnodeName(name)); + + VtnFlowConditionKey key = new VtnFlowConditionKey(vname); + InstanceIdentifier expected = InstanceIdentifier. + builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, key).build(); + assertEquals(expected, FlowCondUtils.getIdentifier(name)); + assertEquals(expected, FlowCondUtils.getIdentifier(vname)); + assertEquals(name, FlowCondUtils.getName(expected)); + + for (Integer idx: indices) { + VtnFlowMatchKey mkey = new VtnFlowMatchKey(idx); + InstanceIdentifier ex = InstanceIdentifier. + builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, key). + child(VtnFlowMatch.class, mkey).build(); + assertEquals(ex, FlowCondUtils.getIdentifier(name, idx)); + assertEquals(ex, FlowCondUtils.getIdentifier(vname, idx)); + assertEquals(name, FlowCondUtils.getName(ex)); + } + + String msg = "Match index cannot be null"; + try { + FlowCondUtils.getIdentifier(name, null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + try { + FlowCondUtils.getIdentifier(vname, null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + } + + // Null name. + String msg = "Flow condition name cannot be null"; + RpcErrorTag etag = RpcErrorTag.MISSING_ELEMENT; + StatusCode code = StatusCode.BADREQUEST; + try { + FlowCondUtils.checkName((String)null); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + try { + FlowCondUtils.checkName((VnodeName)null); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + try { + FlowCondUtils.getVnodeName(null); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + try { + FlowCondUtils.getIdentifier((String)null); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + try { + FlowCondUtils.getIdentifier((String)null, Integer.valueOf(1)); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + // Empty name. + msg = "Flow condition name cannot be empty"; + etag = RpcErrorTag.BAD_ELEMENT; + try { + FlowCondUtils.checkName(""); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + try { + FlowCondUtils.getVnodeName(""); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(": Flow condition does not exist.", + st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof RpcException); + RpcException re = (RpcException)cause; + assertEquals(etag, re.getErrorTag()); + st = re.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, re.getCause()); + } + + try { + FlowCondUtils.getIdentifier(""); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(": Flow condition does not exist.", + st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof RpcException); + RpcException re = (RpcException)cause; + assertEquals(etag, re.getErrorTag()); + st = re.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, re.getCause()); + } + + try { + FlowCondUtils.getIdentifier("", Integer.valueOf(1)); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(": Flow condition does not exist.", + st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof RpcException); + RpcException re = (RpcException)cause; + assertEquals(etag, re.getErrorTag()); + st = re.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, re.getCause()); + } + + // Invalid name. + msg = "Flow condition name is invalid"; + String[] invalidNames = { + "01234567890123456789012345678901", + "abcABC_0123_XXXXXXXXXXXXXXXXXXXX", + "_flow_cond", + "flow-cond", + "flow%cond", + "_", + " ", + "\u3042", + }; + for (String name: invalidNames) { + try { + FlowCondUtils.checkName(name); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + Throwable cause = e.getCause(); + assertTrue(cause instanceof IllegalArgumentException); + } + + try { + FlowCondUtils.getVnodeName(name); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(name + ": Flow condition does not exist.", + st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof RpcException); + RpcException re = (RpcException)cause; + assertEquals(etag, re.getErrorTag()); + st = re.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + cause = re.getCause(); + assertTrue(cause instanceof IllegalArgumentException); + } + + try { + FlowCondUtils.getIdentifier(name); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(name + ": Flow condition does not exist.", + st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof RpcException); + RpcException re = (RpcException)cause; + assertEquals(etag, re.getErrorTag()); + st = re.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + cause = re.getCause(); + assertTrue(cause instanceof IllegalArgumentException); + } + + try { + FlowCondUtils.getIdentifier(name, Integer.valueOf(1)); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(name + ": Flow condition does not exist.", + st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof RpcException); + RpcException re = (RpcException)cause; + assertEquals(etag, re.getErrorTag()); + st = re.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + cause = re.getCause(); + assertTrue(cause instanceof IllegalArgumentException); + } + } + + // getName() should return null if the given path does not contain a + // flow condition key. + SalPort sport = new SalPort(1L, 2L); + List> list = new ArrayList<>(); + list.add(sport.getNodeIdentifier()); + list.add(sport.getNodeConnectorIdentifier()); + list.add(sport.getVtnNodeIdentifier()); + list.add(sport.getVtnPortIdentifier()); + for (InstanceIdentifier path: list) { + assertEquals(null, FlowCondUtils.getName(path)); + } + + VtnFlowConditionKey nullKey = new VtnFlowConditionKey((VnodeName)null); + InstanceIdentifier path = InstanceIdentifier. + builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, nullKey).build(); + assertEquals(null, FlowCondUtils.getName(path)); + + InstanceIdentifier mpath = InstanceIdentifier. + builder(VtnFlowConditions.class). + child(VtnFlowCondition.class, nullKey). + child(VtnFlowMatch.class, new VtnFlowMatchKey(1)).build(); + assertEquals(null, FlowCondUtils.getName(mpath)); + } + + /** + * Test case for thw following methods. + * + *
    + *
  • {@link FlowCondUtils#verifyMatchIndex(Set, Integer)}
  • + *
  • {@link FlowCondUtils#verifyMatchIndex(Integer)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testMatchIndex() throws Exception { + Integer[] indices = { + 1, 2, 3, 444, 1000, 2000, 3333, 44444, 55555, 65534, 65535, + }; + + Set idxSet = new HashSet<>(); + for (Integer index: indices) { + FlowCondUtils.verifyMatchIndex(index); + FlowCondUtils.verifyMatchIndex(idxSet, index); + } + + // Index is null. + String msg = "Match index cannot be null"; + RpcErrorTag etag = RpcErrorTag.MISSING_ELEMENT; + StatusCode code = StatusCode.BADREQUEST; + try { + FlowCondUtils.verifyMatchIndex(null); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + + // Invalid index. + Integer[] badIndices = { + Integer.MIN_VALUE, -10000000, -3000, -200, -3, -2, -1, 0, + 65536, 65537, 70000, 1000000, Integer.MAX_VALUE, + }; + etag = RpcErrorTag.BAD_ELEMENT; + for (Integer index: badIndices) { + msg = "Invalid match index: " + index; + try { + FlowCondUtils.verifyMatchIndex(index); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + + Throwable cause = e.getCause(); + assertTrue(cause instanceof IllegalArgumentException); + } + } + + // Duplicate index. + for (Integer index: indices) { + msg = "Duplicate match index: " + index; + try { + FlowCondUtils.verifyMatchIndex(idxSet, index); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(code, st.getCode()); + assertEquals(msg, st.getDescription()); + assertEquals(null, e.getCause()); + } + } + } + + /** + * Test case for + * {@link FlowCondUtils#checkPresent(ReadTransaction, VnodeName)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testCheckPresent() throws Exception { + // Set up mock-up of MD-SAL read transaction. + ReadTransaction rtx = Mockito.mock(ReadTransaction.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + List names = new ArrayList<>(); + List> paths = new ArrayList<>(); + Set present = new HashSet<>(); + + for (int i = 0; i < 10; i++) { + String name = "present" + i; + VnodeName vname = new VnodeName(name); + names.add(vname); + assertEquals(true, present.add(vname)); + VtnFlowCondition vfc = new VtnFlowConditionBuilder(). + setName(vname).build(); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(vname); + paths.add(path); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfc)); + } + + VtnFlowCondition vfcNull = null; + for (int i = 0; i < 10; i++) { + String name = "notfound" + i; + VnodeName vname = new VnodeName(name); + names.add(vname); + assertEquals(false, present.contains(vname)); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(vname); + paths.add(path); + Mockito.when(rtx.read(oper, path)). + thenReturn(getReadResult(vfcNull)); + } + + for (VnodeName vname: names) { + try { + FlowCondUtils.checkPresent(rtx, vname); + assertEquals(true, present.contains(vname)); + } catch (RpcException e) { + assertEquals(false, present.contains(vname)); + assertEquals(null, e.getCause()); + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + String msg = vname.getValue() + + ": Flow condition does not exist."; + assertEquals(msg, st.getDescription()); + } + } + + for (InstanceIdentifier path: paths) { + Mockito.verify(rtx).read(oper, path); + } + } + + /** + * Test case for {@link FlowCondUtils#readFlowConditions(ReadTransaction)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testReadConditions() throws Exception { + // Set up mock-up of MD-SAL read transaction. + ReadTransaction rtx = Mockito.mock(ReadTransaction.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + InstanceIdentifier path = + InstanceIdentifier.create(VtnFlowConditions.class); + + // Root container is not present. + VtnFlowConditions root = null; + List expected = new ArrayList<>(); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(root)); + assertEquals(expected, FlowCondUtils.readFlowConditions(rtx)); + Mockito.verify(rtx).read(oper, path); + Mockito.reset(rtx); + + // Flow condition list is null. + root = new VtnFlowConditionsBuilder().build(); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(root)); + assertEquals(expected, FlowCondUtils.readFlowConditions(rtx)); + Mockito.verify(rtx).read(oper, path); + Mockito.reset(rtx); + + // Flow condition list is empty. + List vlist = new ArrayList<>(); + root = new VtnFlowConditionsBuilder(). + setVtnFlowCondition(vlist).build(); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(root)); + assertEquals(expected, FlowCondUtils.readFlowConditions(rtx)); + Mockito.verify(rtx).read(oper, path); + Mockito.reset(rtx); + + // Flow conditions are present. + Map cases = + FlowCondParams.createFlowConditions(); + for (FlowCondParams params: cases.values()) { + vlist.add(params.toVtnFlowConditionBuilder().build()); + expected.add(params.toVTNFlowCondition()); + } + root = new VtnFlowConditionsBuilder(). + setVtnFlowCondition(vlist).build(); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(root)); + assertEquals(expected, FlowCondUtils.readFlowConditions(rtx)); + Mockito.verify(rtx).read(oper, path); + Mockito.reset(rtx); + } + + /** + * Test case for + * {@link FlowCondUtils#readFlowCondition(ReadTransaction, String)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testReadCondition() throws Exception { + // Set up mock-up of MD-SAL read transaction. + ReadTransaction rtx = Mockito.mock(ReadTransaction.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + + // Null name. + try { + FlowCondUtils.readFlowCondition(rtx, (String)null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Flow condition name cannot be null", + st.getDescription()); + } + + // Invalid name should be treated as if the specified flow condition + // is not present. + String[] invalidNames = { + "", + "01234567890123456789012345678901", + "abcABC_0123_XXXXXXXXXXXXXXXXXXXX", + "_flow_cond", + "flow-cond", + "flow%cond", + "_", + " ", + "\u3042", + }; + for (String name: invalidNames) { + try { + FlowCondUtils.readFlowCondition(rtx, name); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + String msg = name + ": Flow condition does not exist."; + assertEquals(msg, st.getDescription()); + } + } + Mockito.verify(rtx, Mockito.never()). + read(Mockito.any(LogicalDatastoreType.class), + Mockito.any(InstanceIdentifier.class)); + + // Flow condition is not present. + VtnFlowCondition vfc = null; + Map cases = + FlowCondParams.createFlowConditions(); + for (FlowCondParams params: cases.values()) { + String name = params.getName(); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfc)); + try { + FlowCondUtils.readFlowCondition(rtx, name); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + String msg = name + ": Flow condition does not exist."; + assertEquals(msg, st.getDescription()); + } + Mockito.verify(rtx).read(oper, path); + } + + // Flow condition is present. + for (FlowCondParams params: cases.values()) { + String name = params.getName(); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name); + vfc = params.toVtnFlowConditionBuilder().build(); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfc)); + assertEquals(params.toVTNFlowCondition(), + FlowCondUtils.readFlowCondition(rtx, name)); + Mockito.verify(rtx, Mockito.times(2)).read(oper, path); + } + } + + /** + * Test case for + * {@link FlowCondUtils#readFlowMatch(ReadTransaction, String, int)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testReadMatch() throws Exception { + // Set up mock-up of MD-SAL read transaction. + ReadTransaction rtx = Mockito.mock(ReadTransaction.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + + // Null name. + try { + FlowCondUtils.readFlowMatch(rtx, (String)null, 1); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Flow condition name cannot be null", + st.getDescription()); + } + + // Invalid name should be treated as if the specified flow condition + // is not present. + String[] invalidNames = { + "", + "01234567890123456789012345678901", + "abcABC_0123_XXXXXXXXXXXXXXXXXXXX", + "_flow_cond", + "flow-cond", + "flow%cond", + "_", + " ", + "\u3042", + }; + for (String name: invalidNames) { + try { + FlowCondUtils.readFlowMatch(rtx, name, 1); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + String msg = name + ": Flow condition does not exist."; + assertEquals(msg, st.getDescription()); + } + } + Mockito.verify(rtx, Mockito.never()). + read(Mockito.any(LogicalDatastoreType.class), + Mockito.any(InstanceIdentifier.class)); + + VtnFlowCondition vfc = new VtnFlowConditionBuilder().build(); + VtnFlowCondition vfcNull = null; + VtnFlowMatch vfm = null; + Map cases = + FlowMatchParams.createFlowMatches(); + String name = "fcond"; + InstanceIdentifier fcPath = + FlowCondUtils.getIdentifier(name); + String msg = name + ": Flow condition does not exist."; + int fcCount = 0; + for (FlowMatchParams params: cases.values()) { + // Flow match is not present. + Integer index = params.getIndex(); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name, index); + Mockito.when(rtx.read(oper, fcPath)).thenReturn(getReadResult(vfc)); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfm)); + assertEquals(null, FlowCondUtils.readFlowMatch(rtx, name, index)); + fcCount++; + Mockito.verify(rtx, Mockito.times(fcCount)).read(oper, fcPath); + Mockito.verify(rtx).read(oper, path); + + // Flow condition is not present. + Mockito.when(rtx.read(oper, fcPath)). + thenReturn(getReadResult(vfcNull)); + try { + FlowCondUtils.readFlowMatch(rtx, name, index); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.DATA_MISSING, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.NOTFOUND, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + fcCount++; + Mockito.verify(rtx, Mockito.times(fcCount)).read(oper, fcPath); + Mockito.verify(rtx, Mockito.times(2)).read(oper, path); + } + + // Flow match is present. + for (FlowMatchParams params: cases.values()) { + Integer index = params.getIndex(); + InstanceIdentifier path = + FlowCondUtils.getIdentifier(name, index); + vfm = params.toVtnFlowMatchBuilder().build(); + Mockito.when(rtx.read(oper, path)).thenReturn(getReadResult(vfm)); + assertEquals(params.toVTNFlowMatch(), + FlowCondUtils.readFlowMatch(rtx, name, index)); + Mockito.verify(rtx, Mockito.times(fcCount)).read(oper, fcPath); + Mockito.verify(rtx, Mockito.times(3)).read(oper, path); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowMatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowMatchParams.java new file mode 100644 index 00000000..3b1711ff --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/FlowMatchParams.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; + +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.util.flow.match.MatchParams; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.set.flow.condition.match.input.FlowMatchList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; + +/** + * {@code FlowMatchParams} describes parameters for a flow match in a + * flow condition. + */ +public final class FlowMatchParams extends MatchParams { + /** + * A map that contains {@link FlowMatchParams} instances for test. + */ + private static final Map MATCH_PARAMS; + + /** + * The index to be assigned for a flow match. + */ + private Integer index; + + /** + * Initialize static fields. + */ + static { + Map map = new HashMap<>(); + + int idx = 1; + for (Map.Entry entry: + MatchParams.createMatches().entrySet()) { + MatchParams params = entry.getKey(); + MatchParams expected = entry.getValue(); + map.put(new FlowMatchParams(idx, params), + new FlowMatchParams(idx, expected)); + idx++; + } + + MATCH_PARAMS = Collections.unmodifiableMap(map); + } + + /** + * Create a map that contains {@link FlowMatchParams} instances for test. + * + *

+ * An instance of {@link FlowMatchParams} to be used to construct + * {@link VTNFlowMatch} instance is set as a key, and an instance of + * {@link FlowMatchParams} instances that contains conditions expected to + * be configured in {@link VTNFlowMatch} is set as a value. + *

+ * + * @return A map that contains {@link FlowMatchParams} instances. + */ + public static Map createFlowMatches() { + Map map = + new HashMap<>(MATCH_PARAMS.size()); + for (Map.Entry entry: + MATCH_PARAMS.entrySet()) { + FlowMatchParams params = entry.getKey(); + FlowMatchParams expected = entry.getValue(); + map.put(params.clone(), expected.clone()); + } + + return map; + } + + /** + * Construct an empty instance. + */ + public FlowMatchParams() { + } + + /** + * Construct a new instance. + * + * @param idx The index to be assigned. + */ + public FlowMatchParams(int idx) { + index = Integer.valueOf(idx); + } + + /** + * Construct a new instance. + * + * @param idx The index to be assigned. + * @param params A {@link MatchParams} instance. + */ + public FlowMatchParams(int idx, MatchParams params) { + super(params); + index = Integer.valueOf(idx); + } + + /** + * Return the index for this flow match. + * + * @return The index for this flow match. + */ + public Integer getIndex() { + return index; + } + + /** + * Set the index for this flow match. + * + * @param idx The index for this flow match. + * @return This instance. + */ + public FlowMatchParams setIndex(Integer idx) { + index = idx; + return this; + } + + /** + * Construct a new {@link VTNFlowMatch} instance. + * + * @return A {@link VTNFlowMatch} instance. + * @throws Exception An error occurred. + */ + public VTNFlowMatch toVTNFlowMatch() throws Exception { + return new VTNFlowMatch(toFlowMatch()); + } + + /** + * Ensure that the given {@link VTNFlowMatch} instance contains the same + * conditions as this instance. + * + * @param vfmatch A {@link VTNFlowMatch} instance. + * @throws Exception An error occurred. + */ + public void verify(VTNFlowMatch vfmatch) throws Exception { + super.verify(vfmatch); + assertEquals(index, vfmatch.getIdentifier()); + + VtnFlowMatch vfm = toVtnFlowMatchBuilder().build(); + assertEquals(vfmatch, new VTNFlowMatch(vfm)); + + FlowMatchList fml = vfmatch.toFlowMatchListBuilder().build(); + assertEquals(vfmatch, new VTNFlowMatch(fml)); + } + + // MatchParams + + /** + * {@inheritDoc} + */ + @Override + public FlowMatchParams reset() { + super.reset(); + index = null; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public FlowMatch toFlowMatch() { + return (index == null) + ? super.toFlowMatch() + : new FlowMatch(index.intValue(), getEthernetMatch(), + getInetMatch(), getL4Match()); + } + + /** + * {@inheritDoc} + */ + @Override + public VtnFlowMatchBuilder toVtnFlowMatchBuilder() { + return super.toVtnFlowMatchBuilder().setIndex(index); + } + + /** + * {@inheritDoc} + */ + @Override + public XmlNode toXmlNode(String name) { + XmlNode root = super.toXmlNode(name); + if (index != null) { + root.add(new XmlNode("index", index)); + } + + return root; + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public FlowMatchParams clone() { + return (FlowMatchParams)super.clone(); + } +} + diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowConditionTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowConditionTest.java new file mode 100644 index 00000000..1a249453 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowConditionTest.java @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.FlowCondition; +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.IpNetwork; +import org.opendaylight.vtn.manager.util.VTNIdentifiableComparator; + +import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType; +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.DataGenerator; +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlDataType; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.util.flow.match.EtherMatchParams; +import org.opendaylight.vtn.manager.internal.util.flow.match.IcmpMatchParams; +import org.opendaylight.vtn.manager.internal.util.flow.match.Inet4MatchParams; +import org.opendaylight.vtn.manager.internal.util.flow.match.TcpMatchParams; +import org.opendaylight.vtn.manager.internal.util.flow.match.TestMatchContext; +import org.opendaylight.vtn.manager.internal.util.flow.match.UdpMatchParams; + +import org.opendaylight.controller.sal.utils.EtherTypes; +import org.opendaylight.controller.sal.utils.IPProtocols; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowCondition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.conditions.VtnFlowConditionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName; + +/** + * JUnit test for {@link VTNFlowCondition}. + */ +public class VTNFlowConditionTest extends TestBase { + /** + * Root XML element name associated with {@link VTNFlowCondition} class. + */ + private static final String XML_ROOT = "vtn-flow-condition"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNFlowCondition} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + String[] p = XmlDataType.addPath( + "vtn-flow-matches", XmlDataType.addPath(name, parent)); + List dlist = new ArrayList<>(); + dlist.addAll(VTNFlowMatchTest.getXmlDataTypes("vtn-flow-match", p)); + return dlist; + } + + /** + * Test case for constructors and getter methods. + * + * @throws Exception An error occurred. + */ + @Test + public void testGetter() throws Exception { + assertEquals(null, VTNFlowCondition.create(null)); + + List list = new ArrayList<>(); + Map cases = + FlowCondParams.createFlowConditions(); + for (Map.Entry entry: + cases.entrySet()) { + FlowCondParams params = entry.getKey(); + FlowCondParams expected = entry.getValue(); + VTNFlowCondition vfcond = params.toVTNFlowCondition(); + expected.verify(vfcond); + list.add(vfcond); + } + + // Ensure that VTNFlowCondition can be sorted by + // VTNIdentifiableComparator. + VTNIdentifiableComparator comparator = + new VTNIdentifiableComparator<>(String.class); + Collections.sort(list, comparator); + String prev = null; + for (VTNFlowCondition vfcond: list) { + String name = vfcond.getIdentifier(); + if (prev != null) { + assertTrue(prev.compareTo(name) < 0); + } + prev = name; + } + + // Test cases for valid names. + String[] names = { + "0123456789012345678901234567890", + "aaaaaaaaaaaaaaaAAAAAAAAAAAAAAAA", + "aaaa_BBBB_cccc_DDDD_0000_1111_2", + "0", + "1", + "a", + "B", + }; + for (String name: names) { + FlowCondition fc = new FlowCondition(null, null); + VTNFlowCondition vfcond = new VTNFlowCondition(name, fc); + assertEquals(name, vfcond.getIdentifier()); + } + + // Null name. + String msg = "Flow condition name cannot be null"; + try { + new VTNFlowCondition(null, null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + VtnFlowCondition vfc = new VtnFlowConditionBuilder().build(); + try { + new VTNFlowCondition(vfc); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + assertEquals(null, VTNFlowCondition.create(vfc)); + + // Empty name + msg = "Flow condition name cannot be empty"; + try { + new VTNFlowCondition("", null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + // Invalid name + msg = "Flow condition name is invalid"; + String[] invalidNames = { + // Too long name. + "01234567890123456789012345678901", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + + // Starts with an invalid character. + "_abc", + ";abc", + "/abc", + "%abc", + + // Invalid character. + "abcde-0123", + "abcde.0123", + "abcde:0123", + }; + + for (String name: invalidNames) { + try { + new VTNFlowCondition(name, null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + + // Duplicate index. + int badIndex = 20; + msg = "Duplicate match index: " + badIndex; + List matches = new ArrayList<>(); + List vmatches = new ArrayList<>(); + for (int i = 1; i <= badIndex + 20; i++) { + matches.add(new FlowMatch(i, null, null, null)); + vmatches.add(new VtnFlowMatchBuilder().setIndex(i).build()); + } + matches.add(new FlowMatch(badIndex, null, null, null)); + vmatches.add(new VtnFlowMatchBuilder().setIndex(badIndex).build()); + + String name = "fcond"; + FlowCondition fc = new FlowCondition(null, matches); + try { + new VTNFlowCondition(name, fc); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + vfc = new VtnFlowConditionBuilder(). + setName(new VnodeName(name)).setVtnFlowMatch(vmatches).build(); + try { + new VTNFlowCondition(vfc); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNFlowCondition#equals(Object)}
  • + *
  • {@link VTNFlowCondition#hashCode()}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + + final int numEmpties = 10; + List matches = Collections.emptyList(); + List vmatches = Collections.emptyList(); + for (int i = 0; i < numEmpties; i++) { + String name = "empty" + i; + FlowCondition fc = new FlowCondition(null, matches); + VTNFlowCondition vfcond1 = new VTNFlowCondition(name, null); + VTNFlowCondition vfcond2 = new VTNFlowCondition(name, fc); + testEquals(set, vfcond1, vfcond2); + + VtnFlowConditionBuilder builder = new VtnFlowConditionBuilder(). + setName(new VnodeName(name)); + VTNFlowCondition vfcond = new VTNFlowCondition(builder.build()); + assertEquals(false, set.add(vfcond)); + + builder.setVtnFlowMatch(vmatches); + vfcond = new VTNFlowCondition(builder.build()); + assertEquals(false, set.add(vfcond)); + } + + int count = 0; + Map cases = + FlowCondParams.createFlowConditions(); + for (Map.Entry entry: + cases.entrySet()) { + FlowCondParams params = entry.getKey(); + FlowCondParams expected = entry.getValue(); + VTNFlowCondition vfcond1 = params.toVTNFlowCondition(); + VTNFlowCondition vfcond2 = expected.toVTNFlowCondition(); + testEquals(set, vfcond1, vfcond2); + + String name = "another_cond_" + count; + VtnFlowCondition vfc = params.toVtnFlowConditionBuilder(). + setName(new VnodeName(name)).build(); + vfcond1 = new VTNFlowCondition(name, params.toFlowCondition()); + vfcond2 = new VTNFlowCondition(vfc); + testEquals(set, vfcond1, vfcond2); + } + + int expected = cases.size() * 2 + numEmpties; + assertEquals(expected, set.size()); + } + + /** + * Test case for {@link VTNFlowCondition#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + Class type = VTNFlowCondition.class; + Unmarshaller um = createUnmarshaller(type); + Map cases = + FlowCondParams.createFlowConditions(); + for (Map.Entry entry: + cases.entrySet()) { + FlowCondParams params = entry.getKey(); + FlowCondParams expected = entry.getValue(); + String xml = params.toXmlNode(XML_ROOT).toString(); + VTNFlowCondition vfcond = unmarshal(um, xml, type); + vfcond.verify(); + expected.verify(vfcond); + + xml = expected.toXmlNode(XML_ROOT).toString(); + VTNFlowCondition vfcond1 = unmarshal(um, xml, type); + vfcond1.verify(); + assertEquals(vfcond, vfcond1); + } + + // Test cases for valid names. + String[] names = { + "0123456789012345678901234567890", + "aaaaaaaaaaaaaaaAAAAAAAAAAAAAAAA", + "aaaa_BBBB_cccc_DDDD_0000_1111_2", + "0", + "1", + "a", + "B", + }; + for (String name: names) { + FlowCondParams params = new FlowCondParams(name); + String xml = params.toXmlNode(XML_ROOT).toString(); + VTNFlowCondition vfcond = unmarshal(um, xml, type); + vfcond.verify(); + params.verify(vfcond); + } + + // Invalid match index. + Integer[] badIndices = { + null, Integer.MIN_VALUE, -10000000, -3000, -200, -3, -2, -1, 0, + 65536, 65537, 70000, 1000000, Integer.MAX_VALUE, + }; + + String msg; + RpcErrorTag etag; + for (Integer idx: badIndices) { + XmlNode xn = new XmlNode(XML_ROOT). + add(new XmlNode("name", "fcond")); + XmlNode xmatches = new XmlNode("vtn-flow-matches"); + if (idx == null) { + msg = "Match index cannot be null"; + etag = RpcErrorTag.MISSING_ELEMENT; + xmatches.add(new XmlNode("vtn-flow-match")); + } else { + msg = "Invalid match index: " + idx; + etag = RpcErrorTag.BAD_ELEMENT; + FlowMatchParams fmp = new FlowMatchParams().setIndex(idx); + xmatches.add(fmp.toXmlNode("vtn-flow-match")); + } + xn.add(xmatches); + + VTNFlowCondition vfcond = unmarshal(um, xn.toString(), type); + try { + vfcond.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + + // Null name. + msg = "Flow condition name cannot be null"; + etag = RpcErrorTag.MISSING_ELEMENT; + String xml = new XmlNode(XML_ROOT).toString(); + VTNFlowCondition vfcond = unmarshal(um, xml, type); + try { + vfcond.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + // Empty name + msg = "Flow condition name cannot be empty"; + etag = RpcErrorTag.BAD_ELEMENT; + xml = new XmlNode(XML_ROOT).add(new XmlNode("name")).toString(); + vfcond = unmarshal(um, xml, type); + try { + vfcond.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + + // Invalid name + msg = "Flow condition name is invalid"; + String[] invalidNames = { + // Too long name. + "01234567890123456789012345678901", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + + // Starts with an invalid character. + "_abc", + ";abc", + "/abc", + "%abc", + + // Invalid character. + "abcde-0123", + "abcde.0123", + "abcde:0123", + }; + for (String name: invalidNames) { + xml = new XmlNode(XML_ROOT). + add(new XmlNode("name", name)).toString(); + vfcond = unmarshal(um, xml, type); + try { + vfcond.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + + // Duplicate index. + int badIndex = 31; + XmlNode xn = new XmlNode(XML_ROOT).add(new XmlNode("name", "fcond")); + XmlNode xmatches = new XmlNode("vtn-flow-matches"). + add(new FlowMatchParams(badIndex).toXmlNode("vtn-flow-match")); + msg = "Duplicate match index: " + badIndex; + for (int i = 1; i <= badIndex + 20; i++) { + FlowMatchParams fmp = new FlowMatchParams().setIndex(i); + xmatches.add(fmp.toXmlNode("vtn-flow-match")); + } + xml = xn.add(xmatches).toString(); + vfcond = unmarshal(um, xml, type); + try { + vfcond.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + + /** + * Test case for {@link VTNFlowCondition#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + // Create an empty flow condition. + VTNFlowCondition empty = new VTNFlowCondition("empty", null); + + // 10000: IP DSCP == 35 + List vmatches = new ArrayList<>(); + Short dscp = 35; + Inet4MatchParams i4params = new Inet4MatchParams().setDscp(dscp); + FlowMatchParams params = new FlowMatchParams(10000); + params.setInet4Params(i4params); + vmatches.add(params.toVtnFlowMatchBuilder().build()); + + // 10: ether type == 0x1234 + Integer ethType = 0x1234; + EtherMatchParams eparams = new EtherMatchParams(). + setEtherType(ethType); + params.reset().setIndex(10).setEtherParams(eparams); + vmatches.add(params.toVtnFlowMatchBuilder().build()); + + // 1500: TCP dst port 1000-2000 + int dstFrom = 1000; + int dstTo = 2000; + TcpMatchParams tparams = new TcpMatchParams(). + setDestinationPortFrom(dstFrom). + setDestinationPortTo(dstTo); + params.reset().setIndex(1500).setLayer4Params(tparams); + vmatches.add(params.toVtnFlowMatchBuilder().build()); + + // 300: Source MAC == mac1 && VLAN ID == 3 + DataGenerator gen = new DataGenerator(); + EtherAddress mac1 = new EtherAddress(gen.getMacAddress()); + Integer vlan = 3; + eparams.reset().setSourceAddress(mac1.getAddress()).setVlanId(vlan); + params.reset().setIndex(300).setEtherParams(eparams); + vmatches.add(params.toVtnFlowMatchBuilder().build()); + + // 150: Source IP address in 192.168.233.0/24 + IpNetwork srcIp = IpNetwork.create("192.168.233.0/24"); + i4params.reset().setSourceNetwork(srcIp); + params.reset().setIndex(150).setInet4Params(i4params); + vmatches.add(params.toVtnFlowMatchBuilder().build()); + + VtnFlowCondition vfc = new VtnFlowConditionBuilder(). + setName(new VnodeName("fcond")). + setVtnFlowMatch(vmatches).build(); + VTNFlowCondition vfcond = new VTNFlowCondition(vfc); + + // Create an untagged Ethernet frame with type 0x5555. + EtherAddress mac2 = new EtherAddress(gen.getMacAddress()); + EtherAddress mac3 = new EtherAddress(gen.getMacAddress()); + EtherMatchParams ether = new EtherMatchParams(). + setSourceAddress(mac2.getAddress()). + setDestinationAddress(mac3.getAddress()). + setEtherType(Integer.valueOf(0x5555)). + setVlanId(Integer.valueOf(EtherHeader.VLAN_NONE)). + setVlanPriority(Short.valueOf((short)0)); + TestMatchContext ctx = new TestMatchContext().setEtherHeader(ether); + + // Empty flow condition should match every packet. + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + + // vfcond should not match this packet. + assertEquals(false, vfcond.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE, FlowMatchType.DL_SRC). + reset(); + + // Create an Ethernet frame with VLAN tag(vid=10) and type 0x1234. + // Flow match at index 10 should match this packet. + ctx.setEtherHeader(ether.setEtherType(ethType). + setVlanId(Integer.valueOf(10)). + setVlanPriority(Short.valueOf((short)10))); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + assertEquals(true, vfcond.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE).reset(); + + // Create an Ethernet frame to be matched by match at index 300. + ctx.setEtherHeader(ether.setSourceAddress(mac1.getAddress()). + setEtherType(Integer.valueOf(0x3333)). + setVlanId(vlan). + setVlanPriority(Short.valueOf((short)0))); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + assertEquals(true, vfcond.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE, FlowMatchType.DL_SRC). + reset(); + + // Create an UDP packet to be matched by match at index 10000. + Short ipUdp = IPProtocols.UDP.shortValue(); + Integer srcPort = gen.getPort(); + Integer dstPort = gen.getPort(); + IpNetwork ipaddr1 = IpNetwork.create(gen.getInetAddress()); + IpNetwork ipaddr2 = IpNetwork.create(gen.getInetAddress()); + Integer ethIpv4 = EtherTypes.IPv4.intValue(); + ether.setSourceAddress(mac2.getAddress()).setEtherType(ethIpv4). + setVlanId(Integer.valueOf(4095)). + setVlanPriority(Short.valueOf((short)2)); + Inet4MatchParams ipv4 = new Inet4MatchParams(). + setSourceNetwork(ipaddr1).setDestinationNetwork(ipaddr2). + setProtocol(ipUdp).setDscp(dscp); + UdpMatchParams udp = new UdpMatchParams(). + setSourcePortFrom(srcPort). + setDestinationPortFrom(dstPort); + ctx.setEtherHeader(ether).setInetHeader(ipv4).setLayer4Header(udp); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + assertEquals(true, vfcond.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE, FlowMatchType.DL_SRC, + FlowMatchType.IP_SRC, FlowMatchType.IP_PROTO, + FlowMatchType.IP_DSCP).reset(); + + // Change DSCP so that the packet is not be matched. + Short anotherDscp = Short.valueOf((short)(dscp.shortValue() + 1)); + ipv4.setDscp(anotherDscp); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + assertEquals(false, vfcond.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE, FlowMatchType.DL_SRC, + FlowMatchType.IP_SRC, FlowMatchType.IP_PROTO, + FlowMatchType.IP_DSCP).reset(); + + // Create an ICMP packet to be matched by FlowMatch at index 150. + IpNetwork inetSrc = IpNetwork.create("192.168.233.98"); + IcmpMatchParams icmp = new IcmpMatchParams(). + setType(gen.getIcmpValue()).setCode(gen.getIcmpValue()); + Short ipIcmp = IPProtocols.ICMP.shortValue(); + ipv4.setSourceNetwork(inetSrc).setDestinationNetwork(ipaddr2). + setProtocol(ipIcmp).setDscp(dscp); + ether.setVlanId(Integer.valueOf(30)). + setVlanPriority(Short.valueOf((short)1)); + ctx.setEtherHeader(ether).setInetHeader(ipv4).setLayer4Header(icmp); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + assertEquals(true, vfcond.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE, FlowMatchType.IP_SRC). + reset(); + + // Create a TCP packet. + int[] ports = { + dstFrom - 1, + dstFrom, + dstFrom + ((dstTo - dstFrom) >> 1), + dstTo, + dstTo + 1, + }; + + Short ipTcp = IPProtocols.TCP.shortValue(); + TcpMatchParams tcp = new TcpMatchParams(); + ipv4.setSourceNetwork(ipaddr1).setProtocol(ipTcp); + ctx.setEtherHeader(ether).setInetHeader(ipv4).setLayer4Header(tcp); + Set expectedTypes = EnumSet.of( + FlowMatchType.DL_TYPE, FlowMatchType.DL_SRC, FlowMatchType.IP_SRC, + FlowMatchType.IP_PROTO, FlowMatchType.TCP_DST); + for (int port: ports) { + tcp.setSourcePortFrom(gen.getPort()).setDestinationPortFrom(port); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + + // If the destination port is in range [1000, 2000], the match at + // index 1500 should match the packet. + // Otherwise the last match should match the packet. + if (port < dstFrom || port > dstTo) { + expectedTypes.add(FlowMatchType.IP_DSCP); + } else { + expectedTypes.remove(FlowMatchType.IP_DSCP); + } + + assertEquals(true, vfcond.match(ctx)); + ctx.checkMatchFields(expectedTypes).reset(); + } + + // Create a TCP packet that should not be mached. + tcp.setSourcePortFrom(gen.getPort()). + setDestinationPortFrom(dstTo + 1); + ipv4.setDscp(anotherDscp); + assertEquals(true, empty.match(ctx)); + ctx.checkMatchFields().reset(); + expectedTypes.add(FlowMatchType.IP_DSCP); + assertEquals(false, vfcond.match(ctx)); + ctx.checkMatchFields(expectedTypes); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatchTest.java new file mode 100644 index 00000000..7bcf862e --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/cond/VTNFlowMatchTest.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.cond; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.util.VTNIdentifiableComparator; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlDataType; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlValueType; +import org.opendaylight.vtn.manager.internal.util.flow.match.VTNMatchTest; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnFlowMatchConfig; + +/** + * JUnit test for {@link VTNFlowMatch}. + */ +public class VTNFlowMatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNFlowMatch} class. + */ + private static final String XML_ROOT = "vtn-flow-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNFlowMatch} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + List dlist = VTNMatchTest.getXmlDataTypes(name, parent); + dlist.add(new XmlValueType("index", + Integer.class).add(name).prepend(parent)); + return dlist; + } + + /** + * Test case for constructors and getter methods. + * + * @throws Exception An error occurred. + */ + @Test + public void testGetter() throws Exception { + List list = new ArrayList<>(); + + // Test for the upper limit of index. + final int maxId = 65535; + FlowMatchParams params = new FlowMatchParams().setIndex(maxId); + VTNFlowMatch vfmatch = params.toVTNFlowMatch(); + params.verify(vfmatch); + list.add(vfmatch); + + Map cases = + FlowMatchParams.createFlowMatches(); + for (Map.Entry entry: + cases.entrySet()) { + params = entry.getKey(); + FlowMatchParams expected = entry.getValue(); + vfmatch = params.toVTNFlowMatch(); + expected.verify(vfmatch); + list.add(vfmatch); + } + + // Ensure that VTNFlowMatch can be sorted by VTNIdentifiableComparator. + VTNIdentifiableComparator comparator = + new VTNIdentifiableComparator<>(Integer.class); + Collections.sort(list, comparator); + int prev = 0; + for (VTNFlowMatch vf: list) { + int id = vf.getIdentifier().intValue(); + assertTrue(id > prev); + prev = id; + } + assertEquals(maxId, prev); + + // Null argument. + try { + new VTNFlowMatch((FlowMatch)null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Flow match cannot be null", st.getDescription()); + } + + try { + new VTNFlowMatch((VtnFlowMatchConfig)null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("VTN flow match cannot be null", st.getDescription()); + } + + // Invalid index. + Integer[] badIndices = { + null, Integer.MIN_VALUE, -10000000, -3000, -200, -3, -2, -1, 0, + 65536, 65537, 70000, 1000000, Integer.MAX_VALUE, + }; + for (Integer idx: badIndices) { + String msg; + RpcErrorTag etag; + if (idx == null) { + msg = "Match index cannot be null"; + etag = RpcErrorTag.MISSING_ELEMENT; + } else { + msg = "Invalid match index: " + idx; + etag = RpcErrorTag.BAD_ELEMENT; + } + + params = new FlowMatchParams().setIndex(idx); + FlowMatch fm = params.toFlowMatch(); + try { + new VTNFlowMatch(fm); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNFlowMatch#equals(Object)}
  • + *
  • {@link VTNFlowMatch#hashCode()}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + + Map cases = + FlowMatchParams.createFlowMatches(); + for (Map.Entry entry: + cases.entrySet()) { + FlowMatchParams params = entry.getKey(); + FlowMatchParams expected = entry.getValue(); + VTNFlowMatch vfmatch1 = params.toVTNFlowMatch(); + VTNFlowMatch vfmatch2 = expected.toVTNFlowMatch(); + testEquals(set, vfmatch1, vfmatch2); + + Integer idx = params.getIndex().intValue() + 1; + FlowMatchParams p = params.clone().setIndex(idx); + vfmatch1 = p.toVTNFlowMatch(); + vfmatch2 = p.toVTNFlowMatch(); + testEquals(set, vfmatch1, vfmatch2); + } + + assertEquals(cases.size() * 2, set.size()); + } + + /** + * Test case for {@link VTNFlowMatch#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + Class type = VTNFlowMatch.class; + Unmarshaller um = createUnmarshaller(type); + Map cases = + FlowMatchParams.createFlowMatches(); + for (Map.Entry entry: + cases.entrySet()) { + FlowMatchParams params = entry.getKey(); + FlowMatchParams expected = entry.getValue(); + String xml = params.toXmlNode(XML_ROOT).toString(); + VTNFlowMatch vfmatch = unmarshal(um, xml, type); + vfmatch.verify(); + expected.verify(vfmatch); + + xml = expected.toXmlNode(XML_ROOT).toString(); + VTNFlowMatch vfmatch1 = unmarshal(um, xml, type); + vfmatch1.verify(); + assertEquals(vfmatch, vfmatch1); + } + + // Invalid index. + Integer[] badIndices = { + null, Integer.MIN_VALUE, -10000000, -3000, -200, -3, -2, -1, 0, + 65536, 65537, 70000, 1000000, Integer.MAX_VALUE, + }; + for (Integer idx: badIndices) { + XmlNode xn = new XmlNode(XML_ROOT); + String msg; + RpcErrorTag etag; + if (idx == null) { + msg = "Match index cannot be null"; + etag = RpcErrorTag.MISSING_ELEMENT; + } else { + msg = "Invalid match index: " + idx; + etag = RpcErrorTag.BAD_ELEMENT; + xn.add(new XmlNode("index", idx)); + } + + VTNFlowMatch vfmatch = unmarshal(um, xn.toString(), type); + try { + vfmatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(etag, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals(msg, st.getDescription()); + } + } + + // Ensure that broken values in XML can be detected. + jaxbErrorTest(um, type, getXmlDataTypes(XML_ROOT)); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/EtherMatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/EtherMatchParams.java new file mode 100644 index 00000000..db1ff22d --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/EtherMatchParams.java @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.NumberUtils; + +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestination; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSource; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp; + +/** + * {@code EtherMatchParams} describes parameters for conditions to match + * against Ethernet header. + */ +public final class EtherMatchParams extends TestBase + implements EtherHeader, Cloneable { + /** + * The source MAC address. + */ + private EtherAddress sourceAddress; + + /** + * The destination MAC address. + */ + private EtherAddress destinationAddress; + + /** + * Ethernet type. + */ + private Integer etherType; + + /** + * VLAN ID. + */ + private Integer vlanId; + + /** + * Vlan priority. + */ + private Short vlanPriority; + + /** + * Set the source MAC address. + * + * @param src A long integer value which represents the source MAC + * address. + * @return This instance. + */ + public EtherMatchParams setSourceAddress(long src) { + sourceAddress = new EtherAddress(src); + return this; + } + + /** + * Set the source MAC address. + * + * @param src A byte array which represents the source MAC address. + * @return This instance. + */ + public EtherMatchParams setSourceAddress(byte[] src) { + sourceAddress = new EtherAddress(src); + return this; + } + + /** + * Set the destination MAC address. + * + * @param dst A long integer value which represents the destination MAC + * address. + * @return This instance. + */ + public EtherMatchParams setDestinationAddress(long dst) { + destinationAddress = new EtherAddress(dst); + return this; + } + + /** + * Set the destination MAC address. + * + * @param dst A byte array which represents the destination MAC address. + * @return This instance. + */ + public EtherMatchParams setDestinationAddress(byte[] dst) { + destinationAddress = new EtherAddress(dst); + return this; + } + + /** + * Set the Ethernet type. + * + * @param type Ethernet type. + * @return This instance. + */ + public EtherMatchParams setEtherType(Integer type) { + etherType = type; + return this; + } + + /** + * Set the VLAN ID. + * + * @param vid VLAN ID. + * @return This instance. + */ + public EtherMatchParams setVlanId(Integer vid) { + vlanId = vid; + return this; + } + + /** + * Set the VLAN ID. + * + * @param vid VLAN ID. + * @return This instance. + */ + public EtherMatchParams setVlanId(Short vid) { + vlanId = NumberUtils.toInteger(vid); + return this; + } + + /** + * Set the VLAN priority. + * + * @param pcp VLAN priority. + * @return This instance. + */ + public EtherMatchParams setVlanPriority(Short pcp) { + vlanPriority = pcp; + return this; + } + + /** + * Set the VLAN priority. + * + * @param pcp VLAN priority. + * @return This instance. + */ + public EtherMatchParams setVlanPriority(Byte pcp) { + vlanPriority = NumberUtils.toShort(pcp); + return this; + } + + /** + * Reset to the initial state. + * + * @return This instance. + */ + public EtherMatchParams reset() { + sourceAddress = null; + destinationAddress = null; + etherType = null; + vlanId = null; + vlanPriority = null; + return this; + } + + /** + * Construct an + * {@link org.opendaylight.vtn.manager.flow.cond.EthernetMatch} instance. + * + * @return An {@link org.opendaylight.vtn.manager.flow.cond.EthernetMatch} + * instance. + */ + public org.opendaylight.vtn.manager.flow.cond.EthernetMatch toEthernetMatch() { + Short vid = NumberUtils.toShort(vlanId); + Byte pcp = NumberUtils.toByte(vlanPriority); + return new org.opendaylight.vtn.manager.flow.cond.EthernetMatch( + sourceAddress, destinationAddress, etherType, vid, pcp); + } + + /** + * Construct a {@link VtnEtherMatch} instance. + * + * @return A {@link VtnEtherMatch} instance. + */ + public VtnEtherMatch toVtnEtherMatch() { + VtnEtherMatchBuilder builder = new VtnEtherMatchBuilder(); + + if (sourceAddress != null) { + builder.setSourceAddress(sourceAddress.getMacAddress()); + } + + if (destinationAddress != null) { + builder.setDestinationAddress(destinationAddress.getMacAddress()); + } + + if (etherType != null) { + Long et = NumberUtils.toLong(etherType); + builder.setEtherType(new EtherType(et)); + } + + if (vlanId != null) { + builder.setVlanId(new VlanId(vlanId)); + } + + if (vlanPriority != null) { + builder.setVlanPcp(new VlanPcp(vlanPriority)); + } + + return builder.build(); + } + + /** + * Construct a new {@link VTNEtherMatch} instance. + * + * @return A {@link VTNEtherMatch} instance. + * @throws Exception An error occurred. + */ + public VTNEtherMatch toVTNEtherMatch() throws Exception { + return new VTNEtherMatch(toVtnEtherMatch()); + } + + /** + * Return a {@link XmlNode} instance which represents this instance. + * + * @param name The name of the root node. + * @return A {@link XmlNode} instance. + */ + public XmlNode toXmlNode(String name) { + XmlNode root = new XmlNode(name); + if (sourceAddress != null) { + root.add(new XmlNode("source-address", sourceAddress.getText())); + } + + if (destinationAddress != null) { + root.add(new XmlNode("destination-address", + destinationAddress.getText())); + } + + if (etherType != null) { + root.add(new XmlNode("ether-type", etherType)); + } + + if (vlanId != null) { + root.add(new XmlNode("vlan-id", vlanId)); + } + + if (vlanPriority != null) { + root.add(new XmlNode("vlan-pcp", vlanPriority)); + } + + return root; + } + + /** + * Ensure that the given {@link VTNEtherMatch} instance contains the same + * Ethernet conditions as this instance. + * + * @param ematch A {@link VTNEtherMatch} instance. + */ + public void verifyValues(VTNEtherMatch ematch) { + assertEquals(sourceAddress, ematch.getSourceAddress()); + assertEquals(destinationAddress, ematch.getDestinationAddress()); + assertEquals(etherType, ematch.getEtherType()); + assertEquals(vlanId, ematch.getVlanId()); + assertEquals(vlanPriority, ematch.getVlanPriority()); + assertEquals(isEmpty(), ematch.isEmpty()); + } + + /** + * Ensure that the given {@link VTNEtherMatch} instance contains the same + * Ethernet conditions as this instance. + * + * @param ematch A {@link VTNEtherMatch} instance. + * @throws Exception An error occurred. + */ + public void verify(VTNEtherMatch ematch) throws Exception { + verifyValues(ematch); + + org.opendaylight.vtn.manager.flow.cond.EthernetMatch em = + ematch.toEthernetMatch(); + assertEquals(sourceAddress, em.getSourceEtherAddress()); + assertEquals(destinationAddress, em.getDestinationEtherAddress()); + assertEquals(etherType, em.getType()); + assertEquals(NumberUtils.toShort(vlanId), em.getVlan()); + assertEquals(NumberUtils.toByte(vlanPriority), em.getVlanPriority()); + + MatchBuilder mb = new MatchBuilder(); + ematch.setMatch(mb); + boolean hasValue = verify(mb); + + VTNEtherMatch ematch1 = VTNEtherMatch.create(mb.build()); + assertEquals((hasValue) ? ematch : null, ematch1); + } + + /** + * Ensure that the given {@link MatchBuilder} instance contains the same + * Ethernet conditions as this instance. + * + * @param builder A {@link MatchBuilder} instance. + * @return {@code true} only if the given match contains the condition for + * the Ethernet header. + */ + public boolean verify(MatchBuilder builder) { + boolean isEther = false; + boolean isVlan = false; + EthernetMatch ematch = builder.getEthernetMatch(); + if (ematch == null) { + assertEquals(null, sourceAddress); + assertEquals(null, destinationAddress); + assertEquals(null, etherType); + } else { + if (sourceAddress == null) { + assertEquals(null, ematch.getEthernetSource()); + } else { + EthernetSource src = ematch.getEthernetSource(); + assertEquals(sourceAddress.getMacAddress(), src.getAddress()); + assertEquals(null, src.getMask()); + isEther = true; + } + + if (destinationAddress == null) { + assertEquals(null, ematch.getEthernetDestination()); + } else { + EthernetDestination dst = ematch.getEthernetDestination(); + assertEquals(destinationAddress.getMacAddress(), + dst.getAddress()); + assertEquals(null, dst.getMask()); + isEther = true; + } + + if (etherType == null) { + assertEquals(null, ematch.getEthernetType()); + } else { + EthernetType etype = ematch.getEthernetType(); + assertEquals(etype.getType().getValue(), + NumberUtils.toLong(etherType)); + isEther = true; + } + assertTrue(isEther); + } + + VlanMatch vmatch = builder.getVlanMatch(); + if (vmatch == null) { + assertEquals(null, vlanId); + assertEquals(null, vlanPriority); + } else { + if (vlanId == null) { + assertEquals(null, vmatch.getVlanId()); + } else { + org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanId tag = + vmatch.getVlanId(); + int vid = vlanId.intValue(); + boolean present = (vid != VLAN_NONE); + assertEquals(vlanId, tag.getVlanId().getValue()); + assertEquals(Boolean.valueOf(present), tag.isVlanIdPresent()); + isVlan = true; + } + + if (vlanPriority == null) { + assertEquals(null, vmatch.getVlanPcp()); + } else { + VlanPcp pcp = vmatch.getVlanPcp(); + assertEquals(vlanPriority, pcp.getValue()); + isVlan = true; + } + assertTrue(isVlan); + } + + return (isEther || isVlan); + } + + /** + * Determine whether this instance does not specify any Ethernet header + * field or not. + * + * @return {@code true} only if this instance is empty. + */ + public boolean isEmpty() { + return (sourceAddress == null && destinationAddress == null && + etherType == null && vlanId == null && vlanPriority == null); + } + + // EtherHeader + + /** + * {@inheritDoc} + */ + @Override + public EtherAddress getSourceAddress() { + return sourceAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSourceAddress(EtherAddress mac) { + sourceAddress = mac; + } + + /** + * {@inheritDoc} + */ + @Override + public EtherAddress getDestinationAddress() { + return destinationAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDestinationAddress(EtherAddress mac) { + destinationAddress = mac; + } + + /** + * {@inheritDoc} + */ + @Override + public int getEtherType() { + return etherType.intValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public int getVlanId() { + return (vlanId == null) ? VLAN_NONE : vlanId.intValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setVlanId(int vid) { + vlanId = Integer.valueOf(vid); + } + + /** + * {@inheritDoc} + */ + @Override + public short getVlanPriority() { + return (vlanPriority == null) ? -1 : vlanPriority.shortValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setVlanPriority(short pcp) { + vlanPriority = Short.valueOf(pcp); + } + + /** + * {@inheritDoc} + */ + @Override + public void setDescription(StringBuilder builder) { + } + + // Cloneable + + /** + * Return a shallow copy of this instance. + * + * @return A shallow copy of this instance. + */ + @Override + public EtherMatchParams clone() { + try { + return (EtherMatchParams)super.clone(); + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed.", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchTypeTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchTypeTest.java new file mode 100644 index 00000000..424f2953 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/FlowMatchTypeTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.Set; +import java.util.EnumSet; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.internal.TestBase; + +/** + * Test case for {@link FlowMatchType}. + */ +public class FlowMatchTypeTest extends TestBase { + /** + * Verify values. + */ + @Test + public void testValues() { + int i = 0; + assertEquals(i++, FlowMatchType.IN_PORT.ordinal()); + assertEquals(i++, FlowMatchType.DL_SRC.ordinal()); + assertEquals(i++, FlowMatchType.DL_DST.ordinal()); + assertEquals(i++, FlowMatchType.DL_TYPE.ordinal()); + assertEquals(i++, FlowMatchType.DL_VLAN.ordinal()); + assertEquals(i++, FlowMatchType.DL_VLAN_PCP.ordinal()); + assertEquals(i++, FlowMatchType.IP_SRC.ordinal()); + assertEquals(i++, FlowMatchType.IP_DST.ordinal()); + assertEquals(i++, FlowMatchType.IP_PROTO.ordinal()); + assertEquals(i++, FlowMatchType.IP_DSCP.ordinal()); + assertEquals(i++, FlowMatchType.TCP_SRC.ordinal()); + assertEquals(i++, FlowMatchType.TCP_DST.ordinal()); + assertEquals(i++, FlowMatchType.UDP_SRC.ordinal()); + assertEquals(i++, FlowMatchType.UDP_DST.ordinal()); + assertEquals(i++, FlowMatchType.ICMP_TYPE.ordinal()); + assertEquals(i++, FlowMatchType.ICMP_CODE.ordinal()); + assertEquals(i, FlowMatchType.values().length); + } + + /** + * Test case for {@link FlowMatchType#addUnicastTypes(Set)}. + */ + @Test + public void testAddUnicastTypes() { + Set set = EnumSet.noneOf(FlowMatchType.class); + FlowMatchType.addUnicastTypes(set); + assertEquals(2, set.size()); + assertTrue(set.contains(FlowMatchType.DL_SRC)); + assertTrue(set.contains(FlowMatchType.DL_DST)); + } + + /** + * Test case for {@link FlowMatchType#getUnicastTypeCount(Set)}. + */ + @Test + public void testGetUnicastTypeCount() { + Set set = EnumSet.noneOf(FlowMatchType.class); + assertEquals(0, FlowMatchType.getUnicastTypeCount(set)); + + for (FlowMatchType type: FlowMatchType.values()) { + int count; + switch (type) { + case DL_SRC: + case DL_DST: + count = 1; + break; + + default: + count = 0; + break; + } + + set = EnumSet.of(type); + assertEquals(count, FlowMatchType.getUnicastTypeCount(set)); + } + + set = EnumSet.of(FlowMatchType.DL_SRC, FlowMatchType.DL_DST); + assertEquals(2, FlowMatchType.getUnicastTypeCount(set)); + set = EnumSet.allOf(FlowMatchType.class); + assertEquals(2, FlowMatchType.getUnicastTypeCount(set)); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/IcmpMatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/IcmpMatchParams.java new file mode 100644 index 00000000..be529492 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/IcmpMatchParams.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; + +import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.IcmpHeader; + +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnIcmpMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnIcmpMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code IcmpMatchParams} describes parameters for conditions to match against + * ICMP header. + */ +public final class IcmpMatchParams extends Layer4MatchParams + implements IcmpHeader { + /** + * The ICMP type. + */ + private Short icmpType; + + /** + * The ICMP code. + */ + private Short icmpCode; + + /** + * Test case for {@link VTNIcmpMatch#getInetProtocol(IpVersion)}. + * + * @param imatch A {@link VTNIcmpMatch} instance. + */ + public static void checkInetProtocol(VTNIcmpMatch imatch) { + ArrayList vers = new ArrayList<>(); + vers.add(null); + for (IpVersion ver: IpVersion.values()) { + vers.add(ver); + } + for (IpVersion ver: vers) { + if (ver == IpVersion.Ipv4) { + assertEquals(IPProtocols.ICMP.shortValue(), + imatch.getInetProtocol(ver)); + } else { + try { + imatch.getInetProtocol(ver); + unexpected(); + } catch (IllegalStateException e) { + assertEquals("Unsupported IP version: " + ver, + e.getMessage()); + } + } + } + } + + /** + * Construct an empty instance. + */ + public IcmpMatchParams() { + } + + /** + * Construct a new instance. + * + * @param type The ICMP type. + * @param code The ICMP code. + */ + public IcmpMatchParams(Short type, Short code) { + icmpType = type; + icmpCode = code; + } + + /** + * Return the ICMP type. + * + * @return The ICMP type. + */ + public Short getType() { + return icmpType; + } + + /** + * Set the ICMP type. + * + * @param type The ICMP type. + * @return This instance. + */ + public IcmpMatchParams setType(Short type) { + icmpType = type; + return this; + } + + /** + * Return the ICMP code. + * + * @return The ICMP code. + */ + public Short getCode() { + return icmpCode; + } + + /** + * Set the ICMP code. + * + * @param code The ICMP code. + * @return This instance. + */ + public IcmpMatchParams setCode(Short code) { + icmpCode = code; + return this; + } + + /** + * Reset to the initial state. + * + * @return This instance. + */ + public IcmpMatchParams reset() { + icmpType = null; + icmpCode = null; + return this; + } + + // IcmpHeader + + /** + * {@inheritDoc} + */ + @Override + public short getIcmpType() { + return icmpType.shortValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setIcmpType(short type) { + icmpType = Short.valueOf(type); + } + + /** + * {@inheritDoc} + */ + @Override + public short getIcmpCode() { + return icmpCode.shortValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setIcmpCode(short code) { + icmpCode = Short.valueOf(code); + } + + // Layer4MatchParams + + /** + * {@inheritDoc} + */ + @Override + public IcmpMatch toL4Match() { + return new IcmpMatch(icmpType, icmpCode); + } + + /** + * {@inheritDoc} + */ + @Override + public VtnIcmpMatch toVtnLayer4Match() { + return new VtnIcmpMatchBuilder().setType(icmpType).setCode(icmpCode). + build(); + } + + /** + * {@inheritDoc} + */ + @Override + public VTNIcmpMatch toVTNLayer4Match() throws Exception { + return new VTNIcmpMatch(toL4Match()); + } + + /** + * {@inheritDoc} + */ + @Override + public XmlNode toXmlNode() { + return toXmlNode("vtn-icmp-match"); + } + + /** + * {@inheritDoc} + */ + @Override + public XmlNode toXmlNode(String name) { + XmlNode root = new XmlNode(name); + if (icmpType != null) { + root.add(new XmlNode("type", icmpType)); + } + if (icmpCode != null) { + root.add(new XmlNode("code", icmpCode)); + } + + return root; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + return (icmpType == null && icmpCode == null); + } + + /** + * {@inheritDoc} + */ + @Override + public VTNIcmpMatch verifyValues(VTNLayer4Match l4m) { + assertTrue(l4m instanceof VTNIcmpMatch); + VTNIcmpMatch imatch = (VTNIcmpMatch)l4m; + assertEquals(icmpType, imatch.getIcmpType()); + assertEquals(icmpCode, imatch.getIcmpCode()); + assertEquals(isEmpty(), imatch.isEmpty()); + return imatch; + } + + /** + * {@inheritDoc} + */ + @Override + public void verify(VTNLayer4Match l4m) throws Exception { + VTNIcmpMatch imatch = verifyValues(l4m); + checkInetProtocol(imatch); + + IcmpMatch im = imatch.toL4Match(); + assertEquals(icmpType, im.getType()); + assertEquals(icmpCode, im.getCode()); + + VtnFlowMatchBuilder vfmb = new VtnFlowMatchBuilder(); + imatch.setVtnMatch(vfmb); + VtnLayer4Match vl4 = vfmb.getVtnLayer4Match(); + if (vl4 == null) { + assertEquals(null, icmpType); + assertEquals(null, icmpCode); + assertEquals(null, VTNLayer4Match.create(vl4)); + } else { + assertTrue(vl4 instanceof VtnIcmpMatch); + VtnIcmpMatch vim = (VtnIcmpMatch)vl4; + assertEquals(icmpType, vim.getType()); + assertEquals(icmpCode, vim.getCode()); + assertEquals(imatch, VTNLayer4Match.create(vl4)); + } + + MatchBuilder mb = new MatchBuilder(); + imatch.setMatch(mb, IpVersion.Ipv4); + boolean hasValue = verify(mb); + + VTNLayer4Match l4 = VTNLayer4Match.create(mb.build()); + if (hasValue) { + assertTrue(l4 instanceof VTNIcmpMatch); + VTNIcmpMatch imatch1 = (VTNIcmpMatch)l4; + assertEquals(icmpType, imatch1.getIcmpType()); + assertEquals(icmpCode, imatch1.getIcmpCode()); + } else { + assertEquals(null, l4); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean verify(MatchBuilder builder) { + assertEquals(null, builder.getIcmpv6Match()); + Icmpv4Match i4match = builder.getIcmpv4Match(); + if (i4match == null) { + assertEquals(null, icmpType); + assertEquals(null, icmpCode); + return false; + } + + boolean hasValue = false; + assertEquals(icmpType, i4match.getIcmpv4Type()); + if (icmpType != null) { + hasValue = true; + } + + assertEquals(icmpCode, i4match.getIcmpv4Code()); + if (icmpCode != null) { + hasValue = true; + } + + assertTrue(hasValue); + return hasValue; + } + + /** + * {@inheritDoc} + */ + @Override + public void verifyMd(VTNLayer4Match l4m) throws Exception { + assertTrue(l4m instanceof VTNIcmpMatch); + VTNIcmpMatch imatch = (VTNIcmpMatch)l4m; + assertEquals(icmpType, imatch.getIcmpType()); + assertEquals(icmpCode, imatch.getIcmpCode()); + } + + /** + * {@inheritDoc} + */ + @Override + protected Class getMatchType() { + return IcmpMatchParams.class; + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public IcmpMatchParams clone() { + return (IcmpMatchParams)super.clone(); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Inet4MatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Inet4MatchParams.java new file mode 100644 index 00000000..a37ed13b --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Inet4MatchParams.java @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.net.InetAddress; + +import org.opendaylight.vtn.manager.flow.cond.Inet4Match; +import org.opendaylight.vtn.manager.flow.cond.InetMatch; + +import org.opendaylight.vtn.manager.util.IpNetwork; +import org.opendaylight.vtn.manager.util.NumberUtils; + +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; + +/** + * {@code Inet4MatchParams} describes parameters for conditions to match + * against IPv4 header. + */ +public final class Inet4MatchParams extends TestBase + implements InetHeader, Cloneable { + /** + * The source IP address. + */ + private IpNetwork sourceAddress; + + /** + * The destination IP address. + */ + private IpNetwork destinationAddress; + + /** + * Prefix length for the source IP network. + */ + private Short sourcePrefix; + + /** + * Prefix length for the destination IP network. + */ + private Short destinationPrefix; + + /** + * The IP protocol number. + */ + private Short protocol; + + /** + * The IP DSCP field value. + */ + private Short dscp; + + /** + * Set the IP network to match against the source IP address. + * + * @param ipn An {@link IpNetwork} instance. + * @return This instance. + */ + public Inet4MatchParams setSourceNetwork(IpNetwork ipn) { + if (ipn == null) { + sourceAddress = null; + sourcePrefix = null; + } else { + sourceAddress = IpNetwork.create(ipn.getInetAddress()); + sourcePrefix = (ipn.isAddress()) + ? null : Short.valueOf((short)ipn.getPrefixLength()); + } + + return this; + } + + /** + * Set the IP address to match against the source IP address. + * + * @param ip An {@link InetAddress} instance. + * @return This instance. + */ + public Inet4MatchParams setSourceAddress(InetAddress ip) { + sourceAddress = IpNetwork.create(ip); + return this; + } + + /** + * Set the IP network to match against the destination IP address. + * + * @param ipn An {@link IpNetwork} instance. + * @return This instance. + */ + public Inet4MatchParams setDestinationNetwork(IpNetwork ipn) { + if (ipn == null) { + destinationAddress = null; + destinationPrefix = null; + } else { + destinationAddress = IpNetwork.create(ipn.getInetAddress()); + destinationPrefix = (ipn.isAddress()) + ? null : Short.valueOf((short)ipn.getPrefixLength()); + } + + return this; + } + + /** + * Set the IP address to match against the destination IP address. + * + * @param ip An {@link InetAddress} instance. + * @return This instance. + */ + public Inet4MatchParams setDestinationAddress(InetAddress ip) { + destinationAddress = IpNetwork.create(ip); + return this; + } + + /** + * Set the prefix length for the source IP network. + * + * @param len The prefix length. + * @return This instance. + */ + public Inet4MatchParams setSourcePrefix(Short len) { + sourcePrefix = len; + return this; + } + + /** + * Set the prefix length for the destination IP network. + * + * @param len The prefix length. + * @return This instance. + */ + public Inet4MatchParams setDestinationPrefix(Short len) { + destinationPrefix = len; + return this; + } + + /** + * Set the IP protocol number. + * + * @param proto The IP protocol number. + * @return This instance. + */ + public Inet4MatchParams setProtocol(Short proto) { + protocol = proto; + return this; + } + + /** + * Set the IP DSCP field value. + * + * @param value The DSCP field value. + * @return This instance. + */ + public Inet4MatchParams setDscp(Short value) { + dscp = value; + return this; + } + + /** + * Reset to the initial state. + * + * @return This instance. + */ + public Inet4MatchParams reset() { + sourceAddress = null; + destinationAddress = null; + sourcePrefix = null; + destinationPrefix = null; + protocol = null; + dscp = null; + return this; + } + + /** + * Construct an {@link Inet4Match} instance. + * + * @return An {@link Inet4Match} instance. + */ + public Inet4Match toInet4Match() { + InetAddress src = (sourceAddress == null) + ? null : sourceAddress.getInetAddress(); + InetAddress dst = (destinationAddress == null) + ? null : destinationAddress.getInetAddress(); + Byte d = NumberUtils.toByte(dscp); + return new Inet4Match(src, sourcePrefix, dst, destinationPrefix, + protocol, d); + } + + /** + * Construct a {@link VtnInetMatch} instance. + * + * @return A {@link VtnInetMatch} instance. + */ + public VtnInetMatch toVtnInetMatch() { + VtnInetMatchBuilder builder = new VtnInetMatchBuilder(); + + IpPrefix src = getIpPrefix(sourceAddress, sourcePrefix); + if (src != null) { + builder.setSourceNetwork(src); + } + + IpPrefix dst = getIpPrefix(destinationAddress, destinationPrefix); + if (dst != null) { + builder.setDestinationNetwork(dst); + } + + if (protocol != null) { + builder.setProtocol(protocol); + } + + if (dscp != null) { + builder.setDscp(new Dscp(dscp)); + } + + return builder.build(); + } + + /** + * Construct a new {@link VTNInet4Match} instance. + * + * @return A {@link VTNInet4Match} instance. + * @throws Exception An error occurred. + */ + public VTNInet4Match toVTNInet4Match() throws Exception { + return new VTNInet4Match(toInet4Match()); + } + + /** + * Return a {@link XmlNode} instance which represents this instance. + * + * @param name The name of the root node. + * @return A {@link XmlNode} instance. + */ + public XmlNode toXmlNode(String name) { + XmlNode root = new XmlNode(name); + IpNetwork src = getIpNetwork(sourceAddress, sourcePrefix); + if (src != null) { + root.add(new XmlNode("source-network-v4", src.getText())); + } + + IpNetwork dst = getIpNetwork(destinationAddress, destinationPrefix); + if (dst != null) { + root.add(new XmlNode("destination-network-v4", dst.getText())); + } + + if (protocol != null) { + root.add(new XmlNode("protocol", protocol)); + } + + if (dscp != null) { + root.add(new XmlNode("dscp", dscp)); + } + + return root; + } + + /** + * Ensure that the given {@link VTNInet4Match} instance contains the same + * IP conditions as this instance. + * + * @param imatch A {@link VTNInet4Match} instance. + * @param src An {@link IpNetwork} instance which represents the + * source IP network configured in this instance. + * @param dst An {@link IpNetwork} instance which represents the + * destniation IP network configured in this instance. + */ + public void verifyValues(VTNInet4Match imatch, IpNetwork src, + IpNetwork dst) { + assertEquals(src, imatch.getSourceNetwork()); + assertEquals(dst, imatch.getDestinationNetwork()); + assertEquals(protocol, imatch.getProtocol()); + assertEquals(dscp, imatch.getDscp()); + } + + /** + * Ensure that the given {@link VTNInet4Match} instance contains the same + * IP conditions as this instance. + * + * @param imatch A {@link VTNInet4Match} instance. + */ + public void verifyValues(VTNInet4Match imatch) { + IpNetwork src = getIpNetwork(sourceAddress, sourcePrefix); + IpNetwork dst = getIpNetwork(destinationAddress, destinationPrefix); + verifyValues(imatch, src, dst); + assertEquals(isEmpty(), imatch.isEmpty()); + } + + /** + * Ensure that the given {@link VTNInet4Match} instance contains the same + * IP conditions as this instance. + * + * @param imatch A {@link VTNInet4Match} instance. + * @throws Exception An error occurred. + */ + public void verify(VTNInet4Match imatch) throws Exception { + IpNetwork src = getIpNetwork(sourceAddress, sourcePrefix); + IpNetwork dst = getIpNetwork(destinationAddress, destinationPrefix); + verifyValues(imatch, src, dst); + + InetMatch im = imatch.toInetMatch(); + assertTrue(im instanceof Inet4Match); + InetAddress srcAddr = im.getSourceAddress(); + Short srcSuff = im.getSourceSuffix(); + InetAddress dstAddr = im.getDestinationAddress(); + Short dstSuff = im.getDestinationSuffix(); + assertEquals(src, getIpNetwork(srcAddr, srcSuff)); + assertEquals(dst, getIpNetwork(dstAddr, dstSuff)); + assertEquals(protocol, im.getProtocol()); + assertEquals(NumberUtils.toByte(dscp), im.getDscp()); + + VtnInetMatch vim = imatch.toVtnInetMatchBuilder().build(); + assertEquals(src, IpNetwork.create(vim.getSourceNetwork())); + assertEquals(dst, IpNetwork.create(vim.getDestinationNetwork())); + assertEquals(protocol, vim.getProtocol()); + if (dscp == null) { + assertEquals(null, vim.getDscp()); + } else { + assertEquals(dscp, vim.getDscp().getValue()); + } + + MatchBuilder mb = new MatchBuilder(); + imatch.setMatch(mb); + boolean hasValue = verify(mb); + + VTNInetMatch imatch1 = VTNInetMatch.create(mb.build()); + assertEquals((hasValue) ? imatch : null, imatch1); + } + + /** + * Ensure that the given {@link MatchBuilder} instance contains the same + * IP conditions as this instance. + * + * @param builder A {@link MatchBuilder} instance. + * @return {@code true} only if the given match contains the condition + * for the IP header. + */ + public boolean verify(MatchBuilder builder) { + boolean isIp = false; + boolean isIpv4 = false; + IpMatch imatch = builder.getIpMatch(); + if (imatch == null) { + assertEquals(null, protocol); + assertEquals(null, dscp); + } else { + assertEquals(protocol, imatch.getIpProtocol()); + if (protocol != null) { + isIp = true; + } + + if (dscp == null) { + assertEquals(null, imatch.getIpDscp()); + } else { + assertEquals(dscp, imatch.getIpDscp().getValue()); + isIp = true; + } + assertTrue(isIp); + } + + Layer3Match l3 = builder.getLayer3Match(); + if (l3 == null) { + assertEquals(null, sourceAddress); + assertEquals(null, destinationAddress); + } else { + assertTrue(l3 instanceof Ipv4Match); + Ipv4Match i4match = (Ipv4Match)l3; + if (sourceAddress == null) { + assertEquals(null, i4match.getIpv4Source()); + } else { + Ipv4Prefix pfx = i4match.getIpv4Source(); + IpNetwork src = getIpNetwork(sourceAddress, sourcePrefix); + IpPrefix ipp = src.getIpPrefix(); + assertEquals(pfx, ipp.getIpv4Prefix()); + assertEquals(null, ipp.getIpv6Prefix()); + isIpv4 = true; + } + + if (destinationAddress == null) { + assertEquals(null, i4match.getIpv4Destination()); + } else { + Ipv4Prefix pfx = i4match.getIpv4Destination(); + IpNetwork dst = + getIpNetwork(destinationAddress, destinationPrefix); + IpPrefix ipp = dst.getIpPrefix(); + assertEquals(pfx, ipp.getIpv4Prefix()); + assertEquals(null, ipp.getIpv6Prefix()); + isIpv4 = true; + } + assertTrue(isIpv4); + } + + return (isIp || isIpv4); + } + + /** + * Determine whether this instance does not specify any IP header field + * or not. + * + * @return {@code true} only if this instance is empty. + */ + public boolean isEmpty() { + return (sourceAddress == null && destinationAddress == null && + protocol == null && dscp == null); + } + + /** + * Create an {@link IpNetwork}. + * + * @param addr An {@link IpNetwork} instance which represents the + * IP address. + * @param prefix The network prefix length. + * @return A {@link IpNetwork} or {@code null}. + */ + private IpNetwork getIpNetwork(IpNetwork addr, Short prefix) { + if (addr == null) { + return null; + } + + int len = (prefix == null) ? 0 : prefix.intValue(); + return IpNetwork.create(addr.getInetAddress(), len); + } + + /** + * Create an {@link IpNetwork}. + * + * @param addr An {@link InetAddress} instance which represents the + * IP address. + * @param prefix The network prefix length. + * @return A {@link IpNetwork} or {@code null}. + */ + private IpNetwork getIpNetwork(InetAddress addr, Short prefix) { + if (addr == null) { + return null; + } + + int len = (prefix == null) ? 0 : prefix.intValue(); + return IpNetwork.create(addr, len); + } + + /** + * Create an {@link IpPrefix}. + * + * @param addr An {@link IpNetwork} instance which represents the + * IP address. + * @param prefix The network prefix length. + * @return A {@link IpPrefix} or {@code null}. + */ + private IpPrefix getIpPrefix(IpNetwork addr, Short prefix) { + if (addr == null) { + return null; + } + + int len = (prefix == null) ? 0 : prefix.intValue(); + StringBuilder builder = new StringBuilder(addr.getText()). + append('/').append(len); + Ipv4Prefix v4 = new Ipv4Prefix(builder.toString()); + return new IpPrefix(v4); + } + + // InetHeader + + /** + * {@inheritDoc} + */ + @Override + public IpNetwork getSourceAddress() { + return sourceAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSourceAddress(IpNetwork ipn) { + sourceAddress = ipn; + } + + /** + * {@inheritDoc} + */ + @Override + public IpNetwork getDestinationAddress() { + return destinationAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDestinationAddress(IpNetwork ipn) { + destinationAddress = ipn; + } + + /** + * {@inheritDoc} + */ + @Override + public short getProtocol() { + return protocol.shortValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public short getDscp() { + return dscp.shortValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setDscp(short value) { + dscp = Short.valueOf(value); + } + + /** + * {@inheritDoc} + */ + @Override + public void setDescription(StringBuilder builder) { + } + + // Cloneable + + /** + * Return a shallow copy of this instance. + * + * @return A shallow copy of this instance. + */ + @Override + public Inet4MatchParams clone() { + try { + return (Inet4MatchParams)super.clone(); + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed.", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4MatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4MatchParams.java new file mode 100644 index 00000000..3dd5a9fe --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4MatchParams.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.flow.cond.L4Match; + +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; + +/** + * {@code Layer4MatchParams} describes parameters for condition to match + * against layer 4 protocol header. + * + * @param The type of this instance. + */ +public abstract class Layer4MatchParams + extends TestBase implements Layer4Header, Cloneable { + /** + * Construct a {@link L4Match} instance. + * + * @return A {@link L4Match} instance that contains the settings + * configured in this instance. + */ + public abstract L4Match toL4Match(); + + /** + * Construct a {@link VtnLayer4Match} instance. + * + * @return A {@link VtnLayer4Match} instance that contains the settings + * configured in this instance. + */ + public abstract VtnLayer4Match toVtnLayer4Match(); + + /** + * Construct a {@link VTNLayer4Match} instance. + * + * @return A {@link VTNLayer4Match} instance that contains the settings + * configured in this instance. + * @throws Exception An error occurred. + */ + public abstract VTNLayer4Match toVTNLayer4Match() throws Exception; + + /** + * Return a {@link XmlNode} instance which represents this instance. + * + *

+ * This method returns a {@link XmlNode} to be configured in a + * {@link VTNMatch} instance. + *

+ * + * @return A {@link XmlNode} instance. + */ + public abstract XmlNode toXmlNode(); + + /** + * Return a {@link XmlNode} instance which represents this instance. + * + * @param name The name of the root node. + * @return A {@link XmlNode} instance. + */ + public abstract XmlNode toXmlNode(String name); + + /** + * Determine whether this condition is empty or not. + * + * @return {@code true} only if this instance does not contain any + * condition. + */ + public abstract boolean isEmpty(); + + /** + * Ensure that the given {@link VTNLayer4Match} instance contains the same + * conditions as this instance. + * + * @param l4m A {@link VTNLayer4Match} instance. + * @return The given instance. + */ + public abstract VTNLayer4Match verifyValues(VTNLayer4Match l4m); + + /** + * Ensure that the given {@link VTNLayer4Match} instance contains the same + * conditions as this instance. + * + * @param l4m A {@link VTNLayer4Match} instance. + * @throws Exception An errror occurred. + */ + public abstract void verify(VTNLayer4Match l4m) throws Exception; + + /** + * Ensure that the given {@link MatchBuilder} instance contains the same + * conditions as this instance. + * + * @param builder A {@link MatchBuilder} instance. + * @return {@code true} only if the given match contains the condition + * for the layer4 protocol header corresponding to this instance. + */ + public abstract boolean verify(MatchBuilder builder); + + /** + * Ensure that the given {@link VTNLayer4Match} instance created from the + * MD-SAL match contains the same conditions as this instance. + * + * @param l4m A {@link VTNLayer4Match} instance created from the MD-SAL + * match. + * @throws Exception An errror occurred. + */ + public abstract void verifyMd(VTNLayer4Match l4m) throws Exception; + + /** + * Return a class for the type of this instance. + * + * @return A class for the type of this instance. + */ + protected abstract Class getMatchType(); + + // Layer4Header + + /** + * {@inheritDoc} + */ + @Override + public final void setDescription(StringBuilder builder) { + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public Layer4MatchParams clone() { + try { + return (Layer4MatchParams)super.clone(); + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed.", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4PortMatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4PortMatchParams.java new file mode 100644 index 00000000..bfbea38f --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/Layer4PortMatchParams.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.Layer4PortHeader; + +import org.opendaylight.vtn.manager.internal.XmlNode; + +/** + * {@code Layer4PortMatchParams} describes parameters for condition to match + * against layer 4 protocol which identifies the service using 16-bit port + * number. + * + * @param The type of this instance. + */ +public abstract class Layer4PortMatchParams + extends Layer4MatchParams implements Layer4PortHeader { + /** + * The range of source port numbers. + */ + private PortRangeParams sourcePort; + + /** + * The range of destination port numbers. + */ + private PortRangeParams destinationPort; + + /** + * Return the minimum value in the range of source port numbers. + * + * @return The minimum value in the range of source port numbers. + */ + public final Integer getSourcePortFrom() { + return getSourcePortRange().getPortFrom(); + } + + /** + * Set the minimum value in the range of source port number. + * + * @param port The minimum value in the range of source port numbers. + * @return This instance. + */ + public final T setSourcePortFrom(Integer port) { + getSourcePortRange().setPortFrom(port); + return getMatchType().cast(this); + } + + /** + * Return the maximum value in the range of source port numbers. + * + * @return The maximum value in the range of source port numbers. + */ + public final Integer getSourcePortTo() { + return getSourcePortRange().getPortTo(); + } + + /** + * Set the maximum value in the range of source port number. + * + * @param port The maximum value in the range of source port numbers. + * @return This instance. + */ + public final T setSourcePortTo(Integer port) { + getSourcePortRange().setPortTo(port); + return getMatchType().cast(this); + } + + /** + * Return the range of source port numbers. + * + * @return A {@link PortRangeParams} instance. + */ + public final PortRangeParams getSourcePortParams() { + return sourcePort; + } + + /** + * Set the range of source port numbers. + * + * @param range A {@link PortRangeParams} instance. + * @return This instance. + */ + public final T setSourcePortParams(PortRangeParams range) { + sourcePort = (range == null) ? null : range.clone(); + return getMatchType().cast(this); + } + + /** + * Return the minimum value in the range of destination port numbers. + * + * @return The minimum value in the range of destination port numbers. + */ + public final Integer getDestinationPortFrom() { + return getDestinationPortRange().getPortFrom(); + } + + /** + * Set the minimum value in the range of destination port number. + * + * @param port The minimum value in the range of destination port numbers. + * @return This instance. + */ + public final T setDestinationPortFrom(Integer port) { + getDestinationPortRange().setPortFrom(port); + return getMatchType().cast(this); + } + + /** + * Return the maximum value in the range of destination port numbers. + * + * @return The maximum value in the range of destination port numbers. + */ + public final Integer getDestinationPortTo() { + return getDestinationPortRange().getPortTo(); + } + + /** + * Set the maximum value in the range of destination port number. + * + * @param port The maximum value in the range of destination port numbers. + * @return This instance. + */ + public final T setDestinationPortTo(Integer port) { + getDestinationPortRange().setPortTo(port); + return getMatchType().cast(this); + } + + /** + * Return the range of destination port numbers. + * + * @return A {@link PortRangeParams} instance. + */ + public final PortRangeParams getDestinationPortParams() { + return destinationPort; + } + + /** + * Set the range of destination port numbers. + * + * @param range A {@link PortRangeParams} instance. + * @return This instance. + */ + public final T setDestinationPortParams(PortRangeParams range) { + destinationPort = (range == null) ? null : range.clone(); + return getMatchType().cast(this); + } + + /** + * Reset to the initial state. + * + * @return This instance. + */ + public final T reset() { + sourcePort = null; + destinationPort = null; + return getMatchType().cast(this); + } + + /** + * Prepare the range of source port numbers. + * + * @return A {@link PortRangeParams} instance. + */ + protected final PortRangeParams getSourcePortRange() { + PortRangeParams range = sourcePort; + if (range == null) { + range = new PortRangeParams(); + sourcePort = range; + } + return range; + } + + /** + * Prepare the range of destination port numbers. + * + * @return A {@link PortRangeParams} instance. + */ + protected final PortRangeParams getDestinationPortRange() { + PortRangeParams range = destinationPort; + if (range == null) { + range = new PortRangeParams(); + destinationPort = range; + } + return range; + } + + /** + * Return a {@link PortMatch} instance which represents the range of + * source port numbers. + * + * @return A {@link PortMatch} instance or {@code null}. + */ + public final PortMatch getSourcePortMatch() { + PortRangeParams range = sourcePort; + return (range == null) ? null : range.toPortMatch(); + } + + /** + * Return a {@link PortMatch} instance which represents the range of + * destination port numbers. + * + * @return A {@link PortMatch} instance or {@code null}. + */ + public final PortMatch getDestinationPortMatch() { + PortRangeParams range = destinationPort; + return (range == null) ? null : range.toPortMatch(); + } + + // Layer4MatchParams + + /** + * {@inheritDoc} + */ + @Override + public final XmlNode toXmlNode(String name) { + XmlNode root = new XmlNode(name); + if (sourcePort != null) { + root.add(sourcePort.toXmlNode("source-port")); + } + if (destinationPort != null) { + root.add(destinationPort.toXmlNode("destination-port")); + } + + return root; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isEmpty() { + return (sourcePort == null && destinationPort == null); + } + + // Layer4PortHeader + + /** + * {@inheritDoc} + */ + @Override + public final int getSourcePort() { + return getSourcePortRange().getPortFrom().intValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public final void setSourcePort(int port) { + getSourcePortRange().setPortFrom(port); + } + + /** + * {@inheritDoc} + */ + @Override + public final int getDestinationPort() { + return getDestinationPortRange().getPortFrom().intValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public final void setDestinationPort(int port) { + getDestinationPortRange().setPortFrom(port); + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public Layer4PortMatchParams clone() { + Layer4PortMatchParams params = (Layer4PortMatchParams)super.clone(); + PortRangeParams range = sourcePort; + if (range != null) { + params.sourcePort = range.clone(); + } + + range = destinationPort; + if (range != null) { + params.destinationPort = range.clone(); + } + + return params; + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/MatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/MatchParams.java new file mode 100644 index 00000000..01c9c9cc --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/MatchParams.java @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.HashMap; +import java.util.Map; + +import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.flow.cond.InetMatch; +import org.opendaylight.vtn.manager.flow.cond.L4Match; +import org.opendaylight.vtn.manager.util.IpNetwork; + +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.packet.PacketHeader; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.controller.sal.utils.EtherTypes; +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; + +/** + * {@code MatchParams} describes parameters for conditions to match against + * packets. + */ +public class MatchParams extends TestBase implements PacketHeader, Cloneable { + /** + * An {@link EtherMatchParams} instance. + */ + private EtherMatchParams etherParams; + + /** + * An {@link Inet4MatchParams} instance. + */ + private Inet4MatchParams inet4Params; + + /** + * An {@link Layer4MatchParams} instance. + */ + private Layer4MatchParams layer4Params; + + /** + * Create a map that contains {@link MatchParams} instances for test. + * + *

+ * An instance of {@link MatchParams} to be used to construct + * {@link VTNMatch} instance is set as a key, and an instance of + * {@link MatchParams} instances that contains conditions expected to + * be configured in {@link VTNMatch} is set as a value. + *

+ * + * @return A map that contains {@link MatchParams} instances. + */ + public static Map createMatches() { + Map map = new HashMap<>(); + MatchParams params = new MatchParams(); + map.put(params, params); + + // Match to Ethernet header. + EtherMatchParams eparams = new EtherMatchParams(). + setSourceAddress(0x000102030405L). + setDestinationAddress(0xf0f1f2f3f4f5L). + setVlanId(Integer.valueOf(EtherHeader.VLAN_NONE)); + params = new MatchParams().setEtherParams(eparams); + map.put(params, params); + + eparams = new EtherMatchParams(). + setSourceAddress(0xa83401bf34ceL). + setDestinationAddress(0x00abcdef1234L). + setEtherType(Integer.valueOf(0x800)). + setVlanId(Integer.valueOf(4095)). + setVlanPriority(Short.valueOf((short)7)); + params = new MatchParams().setEtherParams(eparams); + map.put(params, params); + + // Match to IPv4 header. + Inet4MatchParams ip4params = new Inet4MatchParams(); + params = new MatchParams().setInet4Params(ip4params); + + // Ethernet type will be configured. + Integer ethIpv4 = Integer.valueOf(EtherTypes.IPv4.intValue()); + eparams = new EtherMatchParams().setEtherType(ethIpv4); + MatchParams expected = new MatchParams().setEtherParams(eparams); + map.put(params, expected); + + ip4params = new Inet4MatchParams().setDscp(Short.valueOf((short)41)); + params = new MatchParams().setInet4Params(ip4params); + expected = new MatchParams(). + setEtherParams(eparams).setInet4Params(ip4params); + map.put(params, expected); + + eparams = new EtherMatchParams(). + setSourceAddress(0x3873cad23847L). + setVlanId(Integer.valueOf(3)); + ip4params = new Inet4MatchParams(). + setSourceNetwork(IpNetwork.create("192.168.100.255")). + setSourcePrefix(Short.valueOf((short)25)). + setDestinationNetwork(IpNetwork.create("203.198.39.255")). + setDestinationPrefix(Short.valueOf((short)23)). + setProtocol(Short.valueOf((short)123)). + setDscp(Short.valueOf((short)45)); + params = new MatchParams(). + setEtherParams(eparams).setInet4Params(ip4params); + eparams = new EtherMatchParams(). + setSourceAddress(0x3873cad23847L). + setEtherType(ethIpv4). + setVlanId(Integer.valueOf(3)); + ip4params.setSourceNetwork(IpNetwork.create("192.168.100.255/25")). + setDestinationNetwork(IpNetwork.create("203.198.39.255/23")); + expected = new MatchParams(). + setEtherParams(eparams).setInet4Params(ip4params); + map.put(params, expected); + + // Match to TCP header. + TcpMatchParams tcpParams = new TcpMatchParams(); + params = new MatchParams().setLayer4Params(tcpParams); + + // Ethernet type and IP protocol will be configured. + Short tcpProto = Short.valueOf(IPProtocols.TCP.shortValue()); + eparams = new EtherMatchParams().setEtherType(ethIpv4); + ip4params = new Inet4MatchParams().setProtocol(tcpProto); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params); + map.put(params, expected); + + tcpParams = new TcpMatchParams(). + setSourcePortFrom(35).setDestinationPortFrom(987); + params = new MatchParams().setLayer4Params(tcpParams); + tcpParams = new TcpMatchParams(). + setSourcePortFrom(35).setSourcePortTo(35). + setDestinationPortFrom(987).setDestinationPortTo(987); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(tcpParams); + map.put(params, expected); + + eparams = new EtherMatchParams(). + setSourceAddress(0x043e1eb0e32cL). + setDestinationAddress(0xc8ff32f9e7feL). + setVlanId(Integer.valueOf(123)). + setVlanPriority(Short.valueOf((short)4)); + ip4params = new Inet4MatchParams(). + setSourceNetwork(IpNetwork.create("10.20.30.45")). + setDestinationNetwork(IpNetwork.create("192.168.90.100")). + setDscp(Short.valueOf((short)0)); + tcpParams = new TcpMatchParams(). + setSourcePortFrom(100).setSourcePortTo(101). + setDestinationPortFrom(30000).setDestinationPortTo(40000); + params = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(tcpParams); + eparams = new EtherMatchParams(). + setSourceAddress(0x043e1eb0e32cL). + setDestinationAddress(0xc8ff32f9e7feL). + setEtherType(ethIpv4). + setVlanId(Integer.valueOf(123)). + setVlanPriority(Short.valueOf((short)4)); + ip4params = new Inet4MatchParams(). + setSourceNetwork(IpNetwork.create("10.20.30.45")). + setDestinationNetwork(IpNetwork.create("192.168.90.100")). + setProtocol(tcpProto). + setDscp(Short.valueOf((short)0)); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(tcpParams); + map.put(params, expected); + + // Match to UDP header. + UdpMatchParams udpParams = new UdpMatchParams(); + params = new MatchParams().setLayer4Params(udpParams); + + // Ethernet type and IP protocol will be configured. + Short udpProto = Short.valueOf(IPProtocols.UDP.shortValue()); + eparams = new EtherMatchParams().setEtherType(ethIpv4); + ip4params = new Inet4MatchParams().setProtocol(udpProto); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params); + map.put(params, expected); + + udpParams = new UdpMatchParams(). + setSourcePortFrom(999).setDestinationPortFrom(64321); + params = new MatchParams().setLayer4Params(udpParams); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(udpParams); + map.put(params, expected); + + eparams = new EtherMatchParams(). + setSourceAddress(0xfc086b487935L). + setVlanId(Integer.valueOf(19)); + ip4params = new Inet4MatchParams(). + setDestinationNetwork(IpNetwork.create("123.234.56.78")); + udpParams = new UdpMatchParams(). + setSourcePortFrom(12345).setSourcePortTo(20000). + setDestinationPortFrom(50).setDestinationPortTo(60); + params = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(udpParams); + eparams = new EtherMatchParams(). + setSourceAddress(0xfc086b487935L). + setEtherType(ethIpv4). + setVlanId(Integer.valueOf(19)); + ip4params = new Inet4MatchParams(). + setDestinationNetwork(IpNetwork.create("123.234.56.78")). + setProtocol(udpProto); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(udpParams); + map.put(params, expected); + + // Match to ICMP header. + IcmpMatchParams icmpParams = new IcmpMatchParams(); + params = new MatchParams().setLayer4Params(icmpParams); + + // Ethernet type and IP protocol will be configured. + Short icmpProto = Short.valueOf(IPProtocols.ICMP.shortValue()); + eparams = new EtherMatchParams().setEtherType(ethIpv4); + ip4params = new Inet4MatchParams().setProtocol(icmpProto); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params); + map.put(params, expected); + + icmpParams = new IcmpMatchParams(). + setType(Short.valueOf((short)0)). + setCode(Short.valueOf((short)0)); + params = new MatchParams().setLayer4Params(icmpParams); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(icmpParams); + map.put(params, expected); + + eparams = new EtherMatchParams(). + setVlanId(Integer.valueOf(159)). + setVlanPriority(Short.valueOf((short)6)); + ip4params = new Inet4MatchParams(). + setSourceNetwork(IpNetwork.create("10.245.32.189")). + setSourcePrefix(Short.valueOf((short)28)). + setDestinationNetwork(IpNetwork.create("192.168.195.209")). + setDestinationPrefix(Short.valueOf((short)31)). + setDscp(Short.valueOf((short)49)); + icmpParams = new IcmpMatchParams(). + setType(Short.valueOf((short)123)). + setCode(Short.valueOf((short)91)); + params = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(icmpParams); + eparams = new EtherMatchParams(). + setEtherType(ethIpv4). + setVlanId(Integer.valueOf(159)). + setVlanPriority(Short.valueOf((short)6)); + ip4params = new Inet4MatchParams(). + setSourceNetwork(IpNetwork.create("10.245.32.189/28")). + setDestinationNetwork(IpNetwork.create("192.168.195.209/31")). + setProtocol(icmpProto). + setDscp(Short.valueOf((short)49)); + expected = new MatchParams().setEtherParams(eparams). + setInet4Params(ip4params).setLayer4Params(icmpParams); + map.put(params, expected); + + return map; + } + + /** + * Construct an empty instance. + */ + public MatchParams() { + } + + /** + * Copy constructor. + * + * @param params A {@link MatchParams} instance to be copied. + */ + public MatchParams(MatchParams params) { + setEtherParams(params.getEtherParams()); + setInet4Params(params.getInet4Params()); + setLayer4Params(params.getLayer4Params()); + } + + /** + * Return the parameters for Ethernet header. + * + * @return An {@link EtherMatchParams} instance. + */ + public final EtherMatchParams getEtherParams() { + return etherParams; + } + + /** + * Set the parameters for Ethernet header. + * + * @param params An {@link EtherMatchParams} instance. + * @return This instance. + */ + public final MatchParams setEtherParams(EtherMatchParams params) { + etherParams = (params == null) ? null : params.clone(); + return this; + } + + /** + * Return the parameters for IPv4 header. + * + * @return An {@link Inet4MatchParams} instance. + */ + public final Inet4MatchParams getInet4Params() { + return inet4Params; + } + + /** + * Set the parameters for IPv4 header. + * + * @param params An {@link Inet4MatchParams} instance. + * @return This instance. + */ + public final MatchParams setInet4Params(Inet4MatchParams params) { + inet4Params = (params == null) ? null : params.clone(); + return this; + } + + /** + * Return the parameters for layer 4 header. + * + * @return A {@link Layer4MatchParams} instance. + */ + public final Layer4MatchParams getLayer4Params() { + return layer4Params; + } + + /** + * Set the parameters for layer 4 header. + * + * @param params A {@link Layer4MatchParams} instance. + * @return This instance. + */ + public final MatchParams setLayer4Params(Layer4MatchParams params) { + layer4Params = (params == null) ? null : params.clone(); + return this; + } + + /** + * Return an {@link EthernetMatch} instance. + * + * @return An {@link EthernetMatch} instance. + */ + public final EthernetMatch getEthernetMatch() { + return (etherParams == null) ? null : etherParams.toEthernetMatch(); + } + + /** + * Return an {@link InetMatch} instance. + * + * @return An {@link InetMatch} instance. + */ + public final InetMatch getInetMatch() { + return (inet4Params == null) ? null : inet4Params.toInet4Match(); + } + + /** + * Return an {@link L4Match} instance. + * + * @return An {@link L4Match} instance. + */ + public final L4Match getL4Match() { + return (layer4Params == null) ? null : layer4Params.toL4Match(); + } + + /** + * Return a {@link VtnEtherMatch} instance. + * + * @return A {@link VtnEtherMatch} instance. + */ + public final VtnEtherMatch getVtnEtherMatch() { + return (etherParams == null) ? null : etherParams.toVtnEtherMatch(); + } + + /** + * Return a {@link VtnInetMatch} instance. + * + * @return A {@link VtnInetMatch} instance. + */ + public final VtnInetMatch getVtnInetMatch() { + return (inet4Params == null) ? null : inet4Params.toVtnInetMatch(); + } + + /** + * Return a {@link VtnLayer4Match} instance. + * + * @return A {@link VtnLayer4Match} instance. + */ + public final VtnLayer4Match getVtnLayer4Match() { + return (layer4Params == null) ? null : layer4Params.toVtnLayer4Match(); + } + + /** + * Reset to the initial state. + * + * @return This instance. + */ + public MatchParams reset() { + etherParams = null; + inet4Params = null; + layer4Params = null; + return this; + } + + /** + * Construct a new {@link FlowMatch} instance. + * + * @return A {@link FlowMatch} instance. + */ + public FlowMatch toFlowMatch() { + return new FlowMatch(getEthernetMatch(), getInetMatch(), + getL4Match()); + } + + /** + * Create a {@link VtnFlowMatchBuilder} instance that contains the settings + * configured in this instance. + * + * @return A {@link VtnFlowMatchBuilder} instance. + */ + public VtnFlowMatchBuilder toVtnFlowMatchBuilder() { + return new VtnFlowMatchBuilder(). + setVtnEtherMatch(getVtnEtherMatch()). + setVtnInetMatch(getVtnInetMatch()). + setVtnLayer4Match(getVtnLayer4Match()); + } + + /** + * Construct a new {@link VTNMatch} instance. + * + * @return A {@link VTNMatch} instance. + * @throws Exception An error occurred. + */ + public final VTNMatch toVTNMatch() throws Exception { + VTNMatch vmatch = new VTNMatch(); + vmatch.set(toFlowMatch()); + return vmatch; + } + + /** + * Return a {@link XmlNode} instance which represents this instance. + * + * @param name The name of the root node. + * @return A {@link XmlNode} instance. + */ + public XmlNode toXmlNode(String name) { + XmlNode root = new XmlNode(name); + if (etherParams != null) { + root.add(etherParams.toXmlNode("vtn-ether-match")); + } + + if (inet4Params != null) { + root.add(inet4Params.toXmlNode("vtn-inet4-match")); + } + + if (layer4Params != null) { + root.add(layer4Params.toXmlNode()); + } + + return root; + } + + /** + * Ensure that the given {@link VTNMatch} instance contains the same + * conditions as this instance. + * + * @param vmatch A {@link VTNMatch} instance. + * @throws Exception An error occurred. + */ + public void verify(VTNMatch vmatch) throws Exception { + FlowMatch fm = vmatch.toFlowMatch(); + assertEquals(toFlowMatch(), fm); + + VTNEtherMatch vether = vmatch.getEtherMatch(); + MatchBuilder mb = vmatch.toMatchBuilder(); + if (vether == null) { + if (etherParams != null) { + assertEquals(true, etherParams.isEmpty()); + } + assertEquals(null, mb.getEthernetMatch()); + assertEquals(null, mb.getVlanMatch()); + } else { + etherParams.verifyValues(vether); + etherParams.verify(mb); + } + + VTNInetMatch vinet = vmatch.getInetMatch(); + if (vinet == null) { + if (inet4Params != null) { + assertEquals(true, inet4Params.isEmpty()); + } + assertEquals(null, mb.getIpMatch()); + assertEquals(null, mb.getLayer3Match()); + } else { + assertTrue(vinet instanceof VTNInet4Match); + inet4Params.verifyValues((VTNInet4Match)vinet); + inet4Params.verify(mb); + } + + VTNLayer4Match vl4 = vmatch.getLayer4Match(); + if (vl4 == null) { + if (layer4Params != null) { + assertEquals(true, layer4Params.isEmpty()); + } + assertEquals(null, mb.getIcmpv4Match()); + assertEquals(null, mb.getLayer4Match()); + } else { + layer4Params.verifyValues(vl4); + layer4Params.verify(mb); + } + + assertEquals(null, mb.getInPort()); + assertEquals(null, mb.getInPhyPort()); + assertEquals(null, mb.getMetadata()); + assertEquals(null, mb.getTunnel()); + assertEquals(null, mb.getIcmpv6Match()); + assertEquals(null, mb.getProtocolMatchFields()); + assertEquals(null, mb.getTcpFlagMatch()); + + VTNMatch vmatch1 = new VTNMatch(mb.build()); + vether = vmatch1.getEtherMatch(); + vinet = vmatch1.getInetMatch(); + vl4 = vmatch1.getLayer4Match(); + + if (vether == null) { + assertEquals(null, etherParams); + } else { + etherParams.verifyValues(vether); + } + + if (vinet != null) { + assertTrue(vinet instanceof VTNInet4Match); + inet4Params.verifyValues((VTNInet4Match)vinet); + } else if (inet4Params != null) { + assertEquals(true, inet4Params.isEmpty()); + } + + if (vl4 != null) { + layer4Params.verifyMd(vl4); + } else if (layer4Params != null) { + assertEquals(true, layer4Params.isEmpty()); + } + } + + // PacketHeader + + /** + * {@inheritDoc} + */ + @Override + public final EtherHeader getEtherHeader() { + return etherParams; + } + + /** + * {@inheritDoc} + */ + @Override + public final InetHeader getInetHeader() { + return inet4Params; + } + + /** + * {@inheritDoc} + */ + @Override + public final Layer4Header getLayer4Header() { + return layer4Params; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getHeaderDescription() { + return ""; + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public MatchParams clone() { + try { + MatchParams params = (MatchParams)super.clone(); + if (etherParams != null) { + params.etherParams = etherParams.clone(); + } + if (inet4Params != null) { + params.inet4Params = inet4Params.clone(); + } + if (layer4Params != null) { + params.layer4Params = layer4Params.clone(); + } + + return params; + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed.", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/PortRangeParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/PortRangeParams.java new file mode 100644 index 00000000..513b5136 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/PortRangeParams.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; + +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpDestinationRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpDestinationRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpSourceRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpSourceRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpDestinationRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpDestinationRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpSourceRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpSourceRangeBuilder; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; + +/** + * {@code PortRangeParams} describes parameters for conditions which specifies + * the range of transport port numbers. + */ +public final class PortRangeParams implements Cloneable { + /** + * The minimum value in the range of port numbers. + */ + private Integer portFrom; + + /** + * The maximum value in the range of port numbers. + */ + private Integer portTo; + + /** + * Construct a new instance. + */ + public PortRangeParams() { + } + + /** + * Construct a new instance. + * + * @param from The minimum value in the range of port numbers. + */ + public PortRangeParams(Integer from) { + portFrom = from; + } + + /** + * Construct a new instance. + * + * @param from The minimum value in the range of port numbers. + * @param to The maximum value in the range of port numbers. + */ + public PortRangeParams(Integer from, Integer to) { + portFrom = from; + portTo = to; + } + + /** + * Return a {@link PortNumber} instance which contains the given port + * number. + * + * @param port A port number. + * @return A {@link PortNumber} instance or {@code null}. + */ + private static PortNumber getPortNumber(Integer port) { + return (port == null) ? null : new PortNumber(port); + } + + /** + * Return the minimum value in the range of the port numbers. + * + * @return The minimum value in the range of the port numbers. + */ + public Integer getPortFrom() { + return portFrom; + } + + /** + * Set the minimum value in the range of the port numbers. + * + * @param port The minimum value in the range of the port numbers. + * @return This instance. + */ + public PortRangeParams setPortFrom(Integer port) { + portFrom = port; + return this; + } + + /** + * Return the maximum value in the range of the port numbers. + * + * @return The maximum value in the range of the port numbers. + */ + public Integer getPortTo() { + return portTo; + } + + /** + * Set the maximum value in the range of the port numbers. + * + * @param port The maximum value in the range of the port numbers. + * @return This instance. + */ + public PortRangeParams setPortTo(Integer port) { + portTo = port; + return this; + } + + /** + * Reset to the initial state. + * + * @return This instance. + */ + public PortRangeParams reset() { + portFrom = null; + portTo = null; + return this; + } + + /** + * Construct a new {@link PortMatch} instance. + * + * @return A {@link PortMatch} instance. + */ + public PortMatch toPortMatch() { + return new PortMatch(portFrom, portTo); + } + + /** + * Construct a new {@link TcpSourceRange} instance. + * + * @return A {@link TcpSourceRange} instance. + */ + public TcpSourceRange toTcpSourceRange() { + return new TcpSourceRangeBuilder(). + setPortFrom(getPortNumber(portFrom)). + setPortTo(getPortNumber(portTo)).build(); + } + + /** + * Construct a new {@link TcpDestinationRange} instance. + * + * @return A {@link TcpDestinationRange} instance. + */ + public TcpDestinationRange toTcpDestinationRange() { + return new TcpDestinationRangeBuilder(). + setPortFrom(getPortNumber(portFrom)). + setPortTo(getPortNumber(portTo)).build(); + } + + /** + * Construct a new {@link UdpSourceRange} instance. + * + * @return A {@link UdpSourceRange} instance. + */ + public UdpSourceRange toUdpSourceRange() { + return new UdpSourceRangeBuilder(). + setPortFrom(getPortNumber(portFrom)). + setPortTo(getPortNumber(portTo)).build(); + } + + /** + * Construct a new {@link UdpDestinationRange} instance. + * + * @return A {@link UdpDestinationRange} instance. + */ + public UdpDestinationRange toUdpDestinationRange() { + return new UdpDestinationRangeBuilder(). + setPortFrom(getPortNumber(portFrom)). + setPortTo(getPortNumber(portTo)).build(); + } + + /** + * Return a {@link XmlNode} instance to be mapped to a {@link VTNPortRange} + * instance. + * + * @param name The name of the root node. + * @return A {@link XmlNode} instance. + */ + public XmlNode toXmlNode(String name) { + XmlNode root = new XmlNode(name); + if (portFrom != null) { + root.add(new XmlNode("port-from", portFrom)); + } + if (portTo != null) { + root.add(new XmlNode("port-to", portTo)); + } + + return root; + } + + // Cloneable + + /** + * Return a shallow copy of this instance. + * + * @return A shallow copy of this instance. + */ + @Override + public PortRangeParams clone() { + try { + return (PortRangeParams)super.clone(); + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed.", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TcpMatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TcpMatchParams.java new file mode 100644 index 00000000..b9237363 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TcpMatchParams.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.TcpHeader; + +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnTcpMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnTcpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpDestinationRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.tcp.match.fields.TcpSourceRange; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code TcpMatchParams} describes parameters for conditions to match against + * TCP header. + */ +public final class TcpMatchParams extends Layer4PortMatchParams + implements TcpHeader { + // Layer4MatchParams + + /** + * {@inheritDoc} + */ + @Override + public org.opendaylight.vtn.manager.flow.cond.TcpMatch toL4Match() { + return new org.opendaylight.vtn.manager.flow.cond.TcpMatch( + getSourcePortMatch(), getDestinationPortMatch()); + } + + /** + * {@inheritDoc} + */ + @Override + public VtnTcpMatch toVtnLayer4Match() { + PortRangeParams r = getSourcePortParams(); + TcpSourceRange src = (r == null) ? null : r.toTcpSourceRange(); + r = getDestinationPortParams(); + TcpDestinationRange dst = (r == null) + ? null : r.toTcpDestinationRange(); + + return new VtnTcpMatchBuilder().setTcpSourceRange(src). + setTcpDestinationRange(dst).build(); + } + + /** + * {@inheritDoc} + */ + @Override + public VTNTcpMatch toVTNLayer4Match() throws Exception { + return new VTNTcpMatch(toL4Match()); + } + + /** + * {@inheritDoc} + */ + @Override + public XmlNode toXmlNode() { + return toXmlNode("vtn-tcp-match"); + } + + /** + * {@inheritDoc} + */ + @Override + public VTNTcpMatch verifyValues(VTNLayer4Match l4m) { + assertTrue(l4m instanceof VTNTcpMatch); + VTNTcpMatch tmatch = (VTNTcpMatch)l4m; + PortRangeParams src = getSourcePortParams(); + PortRangeParams dst = getDestinationPortParams(); + VTNPortRange srcRange = tmatch.getSourcePort(); + VTNPortRange dstRange = tmatch.getDestinationPort(); + + if (src == null) { + assertEquals(null, srcRange); + } else { + Integer from = src.getPortFrom(); + Integer to = src.getPortTo(); + if (to == null) { + to = from; + } + assertEquals(from, srcRange.getPortFrom()); + assertEquals(to, srcRange.getPortTo()); + } + + if (dst == null) { + assertEquals(null, dstRange); + } else { + Integer from = dst.getPortFrom(); + Integer to = dst.getPortTo(); + if (to == null) { + to = from; + } + assertEquals(from, dstRange.getPortFrom()); + assertEquals(to, dstRange.getPortTo()); + } + + assertEquals(isEmpty(), tmatch.isEmpty()); + + return tmatch; + } + + /** + * {@inheritDoc} + */ + @Override + public void verify(VTNLayer4Match l4m) throws Exception { + assertTrue(l4m instanceof VTNTcpMatch); + VTNTcpMatch tmatch = (VTNTcpMatch)l4m; + PortMatch srcMatch = getSourcePortMatch(); + PortMatch dstMatch = getDestinationPortMatch(); + VTNPortRange src = VTNPortRange.create(srcMatch); + VTNPortRange dst = VTNPortRange.create(dstMatch); + assertEquals(src, tmatch.getSourcePort()); + assertEquals(dst, tmatch.getDestinationPort()); + assertEquals(IPProtocols.TCP.shortValue(), + tmatch.getInetProtocol(IpVersion.Ipv4)); + assertEquals(IPProtocols.TCP.shortValue(), + tmatch.getInetProtocol(IpVersion.Ipv6)); + assertEquals(TcpHeader.class, tmatch.getHeaderType()); + assertEquals(FlowMatchType.TCP_SRC, tmatch.getSourceMatchType()); + assertEquals(FlowMatchType.TCP_DST, tmatch.getDestinationMatchType()); + + org.opendaylight.vtn.manager.flow.cond.TcpMatch tm = + tmatch.toL4Match(); + assertEquals(srcMatch, tm.getSourcePort()); + assertEquals(dstMatch, tm.getDestinationPort()); + + VtnFlowMatchBuilder vfmb = new VtnFlowMatchBuilder(); + tmatch.setVtnMatch(vfmb); + VtnLayer4Match vl4 = vfmb.getVtnLayer4Match(); + if (vl4 == null) { + assertEquals(null, srcMatch); + assertEquals(null, dstMatch); + assertEquals(null, VTNLayer4Match.create(vl4)); + } else { + assertTrue(vl4 instanceof VtnTcpMatch); + VtnTcpMatch vtm = (VtnTcpMatch)vl4; + TcpSourceRange vsrc = vtm.getTcpSourceRange(); + if (srcMatch == null) { + assertEquals(null, vsrc); + } else { + assertEquals(srcMatch.getPortFrom(), + vsrc.getPortFrom().getValue()); + assertEquals(srcMatch.getPortTo(), + vsrc.getPortTo().getValue()); + } + TcpDestinationRange vdst = vtm.getTcpDestinationRange(); + if (dstMatch == null) { + assertEquals(null, vdst); + } else { + assertEquals(dstMatch.getPortFrom(), + vdst.getPortFrom().getValue()); + assertEquals(dstMatch.getPortTo(), + vdst.getPortTo().getValue()); + } + assertEquals(tmatch, VTNLayer4Match.create(vl4)); + } + + MatchBuilder mb = new MatchBuilder(); + tmatch.setMatch(mb, IpVersion.Ipv4); + boolean hasValue = verify(mb); + + VTNLayer4Match l4 = VTNLayer4Match.create(mb.build()); + if (hasValue) { + assertTrue(l4 instanceof VTNTcpMatch); + VTNTcpMatch tmatch1 = (VTNTcpMatch)l4; + + // MD-SAL port match cannot represent the range of port numbers. + src = tmatch1.getSourcePort(); + if (srcMatch == null) { + assertEquals(null, src); + } else { + Integer from = srcMatch.getPortFrom(); + assertEquals(from, src.getPortFrom()); + assertEquals(from, src.getPortTo()); + } + + dst = tmatch1.getDestinationPort(); + if (dstMatch == null) { + assertEquals(null, dst); + } else { + Integer from = dstMatch.getPortFrom(); + assertEquals(from, dst.getPortFrom()); + assertEquals(from, dst.getPortTo()); + } + } else { + assertEquals(null, l4); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean verify(MatchBuilder builder) { + Layer4Match l4 = builder.getLayer4Match(); + PortRangeParams src = getSourcePortParams(); + PortRangeParams dst = getDestinationPortParams(); + if (l4 == null) { + assertEquals(null, src); + assertEquals(null, dst); + return false; + } + + assertTrue(l4 instanceof TcpMatch); + TcpMatch tm = (TcpMatch)l4; + boolean hasValue = false; + if (src == null) { + assertEquals(null, tm.getTcpSourcePort()); + } else { + assertEquals(src.getPortFrom(), tm.getTcpSourcePort().getValue()); + hasValue = true; + } + + if (dst == null) { + assertEquals(null, tm.getTcpDestinationPort()); + } else { + assertEquals(dst.getPortFrom(), + tm.getTcpDestinationPort().getValue()); + hasValue = true; + } + + assertTrue(hasValue); + return hasValue; + } + + /** + * {@inheritDoc} + */ + @Override + public void verifyMd(VTNLayer4Match l4m) throws Exception { + assertTrue(l4m instanceof VTNTcpMatch); + VTNTcpMatch tmatch = (VTNTcpMatch)l4m; + PortRangeParams src = getSourcePortParams(); + PortRangeParams dst = getDestinationPortParams(); + VTNPortRange srcRange = tmatch.getSourcePort(); + VTNPortRange dstRange = tmatch.getDestinationPort(); + if (src == null) { + assertEquals(null, srcRange); + } else { + Integer port = src.getPortFrom(); + assertEquals(port, srcRange.getPortFrom()); + assertEquals(port, srcRange.getPortTo()); + } + + if (dst == null) { + assertEquals(null, dstRange); + } else { + Integer port = dst.getPortFrom(); + assertEquals(port, dstRange.getPortFrom()); + assertEquals(port, dstRange.getPortTo()); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected Class getMatchType() { + return TcpMatchParams.class; + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public TcpMatchParams clone() { + return (TcpMatchParams)super.clone(); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TestMatchContext.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TestMatchContext.java new file mode 100644 index 00000000..947b3269 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/TestMatchContext.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.EnumSet; +import java.util.Set; + +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; + +import org.opendaylight.vtn.manager.internal.TestBase; + +/** + * {@code TestMatchContext} describes a {@code FlowMatchContext} only for + * test. + */ +public final class TestMatchContext extends TestBase + implements FlowMatchContext, Cloneable { + /** + * A set of {@link FlowMatchType} instances which represents match fields + * to be configured. + */ + private EnumSet matchFields = + EnumSet.noneOf(FlowMatchType.class); + + /** + * Ethernet header. + */ + private EtherHeader etherHeader; + + /** + * IP header. + */ + private InetHeader inetHeader; + + /** + * Layer 4 protocol header. + */ + private Layer4Header layer4Header; + + /** + * Set the Ethernet header. + * + * @param eth An {@link EtherHeader} instance. + * @return This instance. + */ + public TestMatchContext setEtherHeader(EtherHeader eth) { + etherHeader = eth; + return this; + } + + /** + * Set the IP header. + * + * @param ip An {@link InetHeader} instance. + * @return This instance. + */ + public TestMatchContext setInetHeader(InetHeader ip) { + inetHeader = ip; + return this; + } + + /** + * Set the layer 4 protocol header. + * + * @param l4 A {@link Layer4Header} instance. + * @return This instance. + */ + public TestMatchContext setLayer4Header(Layer4Header l4) { + layer4Header = l4; + return this; + } + + /** + * Ensure that only the given match fields are configured. + * + * @param types An array of {@link FlowMatchType} instances to be + * configured. + * @return This instance. + */ + public TestMatchContext checkMatchFields(FlowMatchType ... types) { + assertEquals(types.length, matchFields.size()); + for (FlowMatchType type: types) { + assertEquals(true, matchFields.contains(type)); + } + return this; + } + + /** + * Ensure that only the given match fields are configured. + * + * @param set A set of {@link FlowMatchType} instances to be configured. + * @return This instance. + */ + public TestMatchContext checkMatchFields(Set set) { + assertEquals(set, matchFields); + return this; + } + + /** + * Clear the match field. + * + * @return This instance. + */ + public TestMatchContext reset() { + matchFields.clear(); + return this; + } + + // PacketHeader + + /** + * {@inheritDoc} + */ + @Override + public EtherHeader getEtherHeader() { + return etherHeader; + } + + /** + * {@inheritDoc} + */ + @Override + public InetHeader getInetHeader() { + return inetHeader; + } + + /** + * {@inheritDoc} + */ + @Override + public Layer4Header getLayer4Header() { + return layer4Header; + } + + /** + * {@inheritDoc} + */ + @Override + public String getHeaderDescription() { + return ""; + } + + // FlowMatchContext + + /** + * {@inheritDoc} + */ + @Override + public void addMatchField(FlowMatchType type) { + matchFields.add(type); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasMatchField(FlowMatchType type) { + return matchFields.contains(type); + } + + /** + * {@inheritDoc} + */ + @Override + public void addUnicastMatchFields() { + FlowMatchType.addUnicastTypes(matchFields); + } + + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public TestMatchContext clone() { + try { + TestMatchContext ctx = (TestMatchContext)super.clone(); + ctx.matchFields = EnumSet.copyOf(matchFields); + return ctx; + } catch (CloneNotSupportedException e) { + // This should never happen. + throw new IllegalStateException("clone() failed.", e); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/UdpMatchParams.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/UdpMatchParams.java new file mode 100644 index 00000000..58d63279 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/UdpMatchParams.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.UdpHeader; + +import org.opendaylight.vtn.manager.internal.XmlNode; + +import org.opendaylight.controller.sal.utils.IPProtocols; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.flow.cond.config.VtnFlowMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnLayer4Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnUdpMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.vtn.layer4.match.VtnUdpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpDestinationRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.udp.match.fields.UdpSourceRange; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * {@code UdpMatchParams} describes parameters for conditions to match against + * UDP header. + */ +public final class UdpMatchParams extends Layer4PortMatchParams + implements UdpHeader { + // Layer4MatchParams + + /** + * {@inheritDoc} + */ + @Override + public org.opendaylight.vtn.manager.flow.cond.UdpMatch toL4Match() { + return new org.opendaylight.vtn.manager.flow.cond.UdpMatch( + getSourcePortMatch(), getDestinationPortMatch()); + } + + /** + * {@inheritDoc} + */ + @Override + public VtnUdpMatch toVtnLayer4Match() { + PortRangeParams r = getSourcePortParams(); + UdpSourceRange src = (r == null) ? null : r.toUdpSourceRange(); + r = getDestinationPortParams(); + UdpDestinationRange dst = (r == null) + ? null : r.toUdpDestinationRange(); + + return new VtnUdpMatchBuilder().setUdpSourceRange(src). + setUdpDestinationRange(dst).build(); + } + + /** + * {@inheritDoc} + */ + @Override + public VTNUdpMatch toVTNLayer4Match() throws Exception { + return new VTNUdpMatch(toL4Match()); + } + + /** + * {@inheritDoc} + */ + @Override + public XmlNode toXmlNode() { + return toXmlNode("vtn-udp-match"); + } + + /** + * {@inheritDoc} + */ + @Override + public VTNUdpMatch verifyValues(VTNLayer4Match l4m) { + assertTrue(l4m instanceof VTNUdpMatch); + VTNUdpMatch umatch = (VTNUdpMatch)l4m; + PortRangeParams src = getSourcePortParams(); + PortRangeParams dst = getDestinationPortParams(); + VTNPortRange srcRange = umatch.getSourcePort(); + VTNPortRange dstRange = umatch.getDestinationPort(); + + if (src == null) { + assertEquals(null, srcRange); + } else { + Integer from = src.getPortFrom(); + Integer to = src.getPortTo(); + if (to == null) { + to = from; + } + assertEquals(from, srcRange.getPortFrom()); + assertEquals(to, srcRange.getPortTo()); + } + + if (dst == null) { + assertEquals(null, dstRange); + } else { + Integer from = dst.getPortFrom(); + Integer to = dst.getPortTo(); + if (to == null) { + to = from; + } + assertEquals(from, dstRange.getPortFrom()); + assertEquals(to, dstRange.getPortTo()); + } + + assertEquals(isEmpty(), umatch.isEmpty()); + + return umatch; + } + + /** + * {@inheritDoc} + */ + @Override + public void verify(VTNLayer4Match l4m) throws Exception { + assertTrue(l4m instanceof VTNUdpMatch); + VTNUdpMatch umatch = (VTNUdpMatch)l4m; + PortMatch srcMatch = getSourcePortMatch(); + PortMatch dstMatch = getDestinationPortMatch(); + VTNPortRange src = VTNPortRange.create(srcMatch); + VTNPortRange dst = VTNPortRange.create(dstMatch); + assertEquals(src, umatch.getSourcePort()); + assertEquals(dst, umatch.getDestinationPort()); + assertEquals(IPProtocols.UDP.shortValue(), + umatch.getInetProtocol(IpVersion.Ipv4)); + assertEquals(IPProtocols.UDP.shortValue(), + umatch.getInetProtocol(IpVersion.Ipv6)); + assertEquals(UdpHeader.class, umatch.getHeaderType()); + assertEquals(FlowMatchType.UDP_SRC, umatch.getSourceMatchType()); + assertEquals(FlowMatchType.UDP_DST, umatch.getDestinationMatchType()); + + org.opendaylight.vtn.manager.flow.cond.UdpMatch um = + umatch.toL4Match(); + assertEquals(srcMatch, um.getSourcePort()); + assertEquals(dstMatch, um.getDestinationPort()); + + VtnFlowMatchBuilder vfmb = new VtnFlowMatchBuilder(); + umatch.setVtnMatch(vfmb); + VtnLayer4Match vl4 = vfmb.getVtnLayer4Match(); + if (vl4 == null) { + assertEquals(null, srcMatch); + assertEquals(null, dstMatch); + assertEquals(null, VTNLayer4Match.create(vl4)); + } else { + assertTrue(vl4 instanceof VtnUdpMatch); + VtnUdpMatch vum = (VtnUdpMatch)vl4; + UdpSourceRange vsrc = vum.getUdpSourceRange(); + if (srcMatch == null) { + assertEquals(null, vsrc); + } else { + assertEquals(srcMatch.getPortFrom(), + vsrc.getPortFrom().getValue()); + assertEquals(srcMatch.getPortTo(), + vsrc.getPortTo().getValue()); + } + UdpDestinationRange vdst = vum.getUdpDestinationRange(); + if (dstMatch == null) { + assertEquals(null, vdst); + } else { + assertEquals(dstMatch.getPortFrom(), + vdst.getPortFrom().getValue()); + assertEquals(dstMatch.getPortTo(), + vdst.getPortTo().getValue()); + } + assertEquals(umatch, VTNLayer4Match.create(vl4)); + } + + MatchBuilder mb = new MatchBuilder(); + umatch.setMatch(mb, IpVersion.Ipv4); + boolean hasValue = verify(mb); + + VTNLayer4Match l4 = VTNLayer4Match.create(mb.build()); + if (hasValue) { + assertTrue(l4 instanceof VTNUdpMatch); + VTNUdpMatch umatch1 = (VTNUdpMatch)l4; + + // MD-SAL port match cannot represent the range of port numbers. + src = umatch1.getSourcePort(); + if (srcMatch == null) { + assertEquals(null, src); + } else { + Integer from = srcMatch.getPortFrom(); + assertEquals(from, src.getPortFrom()); + assertEquals(from, src.getPortTo()); + } + + dst = umatch1.getDestinationPort(); + if (dstMatch == null) { + assertEquals(null, dst); + } else { + Integer from = dstMatch.getPortFrom(); + assertEquals(from, dst.getPortFrom()); + assertEquals(from, dst.getPortTo()); + } + } else { + assertEquals(null, l4); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean verify(MatchBuilder builder) { + Layer4Match l4 = builder.getLayer4Match(); + PortRangeParams src = getSourcePortParams(); + PortRangeParams dst = getDestinationPortParams(); + if (l4 == null) { + assertEquals(null, src); + assertEquals(null, dst); + return false; + } + + assertTrue(l4 instanceof UdpMatch); + UdpMatch um = (UdpMatch)l4; + boolean hasValue = false; + if (src == null) { + assertEquals(null, um.getUdpSourcePort()); + } else { + assertEquals(src.getPortFrom(), um.getUdpSourcePort().getValue()); + hasValue = true; + } + + if (dst == null) { + assertEquals(null, um.getUdpDestinationPort()); + } else { + assertEquals(dst.getPortFrom(), + um.getUdpDestinationPort().getValue()); + hasValue = true; + } + + assertTrue(hasValue); + return hasValue; + } + + /** + * {@inheritDoc} + */ + @Override + public void verifyMd(VTNLayer4Match l4m) throws Exception { + assertTrue(l4m instanceof VTNUdpMatch); + VTNUdpMatch umatch = (VTNUdpMatch)l4m; + PortRangeParams src = getSourcePortParams(); + PortRangeParams dst = getDestinationPortParams(); + VTNPortRange srcRange = umatch.getSourcePort(); + VTNPortRange dstRange = umatch.getDestinationPort(); + if (src == null) { + assertEquals(null, srcRange); + } else { + Integer port = src.getPortFrom(); + assertEquals(port, srcRange.getPortFrom()); + assertEquals(port, srcRange.getPortTo()); + } + + if (dst == null) { + assertEquals(null, dstRange); + } else { + Integer port = dst.getPortFrom(); + assertEquals(port, dstRange.getPortFrom()); + assertEquals(port, dstRange.getPortTo()); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected Class getMatchType() { + return UdpMatchParams.class; + } + + // Cloneable + + /** + * Return a deep copy of this instance. + * + * @return A deep copy of this instance. + */ + @Override + public UdpMatchParams clone() { + return (UdpMatchParams)super.clone(); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatchTest.java new file mode 100644 index 00000000..d5487c29 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNEtherMatchTest.java @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.EthernetMatch; +import org.opendaylight.vtn.manager.util.EtherAddress; + +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlDataType; +import org.opendaylight.vtn.manager.internal.XmlValueType; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnEtherMatchBuilder; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; + +/** + * JUnit test for {@link VTNEtherMatch}. + */ +public class VTNEtherMatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNEtherMatch} class. + */ + private static final String XML_ROOT = "vtn-ether-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNEtherMatch} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + ArrayList dlist = new ArrayList<>(); + Collections.addAll( + dlist, + new XmlValueType("source-address", + EtherAddress.class).add(name).prepend(parent), + new XmlValueType("destination-address", + EtherAddress.class).add(name).prepend(parent), + new XmlValueType("ether-type", + Integer.class).add(name).prepend(parent), + new XmlValueType("vlan-id", + Integer.class).add(name).prepend(parent), + new XmlValueType("vlan-pcp", + Integer.class).add(name).prepend(parent)); + return dlist; + } + + /** + * Test case for the following constructors. + * + *
    + *
  • {@link VTNEtherMatch#VTNEtherMatch()}
  • + *
  • {@link VTNEtherMatch#VTNEtherMatch(Integer)}
  • + *
  • {@link VTNEtherMatch#setEtherType(Integer)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor1() throws Exception { + VTNEtherMatch ematch = new VTNEtherMatch(); + assertEquals(null, ematch.getSourceAddress()); + assertEquals(null, ematch.getDestinationAddress()); + assertEquals(null, ematch.getEtherType()); + assertEquals(null, ematch.getVlanId()); + assertEquals(null, ematch.getVlanPriority()); + assertEquals(true, ematch.isEmpty()); + + int[] types = { + 0, 1, 0x800, 0x806, 0x86dd, + }; + for (int type: types) { + Integer etype = Integer.valueOf(type); + ematch = new VTNEtherMatch(etype); + assertEquals(null, ematch.getSourceAddress()); + assertEquals(null, ematch.getDestinationAddress()); + assertEquals(etype, ematch.getEtherType()); + assertEquals(null, ematch.getVlanId()); + assertEquals(null, ematch.getVlanPriority()); + assertEquals(false, ematch.isEmpty()); + + ematch = new VTNEtherMatch(); + assertEquals(null, ematch.getEtherType()); + ematch.setEtherType(etype); + assertEquals(etype, ematch.getEtherType()); + ematch.setEtherType(etype); + assertEquals(etype, ematch.getEtherType()); + for (int i = 1; i <= 10; i++) { + int t = type + i; + try { + ematch.setEtherType(t); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Ethernet type conflict: type=0x" + + Integer.toHexString(type) + ", expected=0x" + + Integer.toHexString(t); + assertEquals(msg, st.getDescription()); + } + } + } + } + + /** + * Test case for the following methods. + * + *
    + *
  • {@link VTNEtherMatch#VTNEtherMatch(EthernetMatch)}
  • + *
  • {@link VTNEtherMatch#create(Match)}
  • + *
  • {@link VTNEtherMatch#setMatch(MatchBuilder)}
  • + *
  • Getter methods.
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor2() throws Exception { + EtherAddress[] srcs = { + null, new EtherAddress(1L), new EtherAddress(0x000102030405L), + }; + EtherAddress[] dsts = { + null, new EtherAddress(0xf0f1f2f3f4f5L), + new EtherAddress(0xa8b9cadbecfdL), + }; + Integer[] types = {null, 0x800, 0x86dd}; + Integer[] vlans = {null, 0, 1, 4095}; + Short[] priorities = {0, 3, 7}; + + EtherMatchParams params = new EtherMatchParams(); + for (EtherAddress src: srcs) { + params.setSourceAddress(src); + for (EtherAddress dst: dsts) { + params.setDestinationAddress(dst); + for (Integer type: types) { + params.setEtherType(type); + for (Integer vlan: vlans) { + params.setVlanId(vlan).setVlanPriority((Short)null); + VTNEtherMatch ematch = params.toVTNEtherMatch(); + params.verify(ematch); + if (vlan == null || + vlan.intValue() == EtherHeader.VLAN_NONE) { + continue; + } + + for (Short pri: priorities) { + params.setVlanPriority(pri); + ematch = params.toVTNEtherMatch(); + params.verify(ematch); + } + } + } + } + } + + // Create broken EthernetMatch. + String[] badAddrs = { + "", "aa:bb:cc:dd:ee:ff:11", "00:11", "bad_address", + }; + Unmarshaller um = createUnmarshaller(EthernetMatch.class); + for (String addr: badAddrs) { + String xml = new XmlNode("ethermatch"). + setAttribute("src", addr).toString(); + EthernetMatch em = unmarshal(um, xml, EthernetMatch.class); + assertNotNull(em.getValidationStatus()); + try { + new VTNEtherMatch(em); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid source MAC address: " + addr, + st.getDescription()); + } + } + + // Invalid ether types. + Integer[] badTypes = { + Integer.MIN_VALUE, -10, -1, + 0x10000, 0x10001, 0x33333333, Integer.MAX_VALUE, + }; + for (Integer type: badTypes) { + params.setEtherType(type); + EthernetMatch em = params.toEthernetMatch(); + assertEquals(null, em.getValidationStatus()); + try { + new VTNEtherMatch(em); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid Ethernet type: " + type, + st.getDescription()); + } + } + + // Invalid VLAN ID. + params.setEtherType(0x800); + params.setVlanPriority((Short)null); + Short[] badVlanIds = { + Short.MIN_VALUE, -30000, -10000, -3, -2, -1, + 0x1000, 0x1001, 0x5000, Short.MAX_VALUE, + }; + for (Short vid: badVlanIds) { + params.setVlanId(vid); + EthernetMatch em = params.toEthernetMatch(); + assertEquals(null, em.getValidationStatus()); + try { + new VTNEtherMatch(em); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid VLAN ID: " + vid, + st.getDescription()); + } + } + + // Invalid VLAN priority. + params.setVlanId(1); + Byte[] badPcps = { + Byte.MIN_VALUE, -100, -50, -2, -1, + 8, 9, 10, 50, 100, Byte.MAX_VALUE, + }; + for (Byte pcp: badPcps) { + params.setVlanPriority(pcp); + EthernetMatch em = params.toEthernetMatch(); + assertEquals(null, em.getValidationStatus()); + try { + new VTNEtherMatch(em); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid VLAN priority: " + pcp, + st.getDescription()); + } + } + + // Specifying VLAN priority without VLAN ID. + Integer[] untagged = {null, EtherHeader.VLAN_NONE}; + for (Integer vid: untagged) { + params.setVlanId(vid); + for (byte pcp = 0; pcp <= 7; pcp++) { + params.setVlanPriority(pcp); + EthernetMatch em = params.toEthernetMatch(); + assertEquals(null, em.getValidationStatus()); + try { + new VTNEtherMatch(em); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("VLAN priority requires a valid VLAN ID.", + st.getDescription()); + } + } + } + + Match empty = new MatchBuilder().build(); + assertEquals(null, VTNEtherMatch.create(empty)); + } + + /** + * Test case for the following methods. + * + *
    + *
  • {@link VTNEtherMatch#VTNEtherMatch(org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnEtherMatchFields)}
  • + *
  • {@link VTNEtherMatch#create(Match)}
  • + *
  • {@link VTNEtherMatch#setMatch(MatchBuilder)}
  • + *
  • Getter methods.
  • + *
  • JAXB bindings.
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor3() throws Exception { + EtherAddress[] srcs = { + null, new EtherAddress(1L), new EtherAddress(0x000102030405L), + }; + EtherAddress[] dsts = { + null, new EtherAddress(0xf0f1f2f3f4f5L), + new EtherAddress(0xa8b9cadbecfdL), + }; + Integer[] types = {null, 0x800, 0x86dd}; + Integer[] vlans = {null, 0, 1, 4095}; + Short[] priorities = {0, 3, 7}; + + EtherMatchParams params = new EtherMatchParams(); + Class mtype = VTNEtherMatch.class; + for (EtherAddress src: srcs) { + params.setSourceAddress(src); + for (EtherAddress dst: dsts) { + params.setDestinationAddress(dst); + for (Integer type: types) { + params.setEtherType(type); + for (Integer vlan: vlans) { + params.setVlanId(vlan).setVlanPriority((Short)null); + VtnEtherMatch vem = params.toVtnEtherMatch(); + VTNEtherMatch ematch = new VTNEtherMatch(vem); + params.verify(ematch); + + // JAXB test. + VTNEtherMatch jaxb = jaxbTest(ematch, mtype, XML_ROOT); + jaxb.verify(); + VtnEtherMatch vem1 = + jaxb.toVtnEtherMatchBuilder().build(); + assertEquals(vem, vem1); + + if (vlan == null || + vlan.intValue() == EtherHeader.VLAN_NONE) { + continue; + } + + for (Short pri: priorities) { + params.setVlanPriority(pri); + vem = params.toVtnEtherMatch(); + ematch = new VTNEtherMatch(vem); + params.verify(ematch); + + // JAXB test. + jaxb = jaxbTest(ematch, mtype, XML_ROOT); + jaxb.verify(); + vem1 = jaxb.toVtnEtherMatchBuilder().build(); + assertEquals(vem, vem1); + } + } + } + } + } + + // Invalid ether types. + Long[] badTypes = { + 0x10000L, 0x10001L, 0x20000L, 0x7fffffffL, 0x80000000L, + 0xaaaaaaaaL, 0xccccccccL, 0xffff0000L, 0xffffffffL, + }; + for (Long type: badTypes) { + VtnEtherMatch vem = new VtnEtherMatchBuilder(). + setEtherType(new EtherType(type)).build(); + try { + new VTNEtherMatch(vem); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid Ethernet type: " + type, + st.getDescription()); + } + } + + // Specifying VLAN priority without VLAN ID. + Integer[] untagged = {null, EtherHeader.VLAN_NONE}; + for (Integer vid: untagged) { + params.setVlanId(vid); + for (byte pcp = 0; pcp <= 7; pcp++) { + params.setVlanPriority(pcp); + VtnEtherMatch vem = params.toVtnEtherMatch(); + try { + new VTNEtherMatch(vem); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("VLAN priority requires a valid VLAN ID.", + st.getDescription()); + } + } + } + } + + /** + * Test case for {@link VTNEtherMatch#verify()}. + * + * @throws Exception An error occurred. + */ + @Test + public void testVerify() throws Exception { + Unmarshaller um = createUnmarshaller(VTNEtherMatch.class); + + // Invalid ether types. + Integer[] badTypes = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x10000, -0xffff, -10, -3, -2, -1, + 0x10000, 0x10001, 0x20000, 0x10000000, 0x50000000, + Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + for (Integer type: badTypes) { + XmlNode root = new XmlNode(XML_ROOT). + add(new XmlNode("ether-type", type)); + String xml = root.toString(); + VTNEtherMatch ematch = unmarshal(um, xml, VTNEtherMatch.class); + try { + ematch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid Ethernet type: " + type, + st.getDescription()); + } + } + + // Invalid VLAN ID. + Integer[] badVlanIds = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x10000, -0xffff, -10, -3, -2, -1, + 0x1000, 0x1001, 0x1002, 0x20000, 0xffffff, 0x60000000, + Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + for (Integer vid: badVlanIds) { + XmlNode root = new XmlNode(XML_ROOT). + add(new XmlNode("vlan-id", vid)); + String xml = root.toString(); + VTNEtherMatch ematch = unmarshal(um, xml, VTNEtherMatch.class); + try { + ematch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid VLAN ID: " + vid, + st.getDescription()); + } + } + + // Invalid VLAN priority. + Short[] badPcps = { + Short.MIN_VALUE, -30000, -20000, -10000, -0x100, -3, -2, -1, + 8, 9, 10, 0x100, 300, 10000, Short.MAX_VALUE - 1, Short.MAX_VALUE, + }; + for (Short pcp: badPcps) { + XmlNode root = new XmlNode(XML_ROOT). + add(new XmlNode("vlan-pcp", pcp)); + String xml = root.toString(); + VTNEtherMatch ematch = unmarshal(um, xml, VTNEtherMatch.class); + try { + ematch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid VLAN priority: " + pcp, + st.getDescription()); + } + } + + // Specifying VLAN priority without VLAN ID. + Integer[] untagged = {null, EtherHeader.VLAN_NONE}; + for (Integer vid: untagged) { + for (byte pcp = 0; pcp <= 7; pcp++) { + XmlNode root = new XmlNode(XML_ROOT). + add(new XmlNode("vlan-pcp", pcp)); + if (vid != null) { + root.add(new XmlNode("vlan-id", vid)); + } + String xml = root.toString(); + VTNEtherMatch ematch = unmarshal(um, xml, VTNEtherMatch.class); + try { + ematch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("VLAN priority requires a valid VLAN ID.", + st.getDescription()); + } + } + } + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNEtherMatch#equals(Object)}
  • + *
  • {@link VTNEtherMatch#hashCode()}
  • + *
  • {@link VTNEtherMatch#setConditionKey(StringBuilder)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + EtherAddress[] srcs = { + null, new EtherAddress(1L), new EtherAddress(0x000102030405L), + }; + EtherAddress[] dsts = { + null, new EtherAddress(0xf0f1f2f3f4f5L), + new EtherAddress(0xa8b9cadbecfdL), + }; + Integer[] types = {null, 0x800, 0x86dd}; + Integer[] vlans = {null, 0, 1, 4095}; + Short[] priorities = {0, 3, 7}; + + int count = 0; + StringBuilder b = new StringBuilder(); + EtherMatchParams params = new EtherMatchParams(); + for (EtherAddress src: srcs) { + params.setSourceAddress(src); + for (EtherAddress dst: dsts) { + params.setDestinationAddress(dst); + for (Integer type: types) { + params.setEtherType(type); + for (Integer vlan: vlans) { + params.setVlanId(vlan).setVlanPriority((Short)null); + VTNEtherMatch ematch1 = params.toVTNEtherMatch(); + VTNEtherMatch ematch2 = params.toVTNEtherMatch(); + testEquals(set, ematch1, ematch2); + count++; + + b.setLength(0); + ematch1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + ematch2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + + if (vlan == null || + vlan.intValue() == EtherHeader.VLAN_NONE) { + continue; + } + + for (Short pri: priorities) { + params.setVlanPriority(pri); + ematch1 = params.toVTNEtherMatch(); + ematch2 = params.toVTNEtherMatch(); + testEquals(set, ematch1, ematch2); + count++; + + b.setLength(0); + ematch1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + ematch2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + } + } + } + } + } + + assertEquals(count, set.size()); + assertEquals(count, keySet.size()); + } + + /** + * Ensure that {@link VTNEtherMatch} is mapped to XML root element. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + Unmarshaller um = createUnmarshaller(VTNEtherMatch.class); + EtherMatchParams params = new EtherMatchParams(); + + // Empty match. + String xml = new XmlNode(XML_ROOT).toString(); + VTNEtherMatch ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + // Specifying all fields. + EtherAddress src = new EtherAddress(0x001122334455L); + EtherAddress dst = new EtherAddress(0x0abcdef12345L); + Integer etype = Integer.valueOf(0x806); + Integer vid = Integer.valueOf(4095); + Short pcp = Short.valueOf((short)7); + params.setSourceAddress(src); + params.setDestinationAddress(dst); + params.setEtherType(etype); + params.setVlanId(vid); + params.setVlanPriority(pcp); + + final String tagSrc = "source-address"; + final String tagDst = "destination-address"; + final String tagType = "ether-type"; + final String tagVid = "vlan-id"; + final String tagPcp = "vlan-pcp"; + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagSrc, src.getText())). + add(new XmlNode(tagDst, dst.getText())). + add(new XmlNode(tagType, etype)). + add(new XmlNode(tagVid, vid)). + add(new XmlNode(tagPcp, pcp)).toString(); + ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + // Specifying single field. + params.reset().setSourceAddress(src); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagSrc, src.getText())).toString(); + ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + params.reset().setDestinationAddress(dst); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagDst, dst.getText())).toString(); + ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + params.reset().setEtherType(etype); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagType, etype)).toString(); + ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + params.reset().setVlanId(vid); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagVid, vid)).toString(); + ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + params.setVlanPriority(pcp); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagVid, vid)). + add(new XmlNode(tagPcp, pcp)).toString(); + ematch = unmarshal(um, xml, VTNEtherMatch.class); + ematch.verify(); + assertEquals(params.toVTNEtherMatch(), ematch); + + // Ensure that broken values in XML can be detected. + jaxbErrorTest(VTNEtherMatch.class, getXmlDataTypes(XML_ROOT)); + } + + /** + * Test case for {@link VTNEtherMatch#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + matchTest(Integer.valueOf(0), null); + + Integer[] vlanIds = { + 1, 2, 100, 3000, 4095, + }; + Short[] vlanPcps = { + 0, 3, 7, + }; + + for (Integer vid: vlanIds) { + for (Short pcp: vlanPcps) { + matchTest(vid, pcp); + } + } + } + + /** + * Run tests for {@link VTNEtherMatch#match(FlowMatchContext)}. + * + * @param vid A VLAN ID. + * @param pcp A VLAN priority. + * @throws Exception An error occurred. + */ + private void matchTest(Integer vid, Short pcp) throws Exception { + EtherAddress src = new EtherAddress(0x001122334455L); + EtherAddress dst = new EtherAddress(0xaabbccddeeffL); + int etype = 0x806; + EtherMatchParams header = new EtherMatchParams(); + header.setSourceAddress(src); + header.setDestinationAddress(dst); + header.setEtherType(etype); + header.setVlanId(vid); + header.setVlanPriority(pcp); + TestMatchContext ctx = new TestMatchContext().setEtherHeader(header); + + // Empty match should match every packet. + VTNEtherMatch ematch = new VTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(); + + // Specify single field in Ethernet frame. + ctx.reset(); + EtherMatchParams params = new EtherMatchParams(); + params.setSourceAddress(src); + ematch = params.toVTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC); + + ctx.reset(); + params.reset().setDestinationAddress(dst); + ematch = params.toVTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_DST); + + ctx.reset(); + params.reset().setEtherType(etype); + ematch = params.toVTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_TYPE); + + // FlowMatchType.DL_VLAN should never be set into FlowMatchContext. + ctx.reset(); + params.reset().setVlanId(vid); + ematch = params.toVTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(); + + Set expected = EnumSet.of( + FlowMatchType.DL_SRC, FlowMatchType.DL_DST, FlowMatchType.DL_TYPE); + if (vid.intValue() != EtherHeader.VLAN_NONE) { + params.setVlanPriority(pcp); + ematch = params.toVTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_VLAN_PCP); + expected.add(FlowMatchType.DL_VLAN_PCP); + } + + // Specfify all fields. + ctx.reset(); + params.setSourceAddress(src); + params.setDestinationAddress(dst); + params.setEtherType(etype); + ematch = params.toVTNEtherMatch(); + assertEquals(true, ematch.match(ctx)); + ctx.checkMatchFields(expected); + + // Ensure that match() returns false if one field does not match. + EtherAddress anotherMac = new EtherAddress(0x102030405060L); + ctx.reset(); + params.setSourceAddress(anotherMac); + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC); + + ctx.reset(); + params.setSourceAddress(src); + params.setDestinationAddress(anotherMac); + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST); + + int anotherType = 0x800; + ctx.reset(); + params.setDestinationAddress(dst); + params.setEtherType(anotherType); + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + + params.setEtherType(etype); + if (vid.intValue() == EtherHeader.VLAN_NONE) { + Integer[] vids = {1, 4095}; + for (Integer v: vids) { + ctx.reset(); + params.setVlanId(v); + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, + FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + + ctx.reset(); + params.setVlanPriority((short)0); + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, + FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + } + } else { + int anotherVid = vid.intValue() + 1; + if (anotherVid > 4095) { + anotherVid = 1; + } + Integer[] vids = {EtherHeader.VLAN_NONE, anotherVid}; + for (Integer v: vids) { + ctx.reset(); + params.setVlanId(v); + if (v.intValue() == EtherHeader.VLAN_NONE) { + params.setVlanPriority((Short)null); + } else { + params.setVlanPriority(pcp); + } + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, + FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + } + + short anotherPcp = (short)((pcp.shortValue() + 1) & 0x7); + ctx.reset(); + params.setVlanId(vid); + params.setVlanPriority(anotherPcp); + ematch = params.toVTNEtherMatch(); + assertEquals(false, ematch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE, + FlowMatchType.DL_VLAN_PCP); + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatchTest.java new file mode 100644 index 00000000..e9d497e6 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNIcmpMatchTest.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.IcmpMatch; +import org.opendaylight.vtn.manager.flow.cond.L4Match; + +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlDataType; +import org.opendaylight.vtn.manager.internal.XmlValueType; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +/** + * JUnit test for {@link VTNIcmpMatch}. + */ +public class VTNIcmpMatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNIcmpMatch} class. + */ + private static final String XML_ROOT = "vtn-icmp-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNIcmpMatch} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + ArrayList dlist = new ArrayList<>(); + Collections.addAll( + dlist, + new XmlValueType("type", Short.class).add(name).prepend(parent), + new XmlValueType("code", Short.class).add(name).prepend(parent)); + return dlist; + } + + /** + * Test case for constructors and getter methods. + * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor1() throws Exception { + VTNIcmpMatch empty = new VTNIcmpMatch(); + assertEquals(null, empty.getIcmpType()); + assertEquals(null, empty.getIcmpCode()); + IcmpMatchParams.checkInetProtocol(empty); + + Short[] types = { + null, 0, 1, 50, 100, 200, 254, 255, + }; + Short[] codes = { + null, 0, 1, 33, 67, 128, 254, 255, + }; + + IcmpMatchParams params = new IcmpMatchParams(); + for (Short type: types) { + params.setType(type); + for (Short code: codes) { + params.setCode(code); + IcmpMatch im = params.toL4Match(); + VTNIcmpMatch imatch = new VTNIcmpMatch(im); + params.verify(imatch); + assertEquals(imatch, VTNLayer4Match.create(im)); + } + } + + // Invalid type/code. + Short[] invalidValues = { + Short.MIN_VALUE, Short.MIN_VALUE + 1, -0x7000, -0x5000, -0xf00, + -100, -55, -33, -22, -3, -2, -1, + 256, 257, 500, 1000, 3333, 6666, 12345, 23456, 32000, + Short.MAX_VALUE - 1, Short.MAX_VALUE, + }; + for (Short value: invalidValues) { + params.reset().setType(value); + IcmpMatch im = params.toL4Match(); + try { + new VTNIcmpMatch(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid ICMP type: " + value, + st.getDescription()); + } + + params.reset().setCode(value); + im = params.toL4Match(); + try { + new VTNIcmpMatch(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid ICMP code: " + value, + st.getDescription()); + } + } + + assertEquals(null, VTNLayer4Match.create((IcmpMatch)null)); + assertEquals(null, VTNLayer4Match.create((L4Match)null)); + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNIcmpMatch#equals(Object)}
  • + *
  • {@link VTNIcmpMatch#hashCode()}
  • + *
  • {@link VTNIcmpMatch#setConditionKey(StringBuilder)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + Short[] types = { + null, 0, 1, 2, 50, 78, 100, 127, 200, 254, 255, + }; + Short[] codes = { + null, 0, 1, 14, 33, 67, 103, 128, 192, 254, 255, + }; + + StringBuilder b = new StringBuilder(); + IcmpMatchParams params = new IcmpMatchParams(); + for (Short type: types) { + params.setType(type); + for (Short code: codes) { + params.setCode(code); + VTNIcmpMatch imatch1 = params.toVTNLayer4Match(); + VTNIcmpMatch imatch2 = params.toVTNLayer4Match(); + testEquals(set, imatch1, imatch2); + + b.setLength(0); + imatch1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + imatch2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + } + } + + int count = types.length * codes.length; + assertEquals(count, set.size()); + assertEquals(count, keySet.size()); + } + + /** + * Test case for {@link VTNIcmpMatch#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + Short[] types = { + null, 0, 1, 50, 78, 127, 255, + }; + Short[] codes = { + null, 0, 1, 33, 67, 128, 255, + }; + + Class xmlType = VTNIcmpMatch.class; + Unmarshaller um = createUnmarshaller(xmlType); + IcmpMatchParams params = new IcmpMatchParams(); + for (Short type: types) { + params.setType(type); + for (Short code: codes) { + params.setCode(code); + XmlNode root = new XmlNode(XML_ROOT); + if (type != null) { + root.add(new XmlNode("type", type)); + } + if (code != null) { + root.add(new XmlNode("code", code)); + } + + String xml = root.toString(); + VTNIcmpMatch imatch = unmarshal(um, xml, xmlType); + imatch.verify(); + params.verify(imatch); + } + } + + // Invalid type/code. + Short[] invalidValues = { + Short.MIN_VALUE, Short.MIN_VALUE + 1, -0x7000, -0x5000, -0xf00, + -100, -55, -33, -22, -3, -2, -1, + 256, 257, 500, 1000, 3333, 6666, 12345, 23456, 32000, + Short.MAX_VALUE - 1, Short.MAX_VALUE, + }; + for (Short value: invalidValues) { + String xml = new XmlNode(XML_ROOT). + add(new XmlNode("type", value)).toString(); + VTNIcmpMatch imatch = unmarshal(um, xml, xmlType); + try { + imatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid ICMP type: " + value, + st.getDescription()); + } + + xml = new XmlNode(XML_ROOT).add(new XmlNode("code", value)). + toString(); + imatch = unmarshal(um, xml, xmlType); + try { + imatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid ICMP code: " + value, + st.getDescription()); + } + } + + // Ensure that broken values in XML can be detected. + jaxbErrorTest(um, xmlType, getXmlDataTypes(XML_ROOT)); + } + + /** + * Test case for {@link VTNIcmpMatch#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + short icmpType = 6; + short icmpCode = 234; + IcmpMatchParams header = new IcmpMatchParams(icmpType, icmpCode); + TestMatchContext ctx = new TestMatchContext().setLayer4Header(header); + + // Specify single field in ICMP header. + IcmpMatchParams params = new IcmpMatchParams().setType(icmpType); + VTNIcmpMatch imatch = params.toVTNLayer4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.ICMP_TYPE); + + ctx.reset(); + params.reset().setCode(icmpCode); + imatch = params.toVTNLayer4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.ICMP_CODE); + + // Specify all fields. + ctx.reset(); + params.setType(icmpType); + imatch = params.toVTNLayer4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.ICMP_TYPE, FlowMatchType.ICMP_CODE); + + // ICMP match should not match to a non-ICMP packet. + Layer4Header[] anotherL4 = { + null, + new TcpMatchParams().setSourcePortFrom((int)icmpType). + setDestinationPortFrom((int)icmpCode), + new UdpMatchParams().setSourcePortFrom((int)icmpType). + setDestinationPortFrom((int)icmpCode), + }; + for (Layer4Header h: anotherL4) { + ctx.reset(); + ctx.setLayer4Header(h); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(); + } + + ctx.setLayer4Header(header); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.ICMP_TYPE, FlowMatchType.ICMP_CODE); + + // Ensure match() returns if one field does not match. + for (short value = 0; value < 256; value++) { + if (value != icmpType) { + ctx.reset(); + params.setType(value); + imatch = params.toVTNLayer4Match(); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.ICMP_TYPE); + params.setType(icmpType); + } + + if (value != icmpCode) { + ctx.reset(); + params.setCode(value); + imatch = params.toVTNLayer4Match(); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.ICMP_TYPE, + FlowMatchType.ICMP_CODE); + params.setCode(icmpCode); + } + } + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4MatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4MatchTest.java new file mode 100644 index 00000000..15ce450a --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNInet4MatchTest.java @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.Inet4Match; +import org.opendaylight.vtn.manager.flow.cond.InetMatch; +import org.opendaylight.vtn.manager.util.Ip4Network; +import org.opendaylight.vtn.manager.util.IpNetwork; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlDataType; +import org.opendaylight.vtn.manager.internal.XmlValueType; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.vtn.match.fields.VtnInetMatch; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; + +/** + * JUnit test for {@link VTNInet4Match}. + */ +public class VTNInet4MatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNInet4Match} class. + */ + private static final String XML_ROOT = "vtn-inet4-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNInet4Match} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + ArrayList dlist = new ArrayList<>(); + Collections.addAll( + dlist, + new XmlValueType("source-network-v4", + Ip4Network.class).add(name).prepend(parent), + new XmlValueType("destination-network-v4", + Ip4Network.class).add(name).prepend(parent), + new XmlValueType("protocol", Short.class).add(name).prepend(parent), + new XmlValueType("dscp", Short.class).add(name).prepend(parent)); + return dlist; + } + + /** + * Test case for the following constructors. + * + *
    + *
  • {@link VTNInet4Match#VTNInet4Match()}
  • + *
  • {@link VTNInet4Match#VTNInet4Match(Short)}
  • + *
  • {@link VTNInet4Match#setProtocol(Short)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor1() throws Exception { + VTNInet4Match imatch = new VTNInet4Match(); + assertEquals(null, imatch.getSourceNetwork()); + assertEquals(null, imatch.getDestinationNetwork()); + assertEquals(null, imatch.getProtocol()); + assertEquals(null, imatch.getDscp()); + + Short[] protocols = { + 0, 1, 30, 63, 64, 127, 128, 254, 255, + }; + for (Short proto: protocols) { + imatch = new VTNInet4Match(proto); + assertEquals(null, imatch.getSourceNetwork()); + assertEquals(null, imatch.getDestinationNetwork()); + assertEquals(proto, imatch.getProtocol()); + assertEquals(null, imatch.getDscp()); + + imatch = new VTNInet4Match(); + assertEquals(null, imatch.getProtocol()); + imatch.setProtocol(proto); + assertEquals(proto, imatch.getProtocol()); + imatch.setProtocol(proto); + assertEquals(proto, imatch.getProtocol()); + for (int i = 1; i <= 10; i++) { + short p = (short)((proto.shortValue() + i) & 0xff); + try { + imatch.setProtocol(p); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "IP protocol conflict: proto=" + proto + + ", expected=" + p; + assertEquals(msg, st.getDescription()); + } + } + } + } + + /** + * Test case for the following methods. + * + *
    + *
  • {@link VTNInet4Match#VTNInet4Match(Inet4Match)}
  • + *
  • {@link VTNInet4Match#setMatch(MatchBuilder)}
  • + *
  • {@link VTNInetMatch#create(org.opendaylight.vtn.manager.flow.cond.InetMatch)}
  • + *
  • {@link VTNInetMatch#create(Match)}
  • + *
  • Getter methods.
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor2() throws Exception { + IpNetwork[] srcs = { + null, new Ip4Network("10.1.2.3"), + new Ip4Network("192.168.234.193"), + }; + Short[] srcPfx = {null, 1, 8, 32}; + IpNetwork[] dsts = { + null, new Ip4Network("10.20.30.40"), + new Ip4Network("172.30.193.35"), + }; + Short[] dstPfx = {null, 1, 16, 32}; + Short[] protocols = {null, 0, 6, 255}; + Short[] dscps = {null, 0, 30, 63}; + + Inet4MatchParams params = new Inet4MatchParams(); + for (IpNetwork src: srcs) { + params.setSourceAddress(src); + for (Short spfx: srcPfx) { + params.setSourcePrefix(spfx); + for (IpNetwork dst: dsts) { + params.setDestinationAddress(dst); + for (Short dpfx: dstPfx) { + params.setDestinationPrefix(dpfx); + for (Short proto: protocols) { + params.setProtocol(proto); + for (Short dscp: dscps) { + params.setDscp(dscp); + Inet4Match im = params.toInet4Match(); + VTNInet4Match imatch = new VTNInet4Match(im); + params.verify(imatch); + assertEquals(imatch, VTNInetMatch.create(im)); + } + } + } + } + } + } + + // Create broken Inet4Match. + String v6addr = "::1"; + String[] badAddrs = { + "", "192.168.100.256", v6addr, "bad_address", + }; + Unmarshaller um = createUnmarshaller(Inet4Match.class); + for (String addr: badAddrs) { + String xml = new XmlNode("inet4match"). + setAttribute("src", addr).toString(); + Inet4Match im = unmarshal(um, xml, Inet4Match.class); + assertNotNull(im.getValidationStatus()); + try { + new VTNInet4Match(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg; + if (addr.isEmpty()) { + msg = "Empty source address."; + } else if (addr.equals(v6addr)) { + msg = "Unexpected source address type: addr=" + addr + + ", expected=Inet4Address"; + } else { + msg = "Invalid source IP address: " + addr; + } + assertEquals(msg, st.getDescription()); + } + } + + // Invalid prefix length. + Short[] badPrefix = { + Short.MIN_VALUE, -30000, -10000, -0x100, -3, -2, -1, 0, + 33, 34, 1000, 0x1f00, Short.MAX_VALUE - 1, Short.MAX_VALUE, + }; + IpNetwork ipaddr = new Ip4Network("192.168.10.20"); + for (Short prefix: badPrefix) { + params.reset().setSourceAddress(ipaddr); + params.setSourcePrefix(prefix); + Inet4Match im = params.toInet4Match(); + assertEquals(null, im.getValidationStatus()); + try { + new VTNInet4Match(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = st.getDescription(); + assertTrue(msg.startsWith("Invalid source IP address: ")); + } + + params.reset().setDestinationAddress(ipaddr); + params.setDestinationPrefix(prefix); + im = params.toInet4Match(); + assertEquals(null, im.getValidationStatus()); + try { + new VTNInet4Match(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = st.getDescription(); + assertTrue(msg.startsWith("Invalid destination IP address: ")); + } + } + + // Invalid protocol numbers. + Short[] badProtocols = { + Short.MIN_VALUE, -30000, -10000, -0x100, -3, -2, -1, + 256, 257, 999, 0x1f00, Short.MAX_VALUE - 1, Short.MAX_VALUE, + }; + for (Short proto: badProtocols) { + params.reset().setProtocol(proto); + Inet4Match im = params.toInet4Match(); + assertEquals(null, im.getValidationStatus()); + try { + new VTNInet4Match(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid IP protocol number: " + proto, + st.getDescription()); + } + } + + // Invalid DSCP values. + params.setProtocol((short)6); + Short[] badDscps = { + Byte.MIN_VALUE, -127, -100, -50, -16, -3, -2, -1, + 64, 65, 70, 80, 99, 127, Byte.MAX_VALUE, + }; + for (Short dscp: badDscps) { + params.setDscp(dscp); + Inet4Match im = params.toInet4Match(); + assertEquals(null, im.getValidationStatus()); + try { + new VTNInet4Match(im); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid IP DSCP field value: " + dscp, + st.getDescription()); + } + } + + Match empty = new MatchBuilder().build(); + assertEquals(null, VTNInetMatch.create(empty)); + assertEquals(null, VTNInetMatch.create((InetMatch)null)); + } + + /** + * Test case for the following methods. + * + *
    + *
  • {@link VTNInet4Match#VTNInet4Match(org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnInetMatchFields)}
  • + *
  • {@link VTNInet4Match#setMatch(MatchBuilder)}
  • + *
  • {@link VTNInetMatch#create(Match)}
  • + *
  • {@link VTNInetMatch#create(VTNEtherMatch, VtnInetMatch)}
  • + *
  • Getter methods.
  • + *
  • JAXB bindings.
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor3() throws Exception { + IpNetwork[] srcs = { + null, new Ip4Network("10.1.2.3"), + }; + Short[] srcPfx = {null, 8, 24}; + IpNetwork[] dsts = { + null, new Ip4Network("10.20.30.40"), + }; + Short[] dstPfx = {null, 17, 23}; + Short[] protocols = {null, 33}; + Short[] dscps = {null, 35}; + + Inet4MatchParams params = new Inet4MatchParams(); + Class mtype = VTNInet4Match.class; + VTNEtherMatch ematch = null; + for (IpNetwork src: srcs) { + params.setSourceAddress(src); + for (Short spfx: srcPfx) { + params.setSourcePrefix(spfx); + for (IpNetwork dst: dsts) { + params.setDestinationAddress(dst); + for (Short dpfx: dstPfx) { + params.setDestinationPrefix(dpfx); + for (Short proto: protocols) { + params.setProtocol(proto); + for (Short dscp: dscps) { + params.setDscp(dscp); + VtnInetMatch vim = params.toVtnInetMatch(); + VTNInet4Match imatch = new VTNInet4Match(vim); + params.verify(imatch); + assertEquals(imatch, + VTNInetMatch.create(ematch, vim)); + + // JAXB test. + VTNInet4Match jaxb = + jaxbTest(imatch, mtype, XML_ROOT); + jaxb.verify(); + } + } + } + } + } + } + + assertEquals(null, VTNInetMatch.create(ematch, null)); + } + + /** + * Test case for {@link VTNInetMatch#verify()}. + * + * @throws Exception An error occurred. + */ + @Test + public void testVerify() throws Exception { + Unmarshaller um = createUnmarshaller(VTNInet4Match.class); + + // Invalid protocol numbers. + Short[] badProtocols = { + Short.MIN_VALUE, -30000, -10000, -0x100, -3, -2, -1, + 256, 257, 999, 0x1f00, Short.MAX_VALUE - 1, Short.MAX_VALUE, + }; + for (Short proto: badProtocols) { + String xml = new XmlNode(XML_ROOT). + add(new XmlNode("protocol", proto)).toString(); + VTNInet4Match imatch = unmarshal(um, xml, VTNInet4Match.class); + try { + imatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid IP protocol number: " + proto, + st.getDescription()); + } + } + + // Invalid DSCP values. + Short[] badDscps = { + Short.MIN_VALUE, -30000, -20000, -256, -100, -3, -2, -1, + 64, 65, 100, 256, 10000, 25000, Short.MAX_VALUE, + }; + for (Short dscp: badDscps) { + String xml = new XmlNode(XML_ROOT). + add(new XmlNode("dscp", dscp)).toString(); + VTNInet4Match imatch = unmarshal(um, xml, VTNInet4Match.class); + try { + imatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid IP DSCP field value: " + dscp, + st.getDescription()); + } + } + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNInetMatch#equals(Object)}
  • + *
  • {@link VTNInetMatch#hashCode()}
  • + *
  • {@link VTNInetMatch#setConditionKey(StringBuilder)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + IpNetwork[] srcs = { + null, new Ip4Network("192.168.199.0/24"), + new Ip4Network("172.168.33.44"), + }; + IpNetwork[] dsts = { + null, new Ip4Network("11.22.33.44"), + new Ip4Network("100.200.30.192/26"), + }; + Short[] protocols = {null, 6, 255}; + Short[] dscps = {null, 44, 63}; + + StringBuilder b = new StringBuilder(); + Inet4MatchParams params = new Inet4MatchParams(); + for (IpNetwork src: srcs) { + params.setSourceNetwork(src); + for (IpNetwork dst: dsts) { + params.setDestinationNetwork(dst); + for (Short proto: protocols) { + params.setProtocol(proto); + for (Short dscp: dscps) { + params.setDscp(dscp); + VTNInet4Match imatch1 = params.toVTNInet4Match(); + VTNInet4Match imatch2 = params.toVTNInet4Match(); + testEquals(set, imatch1, imatch2); + + b.setLength(0); + imatch1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + imatch2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + } + } + } + } + + int count = srcs.length * dsts.length * protocols.length * + dscps.length; + assertEquals(count, set.size()); + assertEquals(count, keySet.size()); + } + + /** + * Ensure that {@link VTNInet4Match} is mapped to XML root element. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // VTNInet4Match can be unmashalled by VTNInetMatch unmarshaller. + Unmarshaller um = createUnmarshaller(VTNInetMatch.class); + Unmarshaller um4 = createUnmarshaller(VTNInet4Match.class); + Inet4MatchParams params = new Inet4MatchParams(); + + // Empty match. + String xml = new XmlNode(XML_ROOT).toString(); + VTNInet4Match imatch = unmarshal(um, xml, VTNInet4Match.class); + assertEquals(imatch, unmarshal(um4, xml, VTNInet4Match.class)); + imatch.verify(); + assertEquals(params.toVTNInet4Match(), imatch); + + // Specifying all fields. + IpNetwork src = new Ip4Network("192.168.10.0/24"); + IpNetwork dst = new Ip4Network("1.2.3.4"); + Short proto = Short.valueOf((short)17); + Short dscp = Short.valueOf((short)3); + params.setSourceNetwork(src).setDestinationNetwork(dst). + setProtocol(proto).setDscp(dscp); + + final String tagSrc = "source-network-v4"; + final String tagDst = "destination-network-v4"; + final String tagProto = "protocol"; + final String tagDscp = "dscp"; + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagSrc, src.getText())). + add(new XmlNode(tagDst, dst.getText())). + add(new XmlNode(tagProto, proto)). + add(new XmlNode(tagDscp, dscp)).toString(); + imatch = unmarshal(um, xml, VTNInet4Match.class); + assertEquals(imatch, unmarshal(um4, xml, VTNInet4Match.class)); + imatch.verify(); + assertEquals(params.toVTNInet4Match(), imatch); + + // Specifying single field. + params.reset().setSourceNetwork(src); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagSrc, src.getText())).toString(); + imatch = unmarshal(um, xml, VTNInet4Match.class); + assertEquals(imatch, unmarshal(um4, xml, VTNInet4Match.class)); + imatch.verify(); + assertEquals(params.toVTNInet4Match(), imatch); + + params.reset().setDestinationNetwork(dst); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagDst, dst.getText())).toString(); + imatch = unmarshal(um, xml, VTNInet4Match.class); + assertEquals(imatch, unmarshal(um4, xml, VTNInet4Match.class)); + imatch.verify(); + assertEquals(params.toVTNInet4Match(), imatch); + + params.reset().setProtocol(proto); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagProto, proto)).toString(); + imatch = unmarshal(um, xml, VTNInet4Match.class); + assertEquals(imatch, unmarshal(um4, xml, VTNInet4Match.class)); + imatch.verify(); + assertEquals(params.toVTNInet4Match(), imatch); + + params.reset().setDscp(dscp); + xml = new XmlNode(XML_ROOT). + add(new XmlNode(tagDscp, dscp)).toString(); + imatch = unmarshal(um, xml, VTNInet4Match.class); + assertEquals(imatch, unmarshal(um4, xml, VTNInet4Match.class)); + imatch.verify(); + assertEquals(params.toVTNInet4Match(), imatch); + + // Ensure that broken values in XML can be detected. + List dtypes = getXmlDataTypes(XML_ROOT); + jaxbErrorTest(um, VTNInet4Match.class, dtypes); + jaxbErrorTest(um4, VTNInet4Match.class, dtypes); + } + + /** + * Test case for {@link VTNInetMatch#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + for (short slen = 1; slen <= 32; slen++) { + for (short dlen = 1; dlen <= 32; dlen++) { + matchTest(slen, dlen); + } + } + } + + /** + * Run tests for {@link VTNInetMatch#match(FlowMatchContext)}. + * + * @param srcLen The length of the source network prefix. + * @param dstLen The length of the destination network prefix. + * @throws Exception An error occurred. + */ + private void matchTest(short srcLen, short dstLen) throws Exception { + Ip4Network src = new Ip4Network("192.168.10.20"); + Ip4Network dst = new Ip4Network("172.168.250.254"); + short proto = 6; + short dscp = 39; + Inet4MatchParams header = new Inet4MatchParams(); + header.setSourceAddress(src); + header.setDestinationAddress(dst); + header.setProtocol(proto); + header.setDscp(dscp); + TestMatchContext ctx = new TestMatchContext().setInetHeader(header); + + // Empty match should match every packet. + VTNInet4Match imatch = new VTNInet4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(); + + // Specify single field in IP header. + ctx.reset(); + Inet4MatchParams params = new Inet4MatchParams(); + params.setSourceAddress(src); + params.setSourcePrefix(srcLen); + imatch = params.toVTNInet4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC); + + ctx.reset(); + params.reset().setDestinationAddress(dst); + params.setDestinationPrefix(dstLen); + imatch = params.toVTNInet4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_DST); + + ctx.reset(); + params.reset().setProtocol(proto); + imatch = params.toVTNInet4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_PROTO); + + ctx.reset(); + params.reset().setDscp(dscp); + imatch = params.toVTNInet4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_DSCP); + + // Specify all fields. + ctx.reset(); + params.setSourceAddress(src); + params.setSourcePrefix(srcLen); + params.setDestinationAddress(dst); + params.setDestinationPrefix(dstLen); + params.setProtocol(proto); + params.setDscp(dscp); + imatch = params.toVTNInet4Match(); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC, FlowMatchType.IP_DST, + FlowMatchType.IP_PROTO, FlowMatchType.IP_DSCP); + + // Inet4 match should not match to a non-IP packet. + ctx.reset(); + ctx.setInetHeader(null); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(); + ctx.setInetHeader(header); + assertEquals(true, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC, FlowMatchType.IP_DST, + FlowMatchType.IP_PROTO, FlowMatchType.IP_DSCP); + + // Ensure match() returns false if one field does not match. + int addr = src.getAddress() ^ (int)0x80000000; + Ip4Network anotherSrc = new Ip4Network(addr); + ctx.reset(); + params.setSourceAddress(anotherSrc); + imatch = params.toVTNInet4Match(); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC); + + addr = dst.getAddress() ^ (int)0x80000000; + Ip4Network anotherDst = new Ip4Network(addr); + ctx.reset(); + params.setSourceAddress(src); + params.setDestinationAddress(anotherDst); + imatch = params.toVTNInet4Match(); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC, FlowMatchType.IP_DST); + + ctx.reset(); + params.setDestinationAddress(dst); + params.setProtocol((short)17); + imatch = params.toVTNInet4Match(); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC, FlowMatchType.IP_DST, + FlowMatchType.IP_PROTO); + + ctx.reset(); + params.setProtocol(proto); + params.setDscp((short)0); + imatch = params.toVTNInet4Match(); + assertEquals(false, imatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.IP_SRC, FlowMatchType.IP_DST, + FlowMatchType.IP_PROTO, FlowMatchType.IP_DSCP); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatchTest.java new file mode 100644 index 00000000..0d269322 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNMatchTest.java @@ -0,0 +1,916 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.FlowMatch; +import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.Ip4Network; +import org.opendaylight.vtn.manager.util.IpNetwork; + +import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader; +import org.opendaylight.vtn.manager.internal.util.packet.IcmpHeader; +import org.opendaylight.vtn.manager.internal.util.packet.InetHeader; +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.packet.TcpHeader; +import org.opendaylight.vtn.manager.internal.util.packet.UdpHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.DataGenerator; +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlDataType; + +import org.opendaylight.controller.sal.utils.EtherTypes; +import org.opendaylight.controller.sal.utils.IPProtocols; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +/** + * JUnit test for {@link VTNMatch}. + */ +public class VTNMatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNMatch} class. + */ + private static final String XML_ROOT = "vtn-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNMatch} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + String[] p = XmlDataType.addPath(name, parent); + ArrayList dlist = new ArrayList<>(); + dlist.addAll(VTNEtherMatchTest.getXmlDataTypes("vtn-ether-match", p)); + dlist.addAll(VTNInet4MatchTest.getXmlDataTypes("vtn-inet4-match", p)); + dlist.addAll(VTNTcpMatchTest.getXmlDataTypes("vtn-tcp-match", p)); + dlist.addAll(VTNUdpMatchTest.getXmlDataTypes("vtn-udp-match", p)); + dlist.addAll(VTNIcmpMatchTest.getXmlDataTypes("vtn-icmp-match", p)); + + return dlist; + } + + /** + * Test case for the following methods. + * + *
    + *
  • {@link VTNMatch#VTNMatch()}
  • + *
  • {@link VTNMatch#VTNMatch(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match)}
  • + *
  • {@link VTNMatch#set(FlowMatch)}
  • + *
  • {@link VTNMatch#complete()}
  • + *
  • Getter methods
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testGetter() throws Exception { + VTNMatch empty = new VTNMatch(); + assertEquals(null, empty.getEtherMatch()); + assertEquals(null, empty.getInetMatch()); + assertEquals(null, empty.getLayer4Match()); + + Map cases = MatchParams.createMatches(); + for (Map.Entry entry: cases.entrySet()) { + MatchParams params = entry.getKey(); + MatchParams expected = entry.getValue(); + VTNMatch vmatch = params.toVTNMatch(); + expected.verify(vmatch); + } + + // Ethernet condition will be omitted if it is empty. + MatchParams params = new MatchParams(). + setEtherParams(new EtherMatchParams()); + new MatchParams().verify(params.toVTNMatch()); + + // Inconsistent Ethernet type. + int etype = 0x806; + EtherMatchParams eparams = new EtherMatchParams(). + setEtherType(Integer.valueOf(etype)); + Inet4MatchParams i4params = new Inet4MatchParams(); + params = new MatchParams().setEtherParams(eparams). + setInet4Params(i4params); + FlowMatch fm = params.toFlowMatch(); + VTNMatch vmatch = new VTNMatch(); + try { + vmatch.set(fm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Ethernet type conflict: type=0x" + + Integer.toHexString(etype) + ", expected=0x" + + Integer.toHexString(EtherTypes.IPv4.intValue()); + assertEquals(msg, st.getDescription()); + } + + // Inconsistent IP protocol number. + short proto = 17; + i4params.setProtocol(Short.valueOf(proto)); + TcpMatchParams tparams = new TcpMatchParams(); + params = new MatchParams(). + setInet4Params(i4params). + setLayer4Params(tparams); + fm = params.toFlowMatch(); + try { + vmatch.set(fm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "IP protocol conflict: proto=" + proto + + ", expected=" + IPProtocols.TCP.shortValue(); + assertEquals(msg, st.getDescription()); + } + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNMatch#equals(Object)}
  • + *
  • {@link VTNMatch#hashCode()}
  • + *
  • {@link VTNMatch#getConditionKey()}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + Map cases = MatchParams.createMatches(); + for (Map.Entry entry: cases.entrySet()) { + MatchParams params = entry.getKey(); + MatchParams expected = entry.getValue(); + VTNMatch vmatch1 = params.toVTNMatch(); + VTNMatch vmatch2 = expected.toVTNMatch(); + testEquals(set, vmatch1, vmatch2); + assertEquals(true, keySet.add(vmatch1.getConditionKey())); + assertEquals(false, keySet.add(vmatch2.getConditionKey())); + } + + assertEquals(cases.size(), set.size()); + assertEquals(cases.size(), keySet.size()); + } + + /** + * Test case for {@link VTNMatch#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + Class type = VTNMatch.class; + Unmarshaller um = createUnmarshaller(type); + Map cases = MatchParams.createMatches(); + for (Map.Entry entry: cases.entrySet()) { + MatchParams params = entry.getKey(); + MatchParams expected = entry.getValue(); + String xml = params.toXmlNode(XML_ROOT).toString(); + VTNMatch vmatch = unmarshal(um, xml, type); + vmatch.verify(); + expected.verify(vmatch); + + xml = expected.toXmlNode(XML_ROOT).toString(); + VTNMatch vmatch1 = unmarshal(um, xml, type); + vmatch1.verify(); + assertEquals(vmatch, vmatch1); + } + + // Inconsistent Ethernet type. + int etype = 0x806; + EtherMatchParams eparams = new EtherMatchParams(). + setEtherType(Integer.valueOf(etype)); + Inet4MatchParams i4params = new Inet4MatchParams(); + MatchParams params = new MatchParams(). + setEtherParams(eparams). + setInet4Params(i4params); + String xml = params.toXmlNode(XML_ROOT).toString(); + VTNMatch vmatch = unmarshal(um, xml, type); + try { + vmatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Ethernet type conflict: type=0x" + + Integer.toHexString(etype) + ", expected=0x" + + Integer.toHexString(EtherTypes.IPv4.intValue()); + assertEquals(msg, st.getDescription()); + } + + // Inconsistent IP protocol number. + short proto = 17; + i4params.setProtocol(Short.valueOf(proto)); + TcpMatchParams tparams = new TcpMatchParams(); + params = new MatchParams(). + setInet4Params(i4params). + setLayer4Params(tparams); + xml = params.toXmlNode(XML_ROOT).toString(); + vmatch = unmarshal(um, xml, type); + try { + vmatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "IP protocol conflict: proto=" + proto + + ", expected=" + IPProtocols.TCP.shortValue(); + assertEquals(msg, st.getDescription()); + } + + // Ensure that broken values in XML can be detected. + jaxbErrorTest(um, type, getXmlDataTypes(XML_ROOT)); + } + + /** + * Test case for {@link VTNMatch#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + DataGenerator gen = new DataGenerator(); + ArrayList ipPackets = new ArrayList<>(); + + TcpMatchParams tcp = new TcpMatchParams(); + tcp.setSourcePortFrom(gen.getPort()). + setDestinationPortFrom(gen.getPort()); + TestMatchContext packet = new TestMatchContext(). + setInetHeader(new Inet4MatchParams(). + setSourceAddress(gen.getInetAddress()). + setDestinationAddress(gen.getInetAddress()). + setProtocol(IPProtocols.TCP.shortValue()). + setDscp(Short.valueOf((short)0))). + setLayer4Header(new TcpMatchParams(). + setSourcePortFrom(gen.getPort()). + setDestinationPortFrom(gen.getPort())); + ipPackets.add(packet); + + packet = new TestMatchContext(). + setInetHeader(new Inet4MatchParams(). + setSourceAddress(gen.getInetAddress()). + setDestinationAddress(gen.getInetAddress()). + setProtocol(IPProtocols.UDP.shortValue()). + setDscp(Short.valueOf((short)1))). + setLayer4Header(new UdpMatchParams(). + setSourcePortFrom(gen.getPort()). + setDestinationPortFrom(gen.getPort())); + ipPackets.add(packet); + + packet = new TestMatchContext(). + setInetHeader(new Inet4MatchParams(). + setSourceAddress(gen.getInetAddress()). + setDestinationAddress(gen.getInetAddress()). + setProtocol(IPProtocols.ICMP.shortValue()). + setDscp(Short.valueOf((short)2))). + setLayer4Header(new IcmpMatchParams(). + setType(gen.getIcmpValue()). + setCode(gen.getIcmpValue())); + ipPackets.add(packet); + + packet = new TestMatchContext(). + setInetHeader(new Inet4MatchParams(). + setSourceAddress(gen.getInetAddress()). + setDestinationAddress(gen.getInetAddress()). + setProtocol((short)123). + setDscp(Short.valueOf((short)3))); + ipPackets.add(packet); + + packet = new TestMatchContext(). + setInetHeader(new Inet4MatchParams(). + setSourceAddress(gen.getInetAddress()). + setDestinationAddress(gen.getInetAddress()). + setProtocol(IPProtocols.TCP.shortValue()). + setDscp(Short.valueOf((short)4))). + setLayer4Header(new TcpMatchParams(). + setSourcePortFrom(gen.getPort()). + setDestinationPortFrom(gen.getPort())); + ipPackets.add(packet); + + ArrayList etherPackets = new ArrayList<>(); + Integer[] vlans = { + EtherHeader.VLAN_NONE, 1, 10, 4095, + }; + + short pcp = 0; + int ipv4Type = EtherTypes.IPv4.intValue(); + for (Integer vlan: vlans) { + // Unsupported packet. + packet = new TestMatchContext(). + setEtherHeader(new EtherMatchParams(). + setSourceAddress(gen.getMacAddress()). + setDestinationAddress(gen.getMacAddress()). + setEtherType(0x4444).setVlanId(vlan). + setVlanPriority(Short.valueOf(pcp))); + etherPackets.add(packet); + pcp = (short)((pcp + 1) & 0x7); + + // ARP packet. + packet = new TestMatchContext(). + setEtherHeader(new EtherMatchParams(). + setSourceAddress(gen.getMacAddress()). + setDestinationAddress(gen.getMacAddress()). + setEtherType(EtherTypes.ARP.intValue()). + setVlanId(vlan). + setVlanPriority(Short.valueOf(pcp))); + etherPackets.add(packet); + pcp = (byte)((pcp + 1) & 0x7); + + // IPv4 packets. + for (TestMatchContext ipv4: ipPackets) { + packet = ipv4.clone(). + setEtherHeader(new EtherMatchParams(). + setSourceAddress(gen.getMacAddress()). + setDestinationAddress(gen.getMacAddress()). + setEtherType(ipv4Type). + setVlanId(vlan). + setVlanPriority(Short.valueOf(pcp))); + etherPackets.add(packet); + pcp = (byte)((pcp + 1) & 0x7); + } + } + + List empties = new ArrayList<>(); + Collections.addAll(empties, + new VTNMatch(), + new MatchParams().setEtherParams( + new EtherMatchParams()).toVTNMatch()); + for (TestMatchContext ctx: etherPackets) { + // Empty condition should match every packet. + for (VTNMatch vmatch: empties) { + assertEquals(true, vmatch.match(ctx)); + ctx.checkMatchFields(); + } + + ethernetMatchTest(ctx); + ipv4MatchTest(ctx); + layer4MatchTest(ctx); + } + } + + /** + * Test case for matching Ethernet header. + * + * @param ctx A {@link TestMatchContext} instance for test. + * @throws Exception An error occurred. + */ + private void ethernetMatchTest(TestMatchContext ctx) throws Exception { + EtherHeader ether = ctx.getEtherHeader(); + EtherAddress src = ether.getSourceAddress(); + EtherAddress dst = ether.getDestinationAddress(); + int type = ether.getEtherType(); + int vlan = ether.getVlanId(); + short pcp = ether.getVlanPriority(); + boolean tagged = vlan != EtherHeader.VLAN_NONE; + + EtherAddress anotherSrc = + new EtherAddress(src.getAddress() ^ 0x8000L); + EtherAddress anotherDst = + new EtherAddress(dst.getAddress() ^ 0x10L); + Integer anotherType = type ^ 0x1; + Integer anotherVlan = vlan ^ 0x2; + Short anotherPcp = (tagged) ? (short)(pcp ^ 0x3) : null; + + // Create flow match that specifies all Ethernet header fields. + EtherMatchParams eparams = new EtherMatchParams(). + setSourceAddress(src.getAddress()). + setDestinationAddress(dst.getAddress()). + setEtherType(Integer.valueOf(type)). + setVlanId(Integer.valueOf(vlan)); + Set expectedTypes = EnumSet.of( + FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + if (tagged) { + eparams.setVlanPriority(Short.valueOf(pcp)); + expectedTypes.add(FlowMatchType.DL_VLAN_PCP); + } + + VTNMatch vmatch = new MatchParams(). + setEtherParams(eparams).toVTNMatch(); + assertEquals(true, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + // Ensure that the packet matches only if all conditions are met. + ctx.reset(); + eparams.setSourceAddress(anotherSrc); + vmatch = new MatchParams().setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC); + + ctx.reset(); + eparams.setSourceAddress(src.getAddress()). + setDestinationAddress(anotherDst); + vmatch = new MatchParams().setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST); + + ctx.reset(); + eparams.setDestinationAddress(dst.getAddress()). + setEtherType(anotherType); + vmatch = new MatchParams().setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + + ctx.reset(); + eparams.setEtherType(type).setVlanId(anotherVlan); + vmatch = new MatchParams().setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + + if (tagged) { + ctx.reset(); + eparams.setEtherType(type). + setVlanId(Integer.valueOf(EtherHeader.VLAN_NONE)). + setVlanPriority((Short)null); + vmatch = new MatchParams().setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + } + + ctx.reset(); + eparams.setEtherType(type).setVlanId(Integer.valueOf(vlan)). + setVlanPriority(anotherPcp); + vmatch = new MatchParams().setEtherParams(eparams).toVTNMatch(); + assertEquals(!tagged, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + ctx.reset(); + } + + /** + * Test case for matching IPv4 header. + * + * @param ctx A {@link TestMatchContext} instance for test. + * @throws Exception An error occurred. + */ + private void ipv4MatchTest(TestMatchContext ctx) throws Exception { + EtherHeader ether = ctx.getEtherHeader(); + EtherAddress src = ether.getSourceAddress(); + EtherAddress dst = ether.getDestinationAddress(); + int type = ether.getEtherType(); + int vlan = ether.getVlanId(); + short pcp = ether.getVlanPriority(); + boolean tagged = vlan != EtherHeader.VLAN_NONE; + + EtherAddress anotherSrc = + new EtherAddress(src.getAddress() ^ 0x40000L); + EtherAddress anotherDst = + new EtherAddress(dst.getAddress() ^ 0x20L); + Integer anotherType = type ^ 0x10; + Integer anotherVlan = vlan ^ 0x100; + Short anotherPcp = (tagged) ? (short)(pcp ^ 0x1) : null; + + // Create flow match that specifies all header fields. + EtherMatchParams eparams = new EtherMatchParams(). + setSourceAddress(src.getAddress()). + setDestinationAddress(dst.getAddress()). + setEtherType(Integer.valueOf(type)). + setVlanId(Integer.valueOf(vlan)); + Set expectedTypes = EnumSet.of( + FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + if (tagged) { + eparams.setVlanPriority(Short.valueOf(pcp)); + expectedTypes.add(FlowMatchType.DL_VLAN_PCP); + } + + Inet4MatchParams i4params = new Inet4MatchParams(); + InetHeader inet = ctx.getInetHeader(); + if (inet == null) { + // IPv4 conditions should never be used. + i4params.setSourceNetwork(IpNetwork.create("10.0.0.0/1")). + setDestinationNetwork(IpNetwork.create("192.168.10.1/8")). + setProtocol((short)6).setDscp((short)1); + + VTNMatch vmatch = new MatchParams(). + setEtherParams(eparams.setEtherType(EtherTypes.IPv4. + intValue())). + setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + + // Ether type will be tested before VLAN tag. + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + return; + } + + IpNetwork ipSrc = inet.getSourceAddress(); + IpNetwork ipDst = inet.getDestinationAddress(); + short ipProto = inet.getProtocol(); + short ipDscp = inet.getDscp(); + i4params.setSourceNetwork(ipSrc).setDestinationNetwork(ipDst). + setProtocol(ipProto).setDscp(Short.valueOf(ipDscp)); + expectedTypes.add(FlowMatchType.IP_SRC); + expectedTypes.add(FlowMatchType.IP_DST); + expectedTypes.add(FlowMatchType.IP_PROTO); + expectedTypes.add(FlowMatchType.IP_DSCP); + + assertTrue(ipSrc instanceof Ip4Network); + IpNetwork anotherIpSrc = + new Ip4Network(((Ip4Network)ipSrc).getAddress() ^ 0x100); + assertTrue(ipDst instanceof Ip4Network); + IpNetwork anotherIpDst = + new Ip4Network(((Ip4Network)ipDst).getAddress() ^ 0x4000); + Short anotherIpProto = Short.valueOf((short)(ipProto ^ 0x40)); + Short anotherIpDscp = Short.valueOf((short)(ipDscp ^ 0x8)); + + MatchParams params = new MatchParams(). + setEtherParams(eparams).setInet4Params(i4params); + VTNMatch vmatch = params.toVTNMatch(); + assertEquals(true, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + // Ensure that the packet matches only if all conditions are met. + ctx.reset(); + eparams.setSourceAddress(anotherSrc); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC); + + ctx.reset(); + eparams.setSourceAddress(src.getAddress()). + setDestinationAddress(anotherDst); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST); + + // DL_TYPE condition cannot be changed because IPv4 condition + // will be configured. + ctx.reset(); + eparams.setDestinationAddress(dst.getAddress()). + setVlanId(anotherVlan); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + + if (tagged) { + ctx.reset(); + eparams.setVlanId(Integer.valueOf(EtherHeader.VLAN_NONE)). + setVlanPriority((Short)null); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + } + + ctx.reset(); + eparams.setVlanId(Integer.valueOf(vlan)).setVlanPriority(anotherPcp); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + if (tagged) { + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE, + FlowMatchType.DL_VLAN_PCP); + params.setEtherParams(eparams.setVlanPriority(Short.valueOf(pcp))); + } else { + assertEquals(true, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + } + + expectedTypes = EnumSet.of(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE, FlowMatchType.IP_SRC); + if (tagged) { + expectedTypes.add(FlowMatchType.DL_VLAN_PCP); + } + + ctx.reset(); + i4params.setSourceNetwork(anotherIpSrc); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + ctx.reset(); + expectedTypes.add(FlowMatchType.IP_DST); + i4params.setSourceNetwork(ipSrc).setDestinationNetwork(anotherIpDst); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + ctx.reset(); + expectedTypes.add(FlowMatchType.IP_PROTO); + i4params.setDestinationNetwork(ipDst).setProtocol(anotherIpProto); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + ctx.reset(); + expectedTypes.add(FlowMatchType.IP_DSCP); + i4params.setProtocol(Short.valueOf(ipProto)).setDscp(anotherIpDscp); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + ctx.reset(); + } + + /** + * Test case for matching layer 4 header. + * + * @param ctx A {@link TestMatchContext} instance for test. + * @throws Exception An error occurred. + */ + private void layer4MatchTest(TestMatchContext ctx) throws Exception { + EtherHeader ether = ctx.getEtherHeader(); + EtherAddress src = ether.getSourceAddress(); + EtherAddress dst = ether.getDestinationAddress(); + int type = ether.getEtherType(); + int vlan = ether.getVlanId(); + short pcp = ether.getVlanPriority(); + boolean tagged = vlan != EtherHeader.VLAN_NONE; + + EtherAddress anotherSrc = + new EtherAddress(src.getAddress() ^ 0x200L); + EtherAddress anotherDst = + new EtherAddress(dst.getAddress() ^ 0x800000L); + Integer anotherType = type ^ 0x4; + Integer anotherVlan = vlan ^ 0x8; + Short anotherPcp = (tagged) ? (short)(pcp ^ 0x2) : null; + + // Create flow match that specifies all header fields. + EtherMatchParams eparams = new EtherMatchParams(). + setSourceAddress(src.getAddress()). + setDestinationAddress(dst.getAddress()). + setEtherType(Integer.valueOf(type)). + setVlanId(Integer.valueOf(vlan)); + Set expectedTypes = EnumSet.of( + FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + if (tagged) { + eparams.setVlanPriority(Short.valueOf(pcp)); + expectedTypes.add(FlowMatchType.DL_VLAN_PCP); + } + + Inet4MatchParams i4params = new Inet4MatchParams(); + InetHeader inet = ctx.getInetHeader(); + if (inet == null) { + // IPv4 and layer 4 conditions should never be used. + i4params.setSourceNetwork(IpNetwork.create("10.0.0.1")). + setDestinationNetwork(IpNetwork.create("192.168.10.1")). + setDscp((short)1); + + TcpMatchParams tparams = new TcpMatchParams(). + setSourcePortFrom(10).setDestinationPortFrom(300); + VTNMatch vmatch = new MatchParams(). + setEtherParams(eparams.setEtherType(EtherTypes.IPv4. + intValue())). + setInet4Params(i4params). + setLayer4Params(tparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + + // Ether type will be tested before VLAN tag. + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + return; + } + + + IpNetwork ipSrc = inet.getSourceAddress(); + IpNetwork ipDst = inet.getDestinationAddress(); + short ipProto = inet.getProtocol(); + short ipDscp = inet.getDscp(); + i4params.setSourceNetwork(ipSrc).setDestinationNetwork(ipDst). + setProtocol(ipProto).setDscp(Short.valueOf(ipDscp)); + expectedTypes.add(FlowMatchType.IP_SRC); + expectedTypes.add(FlowMatchType.IP_DST); + expectedTypes.add(FlowMatchType.IP_PROTO); + expectedTypes.add(FlowMatchType.IP_DSCP); + + Layer4Header l4 = ctx.getLayer4Header(); + Layer4MatchParams l4params = null; + IPProtocols ipType = null; + TcpHeader tcp = null; + TcpMatchParams tparams = null; + UdpHeader udp = null; + UdpMatchParams uparams = null; + IcmpHeader icmp = null; + IcmpMatchParams iparams = null; + FlowMatchType srcType = null; + FlowMatchType dstType = null; + int srcPort = -1; + int dstPort = -1; + Integer anotherSrcPort = null; + Integer anotherDstPort = null; + short icmpType = -1; + short icmpCode = -1; + Short anotherIcmpType = null; + Short anotherIcmpCode = null; + if (l4 instanceof TcpHeader) { + ipType = IPProtocols.TCP; + tcp = (TcpHeader)l4; + srcPort = tcp.getSourcePort(); + dstPort = tcp.getDestinationPort(); + anotherSrcPort = Integer.valueOf(srcPort ^ 0x4); + anotherDstPort = Integer.valueOf(dstPort ^ 0x80); + tparams = new TcpMatchParams().setSourcePortFrom(srcPort). + setDestinationPortFrom(dstPort); + l4params = tparams; + srcType = FlowMatchType.TCP_SRC; + dstType = FlowMatchType.TCP_DST; + } else if (l4 instanceof UdpHeader) { + ipType = IPProtocols.UDP; + udp = (UdpHeader)l4; + srcPort = udp.getSourcePort(); + dstPort = udp.getDestinationPort(); + anotherSrcPort = Integer.valueOf(srcPort ^ 0x400); + anotherDstPort = Integer.valueOf(dstPort ^ 0x8); + uparams = new UdpMatchParams().setSourcePortFrom(srcPort). + setDestinationPortFrom(dstPort); + l4params = uparams; + srcType = FlowMatchType.UDP_SRC; + dstType = FlowMatchType.UDP_DST; + } else if (l4 instanceof IcmpHeader) { + ipType = IPProtocols.ICMP; + icmp = (IcmpHeader)l4; + icmpType = icmp.getIcmpType(); + icmpCode = icmp.getIcmpCode(); + anotherIcmpType = Short.valueOf((short)(icmpType ^ 0x8)); + anotherIcmpCode = Short.valueOf((short)(icmpCode ^ 0x80)); + iparams = new IcmpMatchParams().setType(icmpType). + setCode(icmpCode); + l4params = iparams; + srcType = FlowMatchType.ICMP_TYPE; + dstType = FlowMatchType.ICMP_CODE; + } + + if (ipType == null) { + // Layer 4 conditions should never be used. + i4params.setProtocol(IPProtocols.TCP.shortValue()); + VTNMatch vmatch = new MatchParams(). + setEtherParams(eparams). + setInet4Params(i4params). + setLayer4Params(new TcpMatchParams(). + setSourcePortFrom(12345). + setDestinationPortFrom(333)). + toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + + // IP protocol will be tested before DSCP. + if (ipProto != IPProtocols.TCP.shortValue()) { + expectedTypes.remove(FlowMatchType.IP_DSCP); + } + ctx.checkMatchFields(expectedTypes); + return; + } + + assertTrue(ipSrc instanceof Ip4Network); + IpNetwork anotherIpSrc = + new Ip4Network(((Ip4Network)ipSrc).getAddress() ^ 0x200000); + assertTrue(ipDst instanceof Ip4Network); + IpNetwork anotherIpDst = + new Ip4Network(((Ip4Network)ipDst).getAddress() ^ 0x200); + Short anotherIpProto = Short.valueOf((short)(ipProto ^ 0x4)); + Short anotherIpDscp = Short.valueOf((short)(ipDscp ^ 0x10)); + + expectedTypes.add(srcType); + expectedTypes.add(dstType); + MatchParams params = new MatchParams(). + setEtherParams(eparams).setInet4Params(i4params). + setLayer4Params(l4params); + VTNMatch vmatch = params.toVTNMatch(); + assertEquals(true, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + // Ensure that the packet matches only if all conditions are met. + ctx.reset(); + eparams.setSourceAddress(anotherSrc); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC); + + ctx.reset(); + eparams.setSourceAddress(src.getAddress()). + setDestinationAddress(anotherDst); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST); + + // DL_TYPE condition cannot be changed because IPv4 condition + // will be configured. + ctx.reset(); + eparams.setDestinationAddress(dst.getAddress()). + setVlanId(anotherVlan); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + + + if (tagged) { + ctx.reset(); + eparams.setVlanId(Integer.valueOf(EtherHeader.VLAN_NONE)). + setVlanPriority((Short)null); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE); + } + + ctx.reset(); + eparams.setVlanId(Integer.valueOf(vlan)).setVlanPriority(anotherPcp); + vmatch = params.setEtherParams(eparams).toVTNMatch(); + if (tagged) { + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE, + FlowMatchType.DL_VLAN_PCP); + params.setEtherParams(eparams.setVlanPriority(Short.valueOf(pcp))); + } else { + assertEquals(true, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + } + + expectedTypes = EnumSet.of(FlowMatchType.DL_SRC, FlowMatchType.DL_DST, + FlowMatchType.DL_TYPE, FlowMatchType.IP_SRC); + if (tagged) { + expectedTypes.add(FlowMatchType.DL_VLAN_PCP); + } + + ctx.reset(); + i4params.setSourceNetwork(anotherIpSrc); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + ctx.reset(); + expectedTypes.add(FlowMatchType.IP_DST); + i4params.setSourceNetwork(ipSrc).setDestinationNetwork(anotherIpDst); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + // IP_PROTO condition cannot be changed because L4 condition will be + // configured. + ctx.reset(); + Collections.addAll(expectedTypes, FlowMatchType.IP_PROTO, + FlowMatchType.IP_DSCP); + i4params.setDestinationNetwork(ipDst).setDscp(anotherIpDscp); + vmatch = params.setInet4Params(i4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + params.setInet4Params(i4params.setDscp(Short.valueOf(ipDscp))); + + if (tparams != null) { + tparams.setSourcePortFrom(anotherSrcPort); + } else if (uparams != null) { + uparams.setSourcePortFrom(anotherSrcPort); + } else { + iparams.setType(anotherIcmpType); + } + ctx.reset(); + expectedTypes.add(srcType); + vmatch = params.setLayer4Params(l4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + + if (tparams != null) { + tparams.setSourcePortFrom(srcPort). + setDestinationPortFrom(anotherDstPort); + } else if (uparams != null) { + uparams.setSourcePortFrom(srcPort). + setDestinationPortFrom(anotherDstPort); + } else { + iparams.setType(icmpType).setCode(anotherIcmpCode); + } + ctx.reset(); + expectedTypes.add(dstType); + vmatch = params.setLayer4Params(l4params).toVTNMatch(); + assertEquals(false, vmatch.match(ctx)); + ctx.checkMatchFields(expectedTypes); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRangeTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRangeTest.java new file mode 100644 index 00000000..b6398ec0 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNPortRangeTest.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.PortMatch; + +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlDataType; +import org.opendaylight.vtn.manager.internal.XmlValueType; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.cond.rev150313.VtnPortRange; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; + +/** + * JUnit test for {@link VTNPortRange}. + */ +public class VTNPortRangeTest extends TestBase { + /** + * Root XML element name associated with {@link VTNPortRange} class. + */ + private static final String XML_ROOT = "vtn-port-range"; + + /** + * Return a list of {@link XmlValueType} instances that specifies XML node + * types mapped to a {@link VTNPortRange} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + List dlist = new ArrayList<>(); + Collections.addAll(dlist, + new XmlValueType("port-from", Integer.class). + add(name).prepend(parent), + new XmlValueType("port-to", Integer.class). + add(name).prepend(parent)); + return dlist; + } + + /** + * Test case for the following methods. + * + *
    + *
  • {@link VTNPortRange#create(PortMatch)}
  • + *
  • {@link VTNPortRange#create(VtnPortRange)}
  • + *
  • {@link VTNPortRange#create(PortNumber)}
  • + *
  • {@link VTNPortRange#toPortMatch(VTNPortRange)}
  • + *
  • {@link VTNPortRange#VTNPortRange(PortMatch)}
  • + *
  • {@link VTNPortRange#VTNPortRange(VtnPortRange)}
  • + *
  • {@link VTNPortRange#VTNPortRange(PortNumber)}
  • + *
  • Getter methods.
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testGetter() throws Exception { + assertEquals(null, VTNPortRange.create((PortMatch)null)); + assertEquals(null, VTNPortRange.create((VtnPortRange)null)); + assertEquals(null, VTNPortRange.create((PortNumber)null)); + + PortRangeParams[] ranges = { + new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 0), new PortRangeParams(0, 65535), + new PortRangeParams(1000, 1001), new PortRangeParams(333, 4444), + }; + + for (PortRangeParams range: ranges) { + PortMatch pm = range.toPortMatch(); + VTNPortRange vr = VTNPortRange.create(pm); + PortNumber pfrom = new PortNumber(pm.getPortFrom()); + PortNumber pto = new PortNumber(pm.getPortTo()); + assertEquals(pm.getPortFrom(), vr.getPortFrom()); + assertEquals(pm.getPortTo(), vr.getPortTo()); + assertEquals(pfrom, vr.getPortNumberFrom()); + assertEquals(pto, vr.getPortNumberTo()); + + VtnPortRange vpr = range.toTcpSourceRange(); + vr = VTNPortRange.create(vpr); + assertEquals(pm.getPortFrom(), vr.getPortFrom()); + assertEquals(pm.getPortTo(), vr.getPortTo()); + assertEquals(pfrom, vr.getPortNumberFrom()); + assertEquals(pto, vr.getPortNumberTo()); + + Integer port = range.getPortFrom(); + PortNumber pn = new PortNumber(port); + vr = VTNPortRange.create(pn); + assertEquals(port, vr.getPortFrom()); + assertEquals(port, vr.getPortTo()); + assertEquals(pn, vr.getPortNumberFrom()); + assertEquals(pn, vr.getPortNumberTo()); + } + + // port-from is missing. + ArrayList pmList = new ArrayList<>(); + ArrayList vprList = new ArrayList<>(); + PortRangeParams params = new PortRangeParams(); + pmList.add(params.setPortTo(0).toPortMatch()); + vprList.add(params.toTcpSourceRange()); + pmList.add(params.reset().setPortTo(0).toPortMatch()); + vprList.add(params.toTcpSourceRange()); + for (PortMatch pm: pmList) { + try { + new VTNPortRange(pm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", st.getDescription()); + } + } + for (VtnPortRange vpr: vprList) { + try { + new VTNPortRange(vpr); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", st.getDescription()); + } + } + + try { + new VTNPortRange((PortNumber)null); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", st.getDescription()); + } + + // Invalid port number. + int[] badPorts = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x1000, -999, -100, -10, -4, -3, -2, -1, + 0x10000, 0x10001, 0x4000000, 0x12345000, 0x70000000, + 0x7fff0000, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + for (int port: badPorts) { + pmList.clear(); + pmList.add(params.reset().setPortFrom(port).toPortMatch()); + pmList.add(params.reset().setPortFrom(0).setPortTo(port). + toPortMatch()); + for (PortMatch pm: pmList) { + try { + new VTNPortRange(pm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid port number: " + port, + st.getDescription()); + } + } + } + + // Invalid port range. + int[] ports = {1, 2, 3, 10, 50, 100, 2222, 5555, 10000, 34567, 65534}; + for (int port: ports) { + int from = port + 1; + int to = port; + PortMatch pm = params.reset().setPortFrom(from).setPortTo(to). + toPortMatch(); + try { + new VTNPortRange(pm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + + VtnPortRange vpr = params.toTcpSourceRange(); + try { + new VTNPortRange(vpr); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + + from = port; + to = 0; + pm = params.reset().setPortFrom(from).setPortTo(to).toPortMatch(); + try { + new VTNPortRange(pm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + + vpr = params.toTcpSourceRange(); + try { + new VTNPortRange(vpr); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + } + + /** + * Test case for {@link VTNPortRange#match(int)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + // Match to the specific port. + int port = 10000; + VTNPortRange vr = new VTNPortRange(new PortNumber(port)); + assertEquals(true, vr.match(port)); + for (int i = 0; i < port; i += 100) { + assertEquals(false, vr.match(i)); + } + for (int i = 1; i < 10000; i += 100) { + assertEquals(false, vr.match(port + i)); + } + + // Match to port numbers in the specified range. + int from = 100; + int to = 200; + PortRangeParams params = new PortRangeParams(from, to); + vr = new VTNPortRange(params.toPortMatch()); + for (int i = from; i <= to; i++) { + assertEquals(true, vr.match(i)); + } + for (int i = 0; i < from; i++) { + assertEquals(false, vr.match(i)); + } + for (int i = 1; i <= 100; i++) { + assertEquals(false, vr.match(to + i)); + } + } + + /** + * Test case for object identity. + * + *
    + *
  • {@link VTNPortRange#equals(Object)}
  • + *
  • {@link VTNPortRange#hashCode()}
  • + *
  • {@link VTNPortRange#setConditionKey(StringBuilder)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + PortRangeParams[] ranges = { + new PortRangeParams(0), new PortRangeParams(0, 1), + new PortRangeParams(0, 12345), + new PortRangeParams(100), new PortRangeParams(100, 200), + new PortRangeParams(100, 23456), + new PortRangeParams(12345), new PortRangeParams(12345, 13000), + new PortRangeParams(12345, 30000), + new PortRangeParams(32768), new PortRangeParams(32768, 44444), + new PortRangeParams(32768, 65535), + new PortRangeParams(44444), new PortRangeParams(44444, 54321), + new PortRangeParams(44444, 60000), + new PortRangeParams(65535), + }; + + StringBuilder b = new StringBuilder(); + for (PortRangeParams range: ranges) { + VTNPortRange vr1 = new VTNPortRange(range.toPortMatch()); + VTNPortRange vr2 = new VTNPortRange(range.toPortMatch()); + testEquals(set, vr1, vr2); + + b.setLength(0); + vr1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + vr2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + } + + assertEquals(ranges.length, set.size()); + assertEquals(ranges.length, keySet.size()); + } + + /** + * Test case for {@link VTNPortRange#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + Class type = VTNPortRange.class; + Unmarshaller um = createUnmarshaller(type); + Integer[] ports = { + 0, 1, 100, 2000, 30000, 65535, + }; + for (Integer from: ports) { + String xml = new XmlNode(XML_ROOT). + add(new XmlNode("port-from", from)).toString(); + VTNPortRange vr = unmarshal(um, xml, type); + vr.verify(); + assertEquals(from, vr.getPortFrom()); + assertEquals(from, vr.getPortTo()); + + xml = new XmlNode(XML_ROOT). + add(new XmlNode("port-from", from)). + add(new XmlNode("port-to", from)).toString(); + vr = unmarshal(um, xml, type); + vr.verify(); + assertEquals(from, vr.getPortFrom()); + assertEquals(from, vr.getPortTo()); + + int f = from.intValue(); + if (f != 65535) { + Integer[] toPorts = { + Integer.valueOf(f + 1), + Integer.valueOf(65535), + }; + for (Integer to: toPorts) { + xml = new XmlNode(XML_ROOT). + add(new XmlNode("port-from", from)). + add(new XmlNode("port-to", to)).toString(); + vr = unmarshal(um, xml, type); + vr.verify(); + assertEquals(from, vr.getPortFrom()); + assertEquals(to, vr.getPortTo()); + } + } + } + + // port-from is missing. + String[] missings = { + new XmlNode(XML_ROOT).toString(), + new XmlNode(XML_ROOT).add(new XmlNode("port-to", 10)).toString(), + }; + for (String xml: missings) { + VTNPortRange vr = unmarshal(um, xml, type); + try { + vr.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", st.getDescription()); + } + } + + // Invalid port range. + int[] testPorts = { + 1, 2, 3, 10, 50, 100, 2222, 5555, 10000, 34567, 65534 + }; + for (int port: testPorts) { + int from = port + 1; + int to = port; + String xml = new XmlNode(XML_ROOT). + add(new XmlNode("port-from", from)). + add(new XmlNode("port-to", to)).toString(); + VTNPortRange vr = unmarshal(um, xml, type); + try { + vr.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + + from = port; + to = 0; + xml = new XmlNode(XML_ROOT). + add(new XmlNode("port-from", from)). + add(new XmlNode("port-to", to)).toString(); + vr = unmarshal(um, xml, type); + try { + vr.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + + // Ensure that broken values in XML can be detected. + jaxbErrorTest(um, type, getXmlDataTypes(XML_ROOT)); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatchTest.java new file mode 100644 index 00000000..47671a37 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNTcpMatchTest.java @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.L4Match; +import org.opendaylight.vtn.manager.flow.cond.TcpMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.packet.TcpHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlDataType; + +import org.opendaylight.controller.sal.utils.IPProtocols; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * JUnit test for {@link VTNTcpMatch}. + */ +public class VTNTcpMatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNTcpMatch} class. + */ + private static final String XML_ROOT = "vtn-tcp-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNTcpMatch} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + String[] p = XmlDataType.addPath(name, parent); + String[] portTags = {"source-port", "destination-port"}; + ArrayList dlist = new ArrayList<>(); + for (String tag: portTags) { + dlist.addAll(VTNPortRangeTest.getXmlDataTypes(tag, p)); + } + + return dlist; + } + + /** + * Test case for constructors and getter methods. + * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor() throws Exception { + VTNTcpMatch empty = new VTNTcpMatch(); + assertEquals(null, empty.getSourcePort()); + assertEquals(null, empty.getDestinationPort()); + assertEquals(IPProtocols.TCP.shortValue(), + empty.getInetProtocol(IpVersion.Ipv4)); + assertEquals(IPProtocols.TCP.shortValue(), + empty.getInetProtocol(IpVersion.Ipv6)); + assertEquals(TcpHeader.class, empty.getHeaderType()); + assertEquals(FlowMatchType.TCP_SRC, empty.getSourceMatchType()); + assertEquals(FlowMatchType.TCP_DST, empty.getDestinationMatchType()); + + PortRangeParams[] srcs = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(12345), + new PortRangeParams(3, 45), + }; + PortRangeParams[] dsts = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(33333), + new PortRangeParams(1000, 5000), + }; + + TcpMatchParams params = new TcpMatchParams(); + for (PortRangeParams src: srcs) { + params.setSourcePortParams(src); + for (PortRangeParams dst: dsts) { + params.setDestinationPortParams(dst); + TcpMatch tm = params.toL4Match(); + VTNTcpMatch tmatch = new VTNTcpMatch(tm); + params.verify(tmatch); + assertEquals(tmatch, VTNLayer4Match.create(tm)); + } + } + + // port-from is missing. + ArrayList list = new ArrayList<>(); + params.reset().setSourcePortTo(Integer.valueOf(0)); + list.add(params.toL4Match()); + + params.reset().setDestinationPortTo(Integer.valueOf(0)); + list.add(params.toL4Match()); + for (TcpMatch tm: list) { + try { + new VTNTcpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", st.getDescription()); + } + } + + // Invalid port numbers. + Integer[] badPorts = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x1000, -100, -10, -3, -2, -1, + 0x10000, 0x10001, 0x4000000, 0x12345000, 0x70000000, + 0x7fff0000, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + for (Integer port: badPorts) { + params.reset().setSourcePortFrom(port); + list.clear(); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(port); + list.add(params.toL4Match()); + + params.reset().setSourcePortFrom(Integer.valueOf(0)). + setSourcePortTo(port); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(Integer.valueOf(0)). + setDestinationPortTo(port); + list.add(params.toL4Match()); + + for (TcpMatch tm: list) { + try { + new VTNTcpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid port number: " + port, + st.getDescription()); + } + } + } + + // Invalid port range. + int[] ports = {1, 2, 10, 3000, 4000, 5000, 33333, 65534}; + for (int port: ports) { + int from = port + 1; + int to = port; + list.clear(); + params.reset().setSourcePortFrom(Integer.valueOf(from)). + setSourcePortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(Integer.valueOf(from)). + setDestinationPortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + for (TcpMatch tm: list) { + try { + new VTNTcpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + + from = port; + to = 0; + list.clear(); + params.reset().setSourcePortFrom(Integer.valueOf(from)). + setSourcePortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(Integer.valueOf(from)). + setDestinationPortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + for (TcpMatch tm: list) { + try { + new VTNTcpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + } + + assertEquals(null, VTNLayer4Match.create((TcpMatch)null)); + assertEquals(null, VTNLayer4Match.create((L4Match)null)); + } + + /** + * Test case for object identify. + * + *
    + *
  • {@link VTNLayer4PortMatch#equals(Object)}
  • + *
  • {@link VTNLayer4PortMatch#hashCode()}
  • + *
  • {@link VTNLayer4PortMatch#setConditionKey(StringBuilder)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + PortRangeParams[] srcs = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(23456), + new PortRangeParams(17, 99), + }; + PortRangeParams[] dsts = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(4444), + new PortRangeParams(4444, 5000), + }; + + StringBuilder b = new StringBuilder(); + TcpMatchParams params = new TcpMatchParams(); + for (PortRangeParams src: srcs) { + params.setSourcePortParams(src); + for (PortRangeParams dst: dsts) { + params.setDestinationPortParams(dst); + VTNTcpMatch tmatch1 = params.toVTNLayer4Match(); + VTNTcpMatch tmatch2 = params.toVTNLayer4Match(); + testEquals(set, tmatch1, tmatch2); + + b.setLength(0); + tmatch1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + tmatch2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + } + } + + int count = srcs.length * dsts.length; + assertEquals(count, set.size()); + assertEquals(count, keySet.size()); + } + + /** + * Test case for {@link VTNLayer4PortMatch#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + PortRangeParams[] srcs = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(12345), + new PortRangeParams(3, 45), + }; + PortRangeParams[] dsts = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(33333), + new PortRangeParams(1000, 5000), + }; + + Class type = VTNTcpMatch.class; + Unmarshaller um = createUnmarshaller(type); + Unmarshaller um4 = createUnmarshaller(VTNLayer4Match.class); + TcpMatchParams params = new TcpMatchParams(); + for (PortRangeParams src: srcs) { + params.setSourcePortParams(src); + for (PortRangeParams dst: dsts) { + params.setDestinationPortParams(dst); + XmlNode root = new XmlNode(XML_ROOT); + if (src != null) { + root.add(src.toXmlNode("source-port")); + } + if (dst != null) { + root.add(dst.toXmlNode("destination-port")); + } + + String xml = root.toString(); + VTNTcpMatch tmatch = unmarshal(um, xml, type); + tmatch.verify(); + params.verify(tmatch); + + VTNTcpMatch tmatch1 = unmarshal(um4, xml, type); + tmatch1.verify(); + assertEquals(tmatch, tmatch1); + } + } + + // Invalid port numbers. + Integer[] badPorts = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x1000, -100, -10, -3, -2, -1, + 0x10000, 0x10001, 0x4000000, 0x12345000, 0x70000000, + 0x7fff0000, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + String[] portTags = {"source-port", "destination-port"}; + Unmarshaller[] unmarshallers = {um, um4}; + for (Integer port: badPorts) { + ArrayList badXmls = new ArrayList<>(); + for (String tag: portTags) { + PortRangeParams p = new PortRangeParams(port); + badXmls.add(new XmlNode(XML_ROOT).add(p.toXmlNode(tag))); + p.setPortFrom(1).setPortTo(port); + badXmls.add(new XmlNode(XML_ROOT).add(p.toXmlNode(tag))); + } + + for (XmlNode xn: badXmls) { + String xml = xn.toString(); + for (Unmarshaller u: unmarshallers) { + VTNTcpMatch tmatch = unmarshal(u, xml, type); + try { + tmatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid port number: " + port, + st.getDescription()); + } + } + } + } + + // port-from is missing. + for (String tag: portTags) { + XmlNode[] badXmls = { + new XmlNode(XML_ROOT).add(new XmlNode(tag)), + new XmlNode(XML_ROOT).add(new XmlNode(tag). + add(new XmlNode("port-to", 100))), + }; + for (XmlNode xn: badXmls) { + String xml = xn.toString(); + for (Unmarshaller u: unmarshallers) { + VTNTcpMatch tmatch = unmarshal(u, xml, type); + try { + tmatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, + e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", + st.getDescription()); + } + } + } + } + + // Invalid port range. + int[] ports = {1, 2, 10, 3000, 4000, 5000, 33333, 65534}; + for (int port: ports) { + int from = port + 1; + int to = port; + PortRangeParams p = new PortRangeParams(from, to); + ArrayList badXmls = new ArrayList<>(); + for (String tag: portTags) { + badXmls.add(new XmlNode(XML_ROOT).add(p.toXmlNode(tag))); + } + for (XmlNode xn: badXmls) { + String xml = xn.toString(); + for (Unmarshaller u: unmarshallers) { + VTNTcpMatch tmatch = unmarshal(u, xml, type); + try { + tmatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + } + } + + // Ensure that broken values in XML can be detected. + List dlist = getXmlDataTypes(XML_ROOT); + for (Unmarshaller u: unmarshallers) { + jaxbErrorTest(u, type, dlist); + } + } + + /** + * Test case for {@link VTNLayer4PortMatch#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + int srcPort = 45678; + int dstPort = 12345; + TcpMatchParams header = new TcpMatchParams(); + header.setSourcePort(srcPort); + header.setDestinationPort(dstPort); + TestMatchContext ctx = new TestMatchContext().setLayer4Header(header); + + // Empty match should match every TCP packet. + VTNTcpMatch tmatch = new VTNTcpMatch(); + assertEquals(true, tmatch.match(ctx)); + ctx.checkMatchFields(); + + PortRangeParams[] srcs = { + new PortRangeParams(srcPort), + new PortRangeParams(srcPort - 100, srcPort), + new PortRangeParams(srcPort, srcPort + 100), + new PortRangeParams(srcPort - 100, srcPort), + new PortRangeParams(srcPort - 100, srcPort + 100), + }; + PortRangeParams[] dsts = { + new PortRangeParams(dstPort), + new PortRangeParams(dstPort - 200, dstPort), + new PortRangeParams(dstPort, dstPort + 200), + new PortRangeParams(dstPort - 200, dstPort), + new PortRangeParams(dstPort - 200, dstPort + 200), + }; + + for (PortRangeParams src: srcs) { + for (PortRangeParams dst: dsts) { + matchTest(ctx, src, dst); + } + } + } + + /** + * Run tests for {@link VTNLayer4PortMatch#match(FlowMatchContext)}. + * + * @param ctx A {@link TestMatchContext} instance that contains the + * TCP header. + * @param src A {@link PortRangeParams} instance that represents the + * condition for the source port. + * @param dst A {@link PortRangeParams} instance that represents the + * condition for the destination port. + * @throws Exception An error occurred. + */ + private void matchTest(TestMatchContext ctx, PortRangeParams src, + PortRangeParams dst) throws Exception { + Layer4Header l4 = ctx.getLayer4Header(); + assertTrue(l4 instanceof TcpHeader); + TcpHeader l4head = (TcpHeader)l4; + int srcPort = l4head.getSourcePort(); + int dstPort = l4head.getDestinationPort(); + + // Specify single field in TCP header. + ctx.reset(); + TcpMatchParams params = new TcpMatchParams(); + params.setSourcePortParams(src); + VTNTcpMatch tmatch = params.toVTNLayer4Match(); + assertEquals(true, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC); + + ctx.reset(); + params.reset().setDestinationPortParams(dst); + tmatch = params.toVTNLayer4Match(); + assertEquals(true, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_DST); + + // Specify all fields. + ctx.reset(); + params.setSourcePortParams(src); + tmatch = params.toVTNLayer4Match(); + assertEquals(true, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC, FlowMatchType.TCP_DST); + + // TCP match should not match to a non-TCP packet. + Layer4Header[] anotherL4 = { + null, + new UdpMatchParams().setSourcePortFrom(l4head.getSourcePort()). + setDestinationPortFrom(l4head.getDestinationPort()), + new IcmpMatchParams((short)(srcPort & 0xff), + (short)(dstPort & 0xff)), + }; + for (Layer4Header h: anotherL4) { + ctx.reset(); + ctx.setLayer4Header(h); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(); + } + + ctx.setLayer4Header(l4head); + assertEquals(true, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC, FlowMatchType.TCP_DST); + + // Ensure match() returns false if one field does not match. + int port = srcPort - 1; + ctx.reset(); + params.setSourcePortFrom(port).setSourcePortTo(null); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC); + + ctx.reset(); + params.setSourcePortFrom(0).setSourcePortTo(port); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC); + + port = srcPort + 1; + ctx.reset(); + params.setSourcePortFrom(port).setSourcePortTo(null); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC); + + ctx.reset(); + params.setSourcePortTo(65535); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC); + + port = dstPort - 1; + ctx.reset(); + params.setSourcePortParams(src).setDestinationPortFrom(port). + setDestinationPortTo(null); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC, FlowMatchType.TCP_DST); + + ctx.reset(); + params.setDestinationPortFrom(0).setDestinationPortTo(port); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC, FlowMatchType.TCP_DST); + + port = dstPort + 1; + ctx.reset(); + params.setDestinationPortFrom(port).setDestinationPortTo(null); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC, FlowMatchType.TCP_DST); + + ctx.reset(); + params.setDestinationPortTo(65535); + tmatch = params.toVTNLayer4Match(); + assertEquals(false, tmatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.TCP_SRC, FlowMatchType.TCP_DST); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatchTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatchTest.java new file mode 100644 index 00000000..3cc846b3 --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/flow/match/VTNUdpMatchTest.java @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.flow.match; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import javax.xml.bind.Unmarshaller; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.flow.cond.L4Match; +import org.opendaylight.vtn.manager.flow.cond.UdpMatch; + +import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header; +import org.opendaylight.vtn.manager.internal.util.packet.UdpHeader; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcException; + +import org.opendaylight.vtn.manager.internal.TestBase; +import org.opendaylight.vtn.manager.internal.XmlNode; +import org.opendaylight.vtn.manager.internal.XmlDataType; + +import org.opendaylight.controller.sal.utils.IPProtocols; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; + +/** + * JUnit test for {@link VTNUdpMatch}. + */ +public class VTNUdpMatchTest extends TestBase { + /** + * Root XML element name associated with {@link VTNUdpMatch} class. + */ + private static final String XML_ROOT = "vtn-udp-match"; + + /** + * Return a list of {@link XmlDataType} instances that specifies XML node + * types mapped to a {@link VTNUdpMatch} instance. + * + * @param name The name of the target node. + * @param parent Path to the parent node. + * @return A list of {@link XmlDataType} instances. + */ + public static List getXmlDataTypes(String name, + String ... parent) { + String[] p = XmlDataType.addPath(name, parent); + String[] portTags = {"source-port", "destination-port"}; + ArrayList dlist = new ArrayList<>(); + for (String tag: portTags) { + dlist.addAll(VTNPortRangeTest.getXmlDataTypes(tag, p)); + } + + return dlist; + } + + /** + * Test case for constructors and getter methods. + * + * @throws Exception An error occurred. + */ + @Test + public void testConstructor() throws Exception { + VTNUdpMatch empty = new VTNUdpMatch(); + assertEquals(null, empty.getSourcePort()); + assertEquals(null, empty.getDestinationPort()); + assertEquals(IPProtocols.UDP.shortValue(), + empty.getInetProtocol(IpVersion.Ipv4)); + assertEquals(IPProtocols.UDP.shortValue(), + empty.getInetProtocol(IpVersion.Ipv6)); + assertEquals(UdpHeader.class, empty.getHeaderType()); + assertEquals(FlowMatchType.UDP_SRC, empty.getSourceMatchType()); + assertEquals(FlowMatchType.UDP_DST, empty.getDestinationMatchType()); + + PortRangeParams[] srcs = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(12345), + new PortRangeParams(3, 45), + }; + PortRangeParams[] dsts = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(33333), + new PortRangeParams(1000, 5000), + }; + + UdpMatchParams params = new UdpMatchParams(); + for (PortRangeParams src: srcs) { + params.setSourcePortParams(src); + for (PortRangeParams dst: dsts) { + params.setDestinationPortParams(dst); + UdpMatch um = params.toL4Match(); + VTNUdpMatch umatch = new VTNUdpMatch(um); + params.verify(umatch); + assertEquals(umatch, VTNLayer4Match.create(um)); + } + } + + // port-from is missing. + ArrayList list = new ArrayList<>(); + params.reset().setSourcePortTo(Integer.valueOf(0)); + list.add(params.toL4Match()); + + params.reset().setDestinationPortTo(Integer.valueOf(0)); + list.add(params.toL4Match()); + for (UdpMatch tm: list) { + try { + new VTNUdpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", st.getDescription()); + } + } + + // Invalid port numbers. + Integer[] badPorts = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x1000, -100, -10, -3, -2, -1, + 0x10000, 0x10001, 0x4000000, 0x12345000, 0x70000000, + 0x7fff0000, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + for (Integer port: badPorts) { + params.reset().setSourcePortFrom(port); + list.clear(); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(port); + list.add(params.toL4Match()); + + params.reset().setSourcePortFrom(Integer.valueOf(0)). + setSourcePortTo(port); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(Integer.valueOf(0)). + setDestinationPortTo(port); + list.add(params.toL4Match()); + + for (UdpMatch tm: list) { + try { + new VTNUdpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid port number: " + port, + st.getDescription()); + } + } + } + + // Invalid port range. + int[] ports = {1, 2, 10, 3000, 4000, 5000, 33333, 65534}; + for (int port: ports) { + int from = port + 1; + int to = port; + list.clear(); + params.reset().setSourcePortFrom(Integer.valueOf(from)). + setSourcePortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(Integer.valueOf(from)). + setDestinationPortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + for (UdpMatch tm: list) { + try { + new VTNUdpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + + from = port; + to = 0; + list.clear(); + params.reset().setSourcePortFrom(Integer.valueOf(from)). + setSourcePortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + + params.reset().setDestinationPortFrom(Integer.valueOf(from)). + setDestinationPortTo(Integer.valueOf(to)); + list.add(params.toL4Match()); + for (UdpMatch tm: list) { + try { + new VTNUdpMatch(tm); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + } + + assertEquals(null, VTNLayer4Match.create((UdpMatch)null)); + assertEquals(null, VTNLayer4Match.create((L4Match)null)); + } + + /** + * Test case for object identify. + * + *
    + *
  • {@link VTNLayer4PortMatch#equals(Object)}
  • + *
  • {@link VTNLayer4PortMatch#hashCode()}
  • + *
  • {@link VTNLayer4PortMatch#setConditionKey(StringBuilder)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEquals() throws Exception { + HashSet set = new HashSet<>(); + HashSet keySet = new HashSet<>(); + + PortRangeParams[] srcs = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(23456), + new PortRangeParams(17, 99), + }; + PortRangeParams[] dsts = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(4444), + new PortRangeParams(4444, 5000), + }; + + StringBuilder b = new StringBuilder(); + UdpMatchParams params = new UdpMatchParams(); + for (PortRangeParams src: srcs) { + params.setSourcePortParams(src); + for (PortRangeParams dst: dsts) { + params.setDestinationPortParams(dst); + VTNUdpMatch umatch1 = params.toVTNLayer4Match(); + VTNUdpMatch umatch2 = params.toVTNLayer4Match(); + testEquals(set, umatch1, umatch2); + + b.setLength(0); + umatch1.setConditionKey(b); + assertEquals(true, keySet.add(b.toString())); + b.setLength(0); + umatch2.setConditionKey(b); + assertEquals(false, keySet.add(b.toString())); + } + } + + int count = srcs.length * dsts.length; + assertEquals(count, set.size()); + assertEquals(count, keySet.size()); + } + + /** + * Test case for {@link VTNLayer4PortMatch#verify()} and JAXB mapping. + * + * @throws Exception An error occurred. + */ + @Test + public void testJAXB() throws Exception { + // Normal case. + PortRangeParams[] srcs = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(12345), + new PortRangeParams(3, 45), + }; + PortRangeParams[] dsts = { + null, new PortRangeParams(0), new PortRangeParams(65535), + new PortRangeParams(0, 65535), new PortRangeParams(33333), + new PortRangeParams(1000, 5000), + }; + + Class type = VTNUdpMatch.class; + Unmarshaller um = createUnmarshaller(type); + Unmarshaller um4 = createUnmarshaller(VTNLayer4Match.class); + UdpMatchParams params = new UdpMatchParams(); + for (PortRangeParams src: srcs) { + params.setSourcePortParams(src); + for (PortRangeParams dst: dsts) { + params.setDestinationPortParams(dst); + XmlNode root = new XmlNode(XML_ROOT); + if (src != null) { + root.add(src.toXmlNode("source-port")); + } + if (dst != null) { + root.add(dst.toXmlNode("destination-port")); + } + + String xml = root.toString(); + VTNUdpMatch umatch = unmarshal(um, xml, type); + umatch.verify(); + params.verify(umatch); + + VTNUdpMatch umatch1 = unmarshal(um4, xml, type); + umatch1.verify(); + assertEquals(umatch, umatch1); + } + } + + // Invalid port numbers. + Integer[] badPorts = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -0x70000000, + -0x10000000, -0x1000, -100, -10, -3, -2, -1, + 0x10000, 0x10001, 0x4000000, 0x12345000, 0x70000000, + 0x7fff0000, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, + }; + String[] portTags = {"source-port", "destination-port"}; + Unmarshaller[] unmarshallers = {um, um4}; + for (Integer port: badPorts) { + ArrayList badXmls = new ArrayList<>(); + for (String tag: portTags) { + PortRangeParams p = new PortRangeParams(port); + badXmls.add(new XmlNode(XML_ROOT).add(p.toXmlNode(tag))); + p.setPortFrom(1).setPortTo(port); + badXmls.add(new XmlNode(XML_ROOT).add(p.toXmlNode(tag))); + } + + for (XmlNode xn: badXmls) { + String xml = xn.toString(); + for (Unmarshaller u: unmarshallers) { + VTNUdpMatch umatch = unmarshal(u, xml, type); + try { + umatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("Invalid port number: " + port, + st.getDescription()); + } + } + } + } + + // port-from is missing. + for (String tag: portTags) { + XmlNode[] badXmls = { + new XmlNode(XML_ROOT).add(new XmlNode(tag)), + new XmlNode(XML_ROOT).add(new XmlNode(tag). + add(new XmlNode("port-to", 100))), + }; + for (XmlNode xn: badXmls) { + String xml = xn.toString(); + for (Unmarshaller u: unmarshallers) { + VTNUdpMatch umatch = unmarshal(u, xml, type); + try { + umatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.MISSING_ELEMENT, + e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + assertEquals("port-from cannot be null", + st.getDescription()); + } + } + } + } + + // Invalid port range. + int[] ports = {1, 2, 10, 3000, 4000, 5000, 33333, 65534}; + for (int port: ports) { + int from = port + 1; + int to = port; + PortRangeParams p = new PortRangeParams(from, to); + ArrayList badXmls = new ArrayList<>(); + for (String tag: portTags) { + badXmls.add(new XmlNode(XML_ROOT).add(p.toXmlNode(tag))); + } + for (XmlNode xn: badXmls) { + String xml = xn.toString(); + for (Unmarshaller u: unmarshallers) { + VTNUdpMatch umatch = unmarshal(u, xml, type); + try { + umatch.verify(); + unexpected(); + } catch (RpcException e) { + assertEquals(RpcErrorTag.BAD_ELEMENT, e.getErrorTag()); + Status st = e.getStatus(); + assertEquals(StatusCode.BADREQUEST, st.getCode()); + String msg = "Invalid port range: from=" + from + + ", to=" + to; + assertEquals(msg, st.getDescription()); + } + } + } + } + + // Ensure that broken values in XML can be detected. + List dlist = getXmlDataTypes(XML_ROOT); + for (Unmarshaller u: unmarshallers) { + jaxbErrorTest(u, type, dlist); + } + } + + /** + * Test case for {@link VTNLayer4PortMatch#match(FlowMatchContext)}. + * + * @throws Exception An error occurred. + */ + @Test + public void testMatch() throws Exception { + int srcPort = 45678; + int dstPort = 12345; + UdpMatchParams header = new UdpMatchParams(); + header.setSourcePort(srcPort); + header.setDestinationPort(dstPort); + TestMatchContext ctx = new TestMatchContext().setLayer4Header(header); + + // Empty match should match every UDP packet. + VTNUdpMatch umatch = new VTNUdpMatch(); + assertEquals(true, umatch.match(ctx)); + ctx.checkMatchFields(); + + PortRangeParams[] srcs = { + new PortRangeParams(srcPort), + new PortRangeParams(srcPort - 100, srcPort), + new PortRangeParams(srcPort, srcPort + 100), + new PortRangeParams(srcPort - 100, srcPort), + new PortRangeParams(srcPort - 100, srcPort + 100), + }; + PortRangeParams[] dsts = { + new PortRangeParams(dstPort), + new PortRangeParams(dstPort - 200, dstPort), + new PortRangeParams(dstPort, dstPort + 200), + new PortRangeParams(dstPort - 200, dstPort), + new PortRangeParams(dstPort - 200, dstPort + 200), + }; + + for (PortRangeParams src: srcs) { + for (PortRangeParams dst: dsts) { + matchTest(ctx, src, dst); + } + } + } + + /** + * Run tests for {@link VTNLayer4PortMatch#match(FlowMatchContext)}. + * + * @param ctx A {@link TestMatchContext} instance that contains the + * UDP header. + * @param src A {@link PortRangeParams} instance that represents the + * condition for the source port. + * @param dst A {@link PortRangeParams} instance that represents the + * condition for the destination port. + * @throws Exception An error occurred. + */ + private void matchTest(TestMatchContext ctx, PortRangeParams src, + PortRangeParams dst) throws Exception { + Layer4Header l4 = ctx.getLayer4Header(); + assertTrue(l4 instanceof UdpHeader); + UdpHeader l4head = (UdpHeader)l4; + int srcPort = l4head.getSourcePort(); + int dstPort = l4head.getDestinationPort(); + + // Specify single field in UDP header. + ctx.reset(); + UdpMatchParams params = new UdpMatchParams(); + params.setSourcePortParams(src); + VTNUdpMatch umatch = params.toVTNLayer4Match(); + assertEquals(true, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC); + + ctx.reset(); + params.reset().setDestinationPortParams(dst); + umatch = params.toVTNLayer4Match(); + assertEquals(true, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_DST); + + // Specify all fields. + ctx.reset(); + params.setSourcePortParams(src); + umatch = params.toVTNLayer4Match(); + assertEquals(true, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC, FlowMatchType.UDP_DST); + + // UDP match should not match to a non-UDP packet. + Layer4Header[] anotherL4 = { + null, + new TcpMatchParams().setSourcePortFrom(l4head.getSourcePort()). + setDestinationPortFrom(l4head.getDestinationPort()), + new IcmpMatchParams((short)(srcPort & 0xff), + (short)(dstPort & 0xff)), + }; + for (Layer4Header h: anotherL4) { + ctx.reset(); + ctx.setLayer4Header(h); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(); + } + + ctx.setLayer4Header(l4head); + assertEquals(true, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC, FlowMatchType.UDP_DST); + + // Ensure match() returns false if one field does not match. + int port = srcPort - 1; + ctx.reset(); + params.setSourcePortFrom(port).setSourcePortTo(null); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC); + + ctx.reset(); + params.setSourcePortFrom(0).setSourcePortTo(port); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC); + + port = srcPort + 1; + ctx.reset(); + params.setSourcePortFrom(port).setSourcePortTo(null); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC); + + ctx.reset(); + params.setSourcePortTo(65535); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC); + + port = dstPort - 1; + ctx.reset(); + params.setSourcePortParams(src).setDestinationPortFrom(port). + setDestinationPortTo(null); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC, FlowMatchType.UDP_DST); + + ctx.reset(); + params.setDestinationPortFrom(0).setDestinationPortTo(port); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC, FlowMatchType.UDP_DST); + + port = dstPort + 1; + ctx.reset(); + params.setDestinationPortFrom(port).setDestinationPortTo(null); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC, FlowMatchType.UDP_DST); + + ctx.reset(); + params.setDestinationPortTo(65535); + umatch = params.toVTNLayer4Match(); + assertEquals(false, umatch.match(ctx)); + ctx.checkMatchFields(FlowMatchType.UDP_SRC, FlowMatchType.UDP_DST); + } +} diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilderTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilderTest.java new file mode 100644 index 00000000..f3275efe --- /dev/null +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilderTest.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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.vtn.manager.internal.util.packet; + +import java.net.InetAddress; + +import org.junit.Test; + +import org.opendaylight.vtn.manager.util.EtherAddress; +import org.opendaylight.vtn.manager.util.Ip4Network; + +import org.opendaylight.vtn.manager.internal.TestBase; + +import org.opendaylight.controller.sal.packet.ARP; +import org.opendaylight.controller.sal.packet.Ethernet; +import org.opendaylight.controller.sal.packet.IEEE8021Q; +import org.opendaylight.controller.sal.packet.Packet; +import org.opendaylight.controller.sal.utils.EtherTypes; + +/** + * JUnit test for {@link ArpPacketBuilder}. + */ +public class ArpPacketBuilderTest extends TestBase { + /** + * Ensure that an ARP packet can be built without changing parameters. + * + * @throws Exception An error occurred. + */ + @Test + public void testDefault() throws Exception { + EtherAddress src = new EtherAddress(0x001122aabbccL); + EtherAddress dst = EtherAddress.BROADCAST; + InetAddress target = InetAddress.getByName("10.1.2.3"); + InetAddress ip6 = InetAddress.getByName("::1"); + Ip4Network spa = new Ip4Network(0); + Ip4Network tpa = new Ip4Network(target); + ArpPacketBuilder builder = new ArpPacketBuilder(); + Ethernet ether = builder.build(src, target); + verify(ether, src, dst, spa, tpa, ARP.REQUEST, 0); + assertEquals(null, builder.build(src, ip6)); + + dst = new EtherAddress(0x0123456789abL); + ether = builder.build(src, dst, target); + verify(ether, src, dst, spa, tpa, ARP.REQUEST, 0); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, dst, tpa); + verify(ether, src, dst, spa, tpa, ARP.REQUEST, 0); + assertEquals(null, builder.build(src, ip6)); + } + + /** + * Ensure that an ARP packet can be build with changing parameters. + * + * @throws Exception An error occurred. + */ + @Test + public void testParameters() throws Exception { + EtherAddress src = new EtherAddress(0xa0b1c2d3e4f5L); + EtherAddress dst = new EtherAddress(0xffffaaaabbbbL); + EtherAddress bcast = EtherAddress.BROADCAST; + InetAddress target = InetAddress.getByName("192.168.100.200"); + Ip4Network tpa = new Ip4Network(target); + Ip4Network spa = new Ip4Network("192.168.100.254"); + Ip4Network spaZero = new Ip4Network(0); + InetAddress ip6 = InetAddress.getByName("::1"); + int[] vlanIds = { + 0, 1, 2, 4094, 4095, + }; + short[] opCodes = { + ARP.REQUEST, ARP.REPLY, + }; + for (int vid: vlanIds) { + ArpPacketBuilder builder = new ArpPacketBuilder(vid); + Ethernet ether = builder.build(src, target); + verify(ether, src, bcast, spaZero, tpa, ARP.REQUEST, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, bcast, target); + verify(ether, src, bcast, spaZero, tpa, ARP.REQUEST, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, bcast, tpa); + verify(ether, src, bcast, spaZero, tpa, ARP.REQUEST, vid); + assertEquals(null, builder.build(src, ip6)); + + builder.setSenderProtocolAddress(spa); + ether = builder.build(src, target); + verify(ether, src, bcast, spa, tpa, ARP.REQUEST, vid); + assertEquals(null, builder.build(src, ip6)); + + dst = new EtherAddress(0x0123456789abL); + ether = builder.build(src, dst, target); + verify(ether, src, dst, spa, tpa, ARP.REQUEST, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, dst, tpa); + verify(ether, src, dst, spa, tpa, ARP.REQUEST, vid); + assertEquals(null, builder.build(src, ip6)); + + for (short op: opCodes) { + builder = new ArpPacketBuilder(vid, op); + ether = builder.build(src, target); + verify(ether, src, bcast, spaZero, tpa, op, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, bcast, target); + verify(ether, src, bcast, spaZero, tpa, op, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, bcast, tpa); + verify(ether, src, bcast, spaZero, tpa, op, vid); + assertEquals(null, builder.build(src, ip6)); + + builder.setSenderProtocolAddress(spa); + ether = builder.build(src, target); + verify(ether, src, bcast, spa, tpa, op, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, dst, target); + verify(ether, src, dst, spa, tpa, op, vid); + assertEquals(null, builder.build(src, ip6)); + + ether = builder.build(src, dst, tpa); + verify(ether, src, dst, spa, tpa, op, vid); + assertEquals(null, builder.build(src, ip6)); + } + } + } + + /** + * Verify the given ARP packet. + * + * @param ether An {@link Ethernet} instance that contains an ARP + * message. + * @param src The expected source MAC address. + * @param dst The expected destination MAC address. + * @param sender The expected sender protocol address. + * @param target The expected target protocol address. + * @param op The expected ARP operation code. + * @param vid The expected VLAN ID. + */ + private void verify(Ethernet ether, EtherAddress src, EtherAddress dst, + Ip4Network sender, Ip4Network target, short op, + int vid) { + assertArrayEquals(src.getBytes(), ether.getSourceMACAddress()); + assertArrayEquals(dst.getBytes(), ether.getDestinationMACAddress()); + short ethType = ether.getEtherType(); + Packet payload = ether.getPayload(); + if (vid != 0) { + assertEquals(EtherTypes.VLANTAGGED.shortValue(), ethType); + assertTrue(payload instanceof IEEE8021Q); + IEEE8021Q tag = (IEEE8021Q)payload; + byte zero = 0; + assertEquals(zero, tag.getCfi()); + assertEquals(zero, tag.getPcp()); + assertEquals((short)vid, tag.getVid()); + ethType = tag.getEtherType(); + payload = tag.getPayload(); + } + + assertEquals(EtherTypes.ARP.shortValue(), ethType); + assertTrue(payload instanceof ARP); + ARP arp = (ARP)payload; + + byte[] tha = (dst.equals(EtherAddress.BROADCAST)) + ? new byte[6] : dst.getBytes(); + assertEquals(ARP.HW_TYPE_ETHERNET, arp.getHardwareType()); + assertEquals(EtherTypes.IPv4.shortValue(), arp.getProtocolType()); + assertEquals((byte)6, arp.getHardwareAddressLength()); + assertEquals((byte)4, arp.getProtocolAddressLength()); + assertEquals(op, arp.getOpCode()); + assertArrayEquals(src.getBytes(), arp.getSenderHardwareAddress()); + assertArrayEquals(tha, arp.getTargetHardwareAddress()); + assertArrayEquals(sender.getBytes(), arp.getSenderProtocolAddress()); + assertArrayEquals(target.getBytes(), arp.getTargetProtocolAddress()); + } +} diff --git a/manager/implementation/src/test/resources/logback.xml b/manager/implementation/src/test/resources/logback.xml index 208ff1b0..19ae8321 100644 --- a/manager/implementation/src/test/resources/logback.xml +++ b/manager/implementation/src/test/resources/logback.xml @@ -36,6 +36,10 @@ level="ERROR"/> + + diff --git a/manager/model/pom.xml b/manager/model/pom.xml index 12064946..6004aa78 100644 --- a/manager/model/pom.xml +++ b/manager/model/pom.xml @@ -64,6 +64,24 @@ org.opendaylight.yangtools.model ietf-yang-types + + org.opendaylight.yangtools.model + opendaylight-l2-types + + + org.opendaylight.yangtools.model + ietf-inet-types + + + + + org.opendaylight.openflowplugin.model + model-flow-base + + + org.opendaylight.openflowplugin.model + model-flow-statistics + diff --git a/manager/model/src/main/yang/vtn-config.yang b/manager/model/src/main/yang/vtn-config.yang index bd5beba4..c8be68bd 100644 --- a/manager/model/src/main/yang/vtn-config.yang +++ b/manager/model/src/main/yang/vtn-config.yang @@ -12,6 +12,7 @@ module vtn-config { namespace "urn:opendaylight:vtn:config"; prefix vconf; + /* OpenDaylight yangtools */ import ietf-yang-types { prefix yang; revision-date 2010-09-24; diff --git a/manager/model/src/main/yang/vtn-flow-condition.yang b/manager/model/src/main/yang/vtn-flow-condition.yang new file mode 100644 index 00000000..367c86b4 --- /dev/null +++ b/manager/model/src/main/yang/vtn-flow-condition.yang @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2015 NEC Corporation + * 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 + */ + +module vtn-flow-condition { + yang-version 1; + namespace "urn:opendaylight:vtn:flow:cond"; + prefix vfcond; + + import vtn-types { + prefix vtype; + revision-date 2015-02-09; + } + + /* OpenDaylight yangtools */ + import opendaylight-l2-types { + prefix l2; + revision-date 2013-08-27; + } + import ietf-yang-types { + prefix yang; + revision-date 2010-09-24; + } + import ietf-inet-types { + prefix inet; + revision-date 2010-09-24; + } + + description + "The module that describes the flow condition to match against packets."; + + revision 2015-03-13 { + description "Initial revision."; + } + + grouping vtn-ether-match-fields { + description + "Describes the ethernet header and IEEE 802.1Q VLAN tag fields + to match against packets."; + + leaf source-address { + description "The source MAC address."; + type yang:mac-address; + } + + leaf destination-address { + description "The destination MAC address."; + type yang:mac-address; + } + + leaf ether-type { + description "The ethernet type."; + type l2:ether-type; + } + + leaf vlan-id { + description + "The VLAN ID in VLAN tag. + Zero means untagged ethernet frame."; + type l2:vlan-id; + } + + leaf vlan-pcp { + description "The VLAN priority in VLAN tag."; + type l2:vlan-pcp; + } + } + + grouping vtn-inet-match-fields { + description + "Describes the IP header fields to match against packets."; + + leaf source-network { + description + "The IP network to match the source IP address. + Currently, it is possible to configure only an IPv4 address."; + type inet:ip-prefix; + } + + leaf destination-network { + description + "The IP network to match the destination IP address. + Currently, it is possible to configure only an IPv4 address."; + type inet:ip-prefix; + } + + leaf protocol { + description "The IP protocol number."; + type uint8; + } + + leaf dscp { + description "The IP DSCP field value."; + type inet:dscp; + } + } + + grouping vtn-port-range { + description + "Describes the range of IP transport layer protocol such as TCP."; + + leaf port-from { + description + "The minimum value (inclusive) in the range of port numbers + to match against packets."; + type inet:port-number; + mandatory true; + } + + leaf port-to { + description + "The maximum value (inclusive) in the range of port numbers + to match against packets. + The value must be greater than or equal to the value specified + to `port-from' field. If this field is omitted, it will be + treated as the port number specified to `port-from' field is + specified."; + type inet:port-number; + } + } + + grouping vtn-tcp-match-fields { + description "Describes the range of TCP port numbers."; + + container tcp-source-range { + description "The range of TCP source port number."; + uses vtn-port-range; + } + + container tcp-destination-range { + description "The range of TCP destination port number."; + uses vtn-port-range; + } + } + + grouping vtn-udp-match-fields { + description "Describes the range of UDP port numbers."; + + container udp-source-range { + description "The range of UDP source port number."; + uses vtn-port-range; + } + + container udp-destination-range { + description "The range of UDP destination port number."; + uses vtn-port-range; + } + } + + grouping vtn-icmp-match-fields { + description + "Describes the ICMP header fields to match against packets."; + + leaf type { + description "The ICMP type."; + type uint8; + } + + leaf code { + description "The ICMP code."; + type uint8; + } + } + + grouping vtn-match-fields { + description + "Describes the configuration for a VTN flow match that specifies + the condition to match against packets."; + + container vtn-ether-match { + description + "The flow condition to match against Ethernet header."; + uses vtn-ether-match-fields; + } + + container vtn-inet-match { + description + "The flow condition to match against IP header."; + uses vtn-inet-match-fields; + } + + choice vtn-layer4-match { + description + "The flow condition to match layer 4 protocol header."; + + case vtn-tcp-match { + uses vtn-tcp-match-fields; + } + case vtn-udp-match { + uses vtn-udp-match-fields; + } + case vtn-icmp-match { + uses vtn-icmp-match-fields; + } + } + } + + grouping vtn-flow-match-config { + description + "Describes the configuration for a VTN flow match in a VTN flow + condition."; + + uses vtype:vtn-index; + uses vtn-match-fields; + } + + grouping vtn-flow-cond-config { + description + "Describes the configuration for a VTN flow condition."; + + leaf name { + description "The name of the flow condition."; + type vtype:vnode-name; + } + + list vtn-flow-match { + description + "A list of conditions to match against packets. + Each element in this list needs to have a unique index value + in `index' field. If more than one match elements are + configured, they are evaluated against packets in ascending + order of `index' value in each match element. Packets which + matches the condition described by at least one match element + are selected by this flow condition. + + Every packet is selected if this element is omitted or empty."; + key "index"; + uses vtn-flow-match-config; + } + } + + container vtn-flow-conditions { + description + "The root container of all the flow condition configuratins. + Note that the flow condition configuration must be modified by RPC. + Do not edit this container directly."; + config false; + presence + "Indicates that the flow condition management is active."; + + list vtn-flow-condition { + description + "A list of flow conditions shared with all VTNs."; + key "name"; + uses vtn-flow-cond-config; + } + } + + /* + * RPC definitions + */ + + grouping vtn-flow-match-result { + description + "Describes a pair of VTN flow match index and `vtn-update-type'. + + This grouping is used as output of RPC that modifies the VTN flow + match configuration in a flow condition."; + + uses vtype:vtn-index; + uses vtype:vtn-rpc-result; + } + + rpc set-flow-condition { + description + "Create or modify the flow condition. + + If the flow condition specified by the name does not exist, a new + flow condition will be associated with the specified name. + If the flow condition specifie dby the name already exists, + it will be modified as specified the RPC input. + + `status' in RPC output descripts the result of the operation. + + CREATED indicates that the specified flow condition has been newly + created. + + CHANGED indicates that existing flow condition configuraiton has + been successfully changed. + + Null indicates that existing flow condition configuration has not + been changed. + + On failure, one of vtn-error-tag value which indicates the cause + of error is set into application tag in RPC error. + + `BADREQUEST' is set if the RPC input contains invalid data. + + `NOTFOUND' is set if true is set to `present' field in the RPC + input and the target flow condition is not present. + + `INTERNALERROR' is set if the operation failed due to internal + error."; + + input { + uses vtn-flow-cond-config; + + leaf operation { + description + "Describes how to update the specified flow condition if it + already exists. + + If SET is specified, the given flow condition configuration + will be applied as specified. In other words, existing + flow condition configuration will be removed, and the given + flow condition will be created. + + If ADD is specified, the given flow condition configuration + will be merged with existing configuration. The target + flow condition will be created if it is not present. + + Null will be treated as if ADD is specified. + + Note that the operation will fail if true is set to + `present' field and the target flow condition is not + present."; + type vtype:vtn-update-operation-type; + } + + leaf present { + description + "If true is set, the opration will fail unless the target + flow condition is present. + Null will be treated as if false is specified."; + type boolean; + } + } + + output { + uses vtype:vtn-rpc-result; + } + } + + rpc remove-flow-condition { + description + "Remove the flow condition specified by the name. + + On failure, one of vtn-error-tag value which indicates the cause + of error is set into application tag in RPC error. + + `BADREQUEST' is set if the RPC input contains invalid data. + + `NOTFOUND' is set if the specified flow condition is not present. + + `INTERNALERROR' is set if the operation failed due to internal + error."; + + input { + leaf name { + description "The name of the flow condition to be removed."; + type string; + } + } + } + + rpc set-flow-condition-match { + description + "Configure a flow match condition into the flow condition specified + by the flow condition name and match index. + + This operation takes a list of `vtn-flow-match-config', and + put all configurations in that list into the specified flow + condition. + + Match indices specified in the RPC input will be copied to the + RPC output, and `status' field in `vtn-flow-match-result' describes + the result of the operation. + + CREATED indicates that the flow match configuration specified by + the index value has been newly created. + + CHANGED indicates that the flow match configuration specified by + the index value has been successfully changed. + + Null indicates that the flow match configuration specified by + the index value was not changed. + + On failure, one of vtn-error-tag value which indicates the cause + of error is set into application tag in RPC error. + + `BADREQUEST' is set if the RPC input contains invalid data. + + `NOTFOUND' is set if the specified flow condition is not present. + + `INTERNALERROR' is set if the operation failed due to internal + error."; + input { + leaf name { + description "The name of the target flow condition."; + type string; + } + + list flow-match-list { + description + "A list of `vtn-flow-match-config' to be applied to the + flow condition specified by `name' field. Note that a + duplicate match index in this list will cause a + `BADREQUEST' error."; + uses vtn-flow-match-config; + } + } + + output { + list set-match-result { + description + "Describes pairs of match indices passed to the RPC input + and results."; + uses vtn-flow-match-result; + } + } + } + + rpc remove-flow-condition-match { + description + "Remove the flow match condition specified by the flow condition + name and match index. + + Values passed to `match-index' list will be copied to the RPC + output, and `status' field in `vtn-flow-match-result' describes + the result of the operation. + + REMOVED indicates that the flow match associated with the match + index has been successfully removed. + + Null indicates that the flow match is not associated with the + match index in the specified flow condition. + + On failure, one of vtn-error-tag value which indicates the cause + of error is set into application tag in RPC error. + + `BADREQUEST' is set if the RPC input contains invalid data. + + `NOTFOUND' is set if the specified flow condition is not present. + + `INTERNALERROR' is set if the operation failed due to internal + error."; + + input { + leaf name { + description "The name of the flow condition to be removed."; + type string; + } + + leaf-list match-index { + description + "A list of match indices to be removed from the flow + condition specified by the `name' field. + Duplicates in this list will be eliminated automatically."; + type int32; + } + } + + output { + list remove-match-result { + description + "Describes pairs of match indices passed to the RPC input + and results."; + uses vtn-flow-match-result; + } + } + } +} diff --git a/manager/model/src/main/yang/vtn-types.yang b/manager/model/src/main/yang/vtn-types.yang index b46fd1b2..3d46eb47 100644 --- a/manager/model/src/main/yang/vtn-types.yang +++ b/manager/model/src/main/yang/vtn-types.yang @@ -12,6 +12,7 @@ module vtn-types { namespace "urn:opendaylight:vtn:types"; prefix vtype; + /* OpenDaylight controller */ import opendaylight-inventory { prefix inv; revision-date 2013-08-19; @@ -24,6 +25,14 @@ module vtn-types { description "Initial revision."; } + typedef vnode-name { + description "The name of the virtual node."; + type string { + length "1 .. 31"; + pattern "[a-zA-Z0-9][a-zA-Z0-9_]*"; + } + } + typedef vtn-update-type { description "Describes the result of the operation that updates the @@ -169,4 +178,21 @@ module vtn-types { pattern ".+,.*,.*"; } } + + grouping vtn-index { + description + "Describes an int32 fields named `index' that determines the + order of elements in a list. + Unlike `ordered-list', a value for `index' field is limited from + 1 to 65535."; + + leaf index { + description + "The index value that determines the order of elements in a + list."; + type int32 { + range "1 .. 65535"; + } + } + } } -- 2.36.6