From: Ed Warnicke Date: Tue, 1 Apr 2014 15:21:25 +0000 (+0000) Subject: Merge "Bug 499: Initial draft of in-memory datastore and data broker" X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~291 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=c4940d6fa1f6928b7189afb2dc6964fb2f2cbae2;hp=bcd020ecbeeacc97df1717a238d93bacd87bcbfc;p=controller.git Merge "Bug 499: Initial draft of in-memory datastore and data broker" --- diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java index dd510a1ed7..fb0718a721 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java @@ -161,6 +161,8 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe Map> allCurrentFactories = Collections.unmodifiableMap( resolver.getAllFactories()); + + // closed by transaction controller ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier( transactionName), factory, allCurrentFactories); ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry( diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java index 84f76c9936..6b7251c302 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java @@ -407,12 +407,14 @@ class ConfigTransactionControllerImpl implements } private void internalAbort() { + logger.trace("Aborting {}", this); transactionStatus.setAborted(); close(); } public void close() { dependencyResolverManager.close(); + txLookupRegistry.close(); } @Override diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java index 28408abed2..9852a45853 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java @@ -326,26 +326,18 @@ public class SimpleConfigurationTest extends AbstractConfigTest { } @Test - public void testAbort() throws InstanceAlreadyExistsException, ValidationException { + public void testAbort() throws Exception { ConfigTransactionJMXClient transaction = configRegistryClient .createTransaction(); assertEquals(1, configRegistryClient.getOpenConfigs().size()); transaction.abortConfig(); + assertEquals(0, configRegistryClient.getOpenConfigs().size()); try { - transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME, - fixed1); - fail(); - } catch (IllegalStateException e) { - assertEquals("Configuration was aborted", e.getMessage()); - } - try { - transaction.validateConfig(); + platformMBeanServer.getMBeanInfo(transaction.getObjectName()); fail(); - } catch (IllegalStateException e) { - assertEquals("Configuration was aborted", e.getMessage()); + }catch(InstanceNotFoundException e){ } - assertEquals(0, configRegistryClient.getOpenConfigs().size()); } @Test diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend index b90c76378d..2d4e7d2c60 100644 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend @@ -34,7 +34,7 @@ import org.opendaylight.yangtools.yang.common.RpcError class FRMRuntimeDataProvider implements RuntimeDataProvider, DataCommitHandler, DataObject> { - static val FLOWS_PATH = InstanceIdentifier.builder().node(Flows).toInstance; + static val FLOWS_PATH = InstanceIdentifier.builder(Flows).toInstance; @Property var DataProviderService dataService; diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java index 0b77ea7989..a91cef6136 100644 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java @@ -27,7 +27,7 @@ public class SampleConsumer { DataModificationTransaction transaction = dataService.beginTransaction(); Flow flow = createSampleFlow("foo", null); - InstanceIdentifier path = InstanceIdentifier.builder().node(Flows.class).node(Flow.class, flow.getKey()) + InstanceIdentifier path = InstanceIdentifier.builder(Flows.class).child(Flow.class, flow.getKey()) .toInstance(); transaction.putConfigurationData(path, flow); diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend index 72508416a6..20d375fc78 100644 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend @@ -7,35 +7,34 @@ */ package org.opendaylight.controller.md.compatibility.switchmanager -import org.opendaylight.controller.switchmanager.ISwitchManager -import org.opendaylight.controller.sal.core.NodeConnector -import org.opendaylight.controller.sal.core.Property -import java.util.List -import org.opendaylight.controller.sal.core.Node import java.net.InetAddress +import java.net.NetworkInterface +import java.net.SocketException +import java.util.ArrayList +import java.util.Collections +import java.util.HashSet +import java.util.List +import java.util.Map import org.opendaylight.controller.sal.binding.api.data.DataBrokerService -import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* -import org.opendaylight.controller.sal.core.Description -import org.opendaylight.controller.sal.core.Tier import org.opendaylight.controller.sal.core.Bandwidth +import org.opendaylight.controller.sal.core.Description import org.opendaylight.controller.sal.core.ForwardingMode import org.opendaylight.controller.sal.core.MacAddress - -import org.slf4j.LoggerFactory -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yangtools.yang.binding.DataObject -import java.net.NetworkInterface -import java.net.SocketException -import java.util.Collections -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes -import java.util.ArrayList +import org.opendaylight.controller.sal.core.Node +import org.opendaylight.controller.sal.core.NodeConnector +import org.opendaylight.controller.sal.core.Property +import org.opendaylight.controller.sal.core.Tier +import org.opendaylight.controller.switchmanager.ISwitchManager import org.opendaylight.controller.switchmanager.Switch -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId -import java.util.Map -import java.util.HashSet import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.slf4j.LoggerFactory + +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwitchManager { @@ -118,7 +117,7 @@ class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwit } override getNetworkDevices() { - val path = InstanceIdentifier.builder().node(Nodes).toInstance; + val path = InstanceIdentifier.builder(Nodes).toInstance; val data = dataService.readOperationalData(path) as Nodes; val ret = new ArrayList(); for (node : data.node) { @@ -173,7 +172,7 @@ class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwit } override getNodes() { - val path = InstanceIdentifier.builder().node(Nodes).toInstance; + val path = InstanceIdentifier.builder(Nodes).toInstance; val data = dataService.readOperationalData(path) as Nodes; val ret = new HashSet(); for (node : data.node) { diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend index 37d4577e0a..6ebe20b84a 100644 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend @@ -7,32 +7,27 @@ */ package org.opendaylight.controller.md.compatibility.topology +import java.util.ArrayList +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider +import org.opendaylight.controller.sal.core.Edge +import org.opendaylight.controller.sal.core.NodeConnector import org.opendaylight.controller.switchmanager.ISwitchManager import org.opendaylight.controller.topologymanager.ITopologyManager -import org.opendaylight.controller.md.sal.common.api.data.DataReader -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology -import org.opendaylight.controller.md.compatibility.topology.TopologyMapping +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder - -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder -import java.util.ArrayList +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey -import org.opendaylight.controller.sal.core.NodeConnector -import org.opendaylight.controller.sal.topology.TopoEdgeUpdate -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder -import org.opendaylight.controller.sal.core.Edge -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier class TopologyReader implements RuntimeDataProvider { @@ -53,7 +48,7 @@ class TopologyReader implements RuntimeDataProvider { new() { _topologyKey = new TopologyKey(new TopologyId("compatibility:ad-sal")); - _topologyPath = InstanceIdentifier.builder().node(NetworkTopology).child(Topology, topologyKey).toInstance; + _topologyPath = InstanceIdentifier.builder(NetworkTopology).child(Topology, topologyKey).toInstance; _mapping = new TopologyMapping(topologyKey, topologyPath); } diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend index 905b838008..aa238a8a8e 100644 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend @@ -16,12 +16,8 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. import java.util.Map import org.opendaylight.controller.sal.core.Edge import java.util.Set -import java.util.List import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node -import java.util.Collections -import com.google.common.collect.FluentIterable import java.util.HashSet -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId import org.opendaylight.controller.sal.compatibility.NodeMapping import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey @@ -30,7 +26,6 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey import java.util.HashMap @@ -42,11 +37,11 @@ class AdSalTopologyMapping { new(TopologyKey topology) { topologyMapping = topology; - _topologyPath = InstanceIdentifier.builder.node(NetworkTopology).child(Topology, topology).toInstance; + _topologyPath = InstanceIdentifier.builder(NetworkTopology).child(Topology, topology).toInstance; } def InstanceIdentifier toTerminationPoint(NodeConnector connector) { - InstanceIdentifier.builder(topologyPath).node(Node).child(TerminationPoint, connector.toTerminationPointKey()).toInstance; + InstanceIdentifier.builder(topologyPath).child(Node).child(TerminationPoint, connector.toTerminationPointKey()).toInstance; } def Map> toEdgePropertiesMap(Iterable links) { diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend index a59c2c1636..00ce312335 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend @@ -251,9 +251,9 @@ package class SalCompatibilityProvider implements BindingAwareProvider { topology.dataService = session.getSALService(DataProviderService) tpProvider.dataService = session.getSALService(DataProviderService) - inventory.start(); + inventory.startAdapter(); - tpProvider.start(); + tpProvider.startAdapter(); subscribe.registerNotificationListener(dataPacket) } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend index 0c211fd0aa..f54defdf14 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend @@ -122,12 +122,15 @@ class InventoryAndReadAdapter implements IPluginInReadService, private final Lock nodeToNodeConnectorsLock = new ReentrantLock(); - def start(){ + def startAdapter(){ inventoryNotificationProvider.dataProviderService = dataProviderService; inventoryNotificationProvider.inventoryPublisher = inventoryPublisher; // inventoryNotificationProvider.start(); } + def start(){ + } + def setInventoryPublisher(IPluginOutInventoryService listener){ inventoryPublisher.add(listener); } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java index 2dce505d28..29904220d7 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java @@ -44,8 +44,7 @@ public class InventoryMapping { public static NodeRef toNodeRef(final Node node) { final NodeId nodeId = new NodeId(InventoryMapping.toNodeId(node)); final NodeKey nodeKey = new NodeKey(nodeId); - final InstanceIdentifierBuilder builder = InstanceIdentifier.builder(); - final InstanceIdentifierBuilder nodes = builder.node(Nodes.class); + final InstanceIdentifierBuilder nodes = InstanceIdentifier.builder(Nodes.class); final InstanceIdentifierBuilder child = nodes.child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey); final InstanceIdentifier path = child.toInstance(); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java index 0486f3422c..fad37ae4f3 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java @@ -163,7 +163,7 @@ public class NodeMapping { Preconditions.checkArgument(MD_SAL_TYPE.equals(node.getType())); final String nodeId = Arguments.checkInstanceOf(node.getID(), String.class); final NodeKey nodeKey = new NodeKey(new NodeId(nodeId)); - final InstanceIdentifier nodePath = InstanceIdentifier.builder().node(Nodes.class).child(NODE_CLASS, nodeKey).toInstance(); + final InstanceIdentifier nodePath = InstanceIdentifier.builder(Nodes.class).child(NODE_CLASS, nodeKey).toInstance(); return new NodeRef(nodePath); } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyProvider.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyProvider.xtend index 3df826e36e..4aef75d991 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyProvider.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyProvider.xtend @@ -31,8 +31,15 @@ class TopologyProvider implements AutoCloseable{ DataProviderService dataService; Registration,DataObject>> commitHandlerRegistration; - + def void start() { + + } + def void startAdapter() { + if(dataService == null){ + LOG.error("dataService not set"); + return; + } commitHandler = new TopologyCommitHandler(dataService) commitHandler.setTopologyPublisher(topologyPublisher) val InstanceIdentifier path = InstanceIdentifier.builder(NetworkTopology) @@ -49,7 +56,9 @@ class TopologyProvider implements AutoCloseable{ def setTopologyPublisher(IPluginOutTopologyService topologyPublisher) { _topologyPublisher = topologyPublisher; - commitHandler.setTopologyPublisher(topologyPublisher); + if(commitHandler != null){ + commitHandler.setTopologyPublisher(topologyPublisher); + } } } diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-port.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-port.yang index cf6d232db3..047300a61b 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-port.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-port.yang @@ -38,12 +38,6 @@ module sal-port { uses tr:transaction-aware; } } - - rpc get-port { - output { - uses port-type:flow-capable-port; - } - } notification port-updated { uses port-update; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java index 248cca09db..36a172d09c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java @@ -7,24 +7,17 @@ */ package org.opendaylight.controller.sal.binding.test.bugfix; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import org.junit.Test; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; 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; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.CompositeNode; - - - - - - - -import static org.junit.Assert.*; - public class UnionSerializationTest extends AbstractDataServiceTest { public static final String PREFIX_STRING = "192.168.0.1/32"; @@ -42,7 +35,7 @@ public class UnionSerializationTest extends AbstractDataServiceTest { assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME)); assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue()); - Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(InstanceIdentifier.builder().node(Prefix.class).build(), serialized); + Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(Prefix.class, serialized); assertNotNull(deserialized); assertNotNull(deserialized.getPrefix()); assertNotNull(deserialized.getPrefix().getIpv4Prefix()); diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index 777709b06a..182441d3f5 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -41,6 +41,10 @@ org.opendaylight.yangtools yang-data-impl + + org.opendaylight.yangtools + yang-parser-impl + org.opendaylight.controller sal-broker-impl diff --git a/opendaylight/md-sal/sal-rest-connector/pom.xml b/opendaylight/md-sal/sal-rest-connector/pom.xml index cc3b0296ed..4aa3824e61 100644 --- a/opendaylight/md-sal/sal-rest-connector/pom.xml +++ b/opendaylight/md-sal/sal-rest-connector/pom.xml @@ -57,6 +57,10 @@ io.netty netty-codec-http + + org.opendaylight.controller + sal-remote + diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java index c006a34da7..486cdcf04e 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java @@ -17,11 +17,15 @@ import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; import org.opendaylight.yangtools.concepts.Registration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * */ public final class ToasterConsumerModule extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModule { + private static final Logger log = LoggerFactory.getLogger(ToasterConsumerModule.class); public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); @@ -55,6 +59,7 @@ public final class ToasterConsumerModule extends org.opendaylight.controller.con public void close() throws Exception { runtimeRegistration.close(); notificationRegistration.close(); + log.info("Toaster consumer (instance {}) torn down.", this); } @Override @@ -63,6 +68,8 @@ public final class ToasterConsumerModule extends org.opendaylight.controller.con } } - return new AutoCloseableToastConsumer(); + AutoCloseable ret = new AutoCloseableToastConsumer(); + log.info("Toaster consumer (instance {}) initialized.", ret); + return ret; } } diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java index 1029105233..d9bb36eb8e 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java @@ -14,12 +14,15 @@ import org.opendaylight.controller.sample.toaster.provider.OpendaylightToaster; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * */ public final class ToasterProviderModule extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModule { + private static final Logger log = LoggerFactory.getLogger(ToasterProviderModule.class); public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); @@ -43,6 +46,7 @@ public final class ToasterProviderModule extends org.opendaylight.controller.con // Register to md-sal opendaylightToaster.setNotificationProvider(getNotificationServiceDependency()); + opendaylightToaster.setDataProvider(getDataBrokerDependency()); final BindingAwareBroker.RpcRegistration rpcRegistration = getRpcRegistryDependency() .addRpcImplementation(ToasterService.class, opendaylightToaster); @@ -58,6 +62,8 @@ public final class ToasterProviderModule extends org.opendaylight.controller.con public void close() throws Exception { rpcRegistration.close(); runtimeReg.close(); + opendaylightToaster.close(); + log.info("Toaster provider (instance {}) torn down.", this); } @Override @@ -66,7 +72,8 @@ public final class ToasterProviderModule extends org.opendaylight.controller.con } } - return new AutoCloseableToaster(); + AutoCloseable ret = new AutoCloseableToaster(); + log.info("Toaster provider (instance {}) initialized.", ret); + return ret; } - } diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java index e1d69800ca..2dab924e77 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.sample.toaster.provider; import java.util.Collections; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -16,6 +17,8 @@ import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput; @@ -26,6 +29,7 @@ import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterBuilder; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; @@ -33,37 +37,37 @@ import org.slf4j.LoggerFactory; import com.google.common.util.concurrent.Futures; -public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean { +public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean, AutoCloseable { private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class); + private static final InstanceIdentifier toasterIID = InstanceIdentifier.builder(Toaster.class).build(); private static final DisplayString toasterManufacturer = new DisplayString("Opendaylight"); private static final DisplayString toasterModelNumber = new DisplayString("Model 1 - Binding Aware"); - private final ToasterStatus toasterStatus; private NotificationProviderService notificationProvider; + private DataBrokerService dataProvider; private final ExecutorService executor; private Future> currentTask; public OpendaylightToaster() { - toasterStatus = ToasterStatus.Down; executor = Executors.newFixedThreadPool(1); } @Override - public Toaster getToaster() { + public synchronized Toaster getToaster() { ToasterBuilder tb = new ToasterBuilder(); tb // .setToasterManufacturer(toasterManufacturer) // - .setToasterModelNumber(toasterModelNumber) // - .setToasterStatus(toasterStatus); + .setToasterModelNumber(toasterModelNumber) // + .setToasterStatus(currentTask == null ? ToasterStatus.Up : ToasterStatus.Down); return tb.build(); } @Override - public Future> cancelToast() { + public synchronized Future> cancelToast() { if (currentTask != null) { cancelToastImpl(); } @@ -71,14 +75,14 @@ public class OpendaylightToaster implements ToasterData, ToasterService, Toaster } @Override - public Future> makeToast(MakeToastInput input) { - // TODO Auto-generated method stub - log.trace("makeToast - Received input for toast"); + public synchronized Future> makeToast(MakeToastInput input) { + log.debug("makeToast - Received input for toast"); logToastInput(input); if (currentTask != null) { return inProgressError(); } currentTask = executor.submit(new MakeToastTask(input)); + updateStatus(); return currentTask; } @@ -98,6 +102,11 @@ public class OpendaylightToaster implements ToasterData, ToasterService, Toaster this.notificationProvider = salService; } + public void setDataProvider(DataBrokerService salDataProvider) { + this.dataProvider = salDataProvider; + updateStatus(); + } + private void logToastInput(MakeToastInput input) { String toastType = input.getToasterToastType().getName(); String toastDoneness = input.getToasterDoneness().toString(); @@ -111,6 +120,31 @@ public class OpendaylightToaster implements ToasterData, ToasterService, Toaster return toastsMade.get(); } + private void updateStatus() { + if (dataProvider != null) { + final DataModificationTransaction t = dataProvider.beginTransaction(); + t.removeOperationalData(toasterIID); + t.putOperationalData(toasterIID, getToaster()); + + try { + t.commit().get(); + } catch (InterruptedException | ExecutionException e) { + log.warn("Failed to update toaster status, operational otherwise", e); + } + } else { + log.trace("No data provider configured, not updating status"); + } + } + + @Override + public void close() throws ExecutionException, InterruptedException { + if (dataProvider != null) { + final DataModificationTransaction t = dataProvider.beginTransaction(); + t.removeOperationalData(toasterIID); + t.commit().get(); + } + } + private class MakeToastTask implements Callable> { final MakeToastInput toastRequest; @@ -120,17 +154,18 @@ public class OpendaylightToaster implements ToasterData, ToasterService, Toaster } @Override - public RpcResult call() throws Exception { - Thread.sleep(1000); + public RpcResult call() throws InterruptedException { + Thread.sleep(1000 * toastRequest.getToasterDoneness()); ToastDoneBuilder notifyBuilder = new ToastDoneBuilder(); notifyBuilder.setToastStatus(ToastStatus.Done); notificationProvider.publish(notifyBuilder.build()); - log.trace("Toast Done"); + log.debug("Toast Done"); logToastInput(toastRequest); - currentTask = null; + currentTask = null; toastsMade.incrementAndGet(); + updateStatus(); return Rpcs. getRpcResult(true, null, Collections. emptySet()); } diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang index 0be8874245..17b0c8d0f0 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang @@ -47,6 +47,14 @@ module toaster-provider-impl { } } + container data-broker { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity mdsal:binding-data-broker; + } + } + } } } @@ -60,4 +68,4 @@ module toaster-provider-impl { } } -} \ No newline at end of file +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlDst.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlDst.java new file mode 100644 index 0000000000..381de8e23a --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlDst.java @@ -0,0 +1,106 @@ +package org.opendaylight.controller.sal.match.extensible; + +import java.util.Arrays; + +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.controller.sal.utils.HexEncode; +import org.opendaylight.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class DlDst extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "DL_DST"; + private byte[] address; + + /** + * Creates a Match field for the destination data layer address + * + * @param address + * the data layer address. The constructor makes a copy of it + */ + public DlDst(byte[] address) { + super(TYPE); + if (address != null) { + this.address = Arrays.copyOf(address, address.length); + } + } + + // To satisfy JAXB + public DlDst() { + super(TYPE); + } + + @Override + public byte[] getValue() { + return Arrays.copyOf(address, address.length); + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return HexEncode.bytesToHexStringFormat(address); + } + + @Override + public byte[] getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return address != null && address.length == NetUtils.MACAddrLengthInBytes; + } + + @Override + public boolean hasReverse() { + return true; + } + + @Override + public DlSrc getReverse() { + return new DlSrc(address); + } + + @Override + public DlDst clone() { + return new DlDst(address); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(address); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof DlDst)) { + return false; + } + DlDst other = (DlDst) obj; + return Arrays.equals(address, other.address); + } +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlSrc.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlSrc.java new file mode 100644 index 0000000000..962c4d38e9 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlSrc.java @@ -0,0 +1,106 @@ +package org.opendaylight.controller.sal.match.extensible; + +import java.util.Arrays; + +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.controller.sal.utils.HexEncode; +import org.opendaylight.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class DlSrc extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "DL_SRC"; + private byte[] address; + + /** + * Creates a Match field for the source datalayer address + * + * @param address + * the datalayer address. The constructor makes a copy of it + */ + public DlSrc(byte[] address) { + super(TYPE); + if (address != null) { + this.address = Arrays.copyOf(address, address.length); + } + } + + // To satisfy JAXB + private DlSrc() { + super(TYPE); + } + + @Override + public byte[] getValue() { + return Arrays.copyOf(address, address.length); + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return HexEncode.bytesToHexStringFormat(address); + } + + @Override + public byte[] getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return address != null && address.length == NetUtils.MACAddrLengthInBytes; + } + + @Override + public boolean hasReverse() { + return true; + } + + @Override + public DlDst getReverse() { + return new DlDst(address); + } + + @Override + public DlSrc clone() { + return new DlSrc(address); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(address); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof DlSrc)) { + return false; + } + DlSrc other = (DlSrc) obj; + return Arrays.equals(address, other.address); + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlType.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlType.java new file mode 100644 index 0000000000..468703d552 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlType.java @@ -0,0 +1,105 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.utils.EtherTypes; +import org.opendaylight.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class DlType extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "DL_TYPE"; + private short ethertype; + + /** + * Creates a Match field for the data layer type + * + * @param address + * the data layer type + */ + public DlType(short ethertype) { + super(TYPE); + this.ethertype = ethertype; + } + + // To satisfy JAXB + private DlType() { + super(TYPE); + } + + @Override + public Short getValue() { + return ethertype; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return String.format("0X%s", Integer.toHexString(NetUtils.getUnsignedShort(ethertype))); + } + + @Override + public Short getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean hasReverse() { + return false; + } + + @Override + public DlType getReverse() { + return this.clone(); + } + + @Override + public DlType clone() { + return new DlType(ethertype); + } + + @Override + public boolean isV6() { + return this.ethertype == EtherTypes.IPv6.shortValue(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ethertype; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof DlType)) { + return false; + } + DlType other = (DlType) obj; + if (ethertype != other.ethertype) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlVlan.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlVlan.java new file mode 100644 index 0000000000..30657a90bf --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlVlan.java @@ -0,0 +1,104 @@ +package org.opendaylight.controller.sal.match.extensible; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class DlVlan extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "DL_VLAN"; + private static final short MAX = 4095; + private short vlan; + + /** + * Creates a Match field for the data layer type + * + * @param address + * the data layer type + */ + public DlVlan(short vlan) { + super(TYPE); + this.vlan = vlan; + } + + // To satisfy JAXB + private DlVlan() { + super(TYPE); + } + + @Override + public Short getValue() { + return vlan; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return String.valueOf(vlan); + } + + @Override + public Short getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return vlan >= 0 && vlan <= MAX; + } + + @Override + public DlVlan getReverse() { + return this.clone(); + } + + @Override + public boolean hasReverse() { + return false; + } + + @Override + public DlVlan clone() { + return new DlVlan(vlan); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + vlan; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof DlVlan)) { + return false; + } + DlVlan other = (DlVlan) obj; + if (vlan != other.vlan) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlVlanPriority.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlVlanPriority.java new file mode 100644 index 0000000000..58dd5639a2 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/DlVlanPriority.java @@ -0,0 +1,105 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class DlVlanPriority extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "DL_VLAN_PR"; + private static final byte MAX = 7; + private byte vlanPriority; + + /** + * Creates a Match field for the data layer type + * + * @param address + * the data layer type + */ + public DlVlanPriority(byte vlanPriority) { + super(TYPE); + this.vlanPriority = vlanPriority; + } + + // To satisfy JAXB + private DlVlanPriority() { + super(TYPE); + } + + @Override + public Byte getValue() { + return vlanPriority; + } + + @Override + @XmlElement(name = "mask") + protected String getValueString() { + return String.format("0X%s", Integer.toHexString(NetUtils.getUnsignedByte(vlanPriority))); + } + + @Override + public Byte getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return vlanPriority >= 0 && vlanPriority <= MAX; + } + + @Override + public boolean hasReverse() { + return false; + } + + @Override + public DlVlanPriority getReverse() { + return this.clone(); + } + + @Override + public DlVlanPriority clone() { + return new DlVlanPriority(vlanPriority); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + vlanPriority; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof DlVlanPriority)) { + return false; + } + DlVlanPriority other = (DlVlanPriority) obj; + if (vlanPriority != other.vlanPriority) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/InPort.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/InPort.java new file mode 100644 index 0000000000..2b5eb5b574 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/InPort.java @@ -0,0 +1,108 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.core.NodeConnector; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class InPort extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "IN_PORT"; + private NodeConnector port; + + /** + * Creates a Match field for the input port + * + * @param port + * the input port + */ + public InPort(NodeConnector port) { + super(TYPE); + this.port = port; + } + + // To satisfy JAXB + private InPort() { + super(TYPE); + } + + @Override + public NodeConnector getValue() { + return port; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return port.toString(); + } + + @Override + public NodeConnector getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean hasReverse() { + return false; + } + + @Override + public InPort getReverse() { + return this.clone(); + } + + @Override + public InPort clone() { + return new InPort(port); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((port == null) ? 0 : port.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof InPort)) { + return false; + } + InPort other = (InPort) obj; + if (port == null) { + if (other.port != null) { + return false; + } + } else if (!port.equals(other.port)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/Match.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/Match.java new file mode 100644 index 0000000000..b065444c53 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/Match.java @@ -0,0 +1,422 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.sal.match.extensible; + +import java.io.Serializable; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +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.XmlRootElement; + + +import org.opendaylight.controller.sal.utils.NetUtils; + +/** + * Represents the generic match criteria for a network frame/packet/message + * It contains a collection of individual field match + * + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class Match implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + private Map> fields; + + public Match() { + fields = new HashMap>(); + } + + public Match(Match match) { + fields = new HashMap>(match.fields); + } + + /** + * Generic setter for frame/packet/message's header field against which to match + * + * @param field the fields parameters as MAtchField object + */ + public void setField(MatchField field) { + if (field.isValid()) { + fields.put(field.getType(), field); + } + } + + /** + * Generic method to clear a field from the match + */ + public void clearField(String type) { + fields.remove(type); + } + + /** + * Generic getter for fields against which the match is programmed + * + * @param type frame/packet/message's header field type + * @return + */ + public MatchField getField(String type) { + return fields.get(type); + } + + /** + * Returns the list of MatchType fields the match is set for + * + * @return List of individual MatchType fields. + */ + public List getMatchesList() { + return new ArrayList(fields.keySet()); + } + + /** + * Returns the list of MatchFields the match is set for + * + * @return List of individual MatchField values. + */ + @XmlElement(name="matchField") + public List> getMatchFields() { + return new ArrayList>(fields.values()); + } + + /** + * Returns whether this match is for an IPv6 flow + */ + public boolean isIPv6() { + if (isPresent(DlType.TYPE)) { + for (MatchField field : fields.values()) { + if (!field.isV6()) { + return false; + } + } + } + return true; + } + + /** + * Returns whether this match is for an IPv4 flow + */ + public boolean isIPv4() { + return !isIPv6(); + } + + /** + * Returns whether for the specified field type the match is to be considered "any" + * Equivalent to say this match does not care about the value of the specified field + * + * @param type + * @return + */ + public boolean isAny(String type) { + return !fields.containsKey(type); + } + + /** + * Returns whether a match for the specified field type is configured + * + * @param type + * @return + */ + public boolean isPresent(String type) { + return (fields.get(type) != null); + } + + public boolean isEmpty() { + return fields.isEmpty(); + } + + @Override + public Match clone() { + Match cloned = null; + try { + cloned = (Match) super.clone(); + cloned.fields = new HashMap>(); + for (Entry> entry : this.fields.entrySet()) { + cloned.fields.put(entry.getKey(), entry.getValue().clone()); + } + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + return cloned; + } + + /** + * Returns a reversed version of this match + * For example, in the reversed version the network source and destination + * addresses will be exchanged. Non symmetric match field will not be + * copied over into the reversed match version, like input port. + * + * @return + */ + public Match reverse() { + Match reverse = new Match(); + for (MatchField field : fields.values()) { + reverse.setField(field.hasReverse()? field.getReverse() : field.clone()); + } + + // Reset asymmetric fields + reverse.clearField(InPort.TYPE); + + return reverse; + } + + /** + * Check whether the current match conflicts with the passed filter match + * This match conflicts with the filter if for at least a MatchType defined + * in the filter match, the respective MatchFields differ or are not + * compatible + * + * In other words the function returns true if the set of packets described + * by one match and the set of packets described by the other match are + * disjoint. Equivalently, if the intersection of the two sets of packets + * described by the two org.opendaylight.controller.sal.matches is an empty. + * + * For example, Let's suppose the filter has the following MatchFields: + * DL_TYPE = 0x800 + * NW_DST = 172.20.30.110/24 + * + * while this match has the following MatchFields: + * DL_TYPE = 0x800 + * NW_DST = 172.20.30.45/24 + * TP_DST = 80 + * + * Then the function would return false as the two Match are not + * conflicting. + * + * Note: the mask value is taken into account only for MatchType.NW_SRC and + * MatchType.NW_DST + * + * @param match + * the Match describing the filter + * @return true if the set of packets described by one match and the set of + * packets described by the other match are disjoint, false + * otherwise + */ + public boolean conflictWithFilter(Match filter) { + return !this.intersetcs(filter); + } + + /** + * Merge the current Match fields with the fields of the filter Match. A + * check is first run to see if this Match is compatible with the filter + * Match. If it is not, the merge is not attempted. + * + * The result is the match object representing the intersection of the set + * of packets described by this match with the set of packets described by + * the filter match. If the intersection of the two sets is empty, the + * return match will be null. + * + * @param filter + * the match with which attempting the merge + * @return a new Match object describing the set of packets represented by + * the intersection of this and the filter org.opendaylight.controller.sal.matches. null if the + * intersection is empty. + */ + public Match mergeWithFilter(Match filter) { + return this.getIntersection(filter); + } + + /** + * Return the match representing the intersection of the set of packets + * described by this match with the set of packets described by the other + * match. Such as m.getIntersection(m) == m, m.getIntersection(u) == m and + * m.getIntersection(o) == o where u is an empty match (universal set, all + * packets) and o is the null match (empty set). + * + * @param other + * the match with which computing the intersection + * @return a new Match object representing the intersection of the set of + * packets described by this match with the set of packets described + * by the other match. null when the intersection is the empty set. + */ + public Match getIntersection(Match other) { + // If no intersection, return the empty set + if (!this.intersetcs(other)) { + return null; + } + // Check if any of the two is the universal match + if (this.isEmpty()) { + return other.clone(); + } + if (other.isEmpty()) { + return this.clone(); + } + // Get all the match types for both filters + Set allTypes = new HashSet(this.fields.keySet()); + allTypes.addAll(new HashSet(other.fields.keySet())); + // Derive the intersection + Match intersection = new Match(); + for (String type : allTypes) { + if (this.isAny(type) && other.isAny(type)) { + continue; + } + if (this.isAny(type)) { + intersection.setField(other.getField(type).clone()); + continue; + } else if (other.isAny(type)) { + intersection.setField(this.getField(type).clone()); + continue; + } + // Either they are equal or it is about IP address + switch (type) { + // When it is about IP address, take the wider prefix address + // between the twos + case NwSrc.TYPE: + case NwDst.TYPE: + MatchField thisField = this.getField(type); + MatchField otherField = other.getField(type); + InetAddress thisAddress = (InetAddress) thisField.getValue(); + InetAddress otherAddress = (InetAddress) otherField.getValue(); + InetAddress thisMask = (InetAddress) thisField.getMask(); + InetAddress otherMask = (InetAddress) otherField.getMask(); + + int thisMaskLen = (thisMask == null) ? ((thisAddress instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(thisMask); + int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(otherMask); + + InetAddress subnetPrefix = null; + InetAddress subnetMask = null; + if (thisMaskLen < otherMaskLen) { + subnetPrefix = NetUtils.getSubnetPrefix(otherAddress, otherMaskLen); + subnetMask = otherMask; + } else { + subnetPrefix = NetUtils.getSubnetPrefix(thisAddress, thisMaskLen); + subnetMask = thisMask; + } + MatchField field = (type.equals(NwSrc.TYPE)) ? new NwSrc(subnetPrefix, subnetMask) : new NwDst( + subnetPrefix, subnetMask); + intersection.setField(field); + break; + default: + // this and other match field are equal for this type, pick this + // match field + intersection.setField(this.getField(type).clone()); + } + } + return intersection; + } + + /** + * Checks whether the intersection of the set of packets described by this + * match with the set of packets described by the other match is non empty + * + * For example, if this match is: DL_SRC = 00:cc:bb:aa:11:22 + * + * and the other match is: DL_TYPE = 0x800 NW_SRC = 1.2.3.4 + * + * then their respective matching packets set intersection is non empty: + * DL_SRC = 00:cc:bb:aa:11:22 DL_TYPE = 0x800 NW_SRC = 1.2.3.4 + * + * @param other + * the other match with which testing the intersection + * @return true if the intersection of the respective matching packets sets + * is non empty + */ + public boolean intersetcs(Match other) { + // No intersection with the empty set + if (other == null) { + return false; + } + // Always intersection with the universal set + if (this.isEmpty() || other.isEmpty()) { + return true; + } + + // Get all the match types for both filters + Set allTypes = new HashSet(this.fields.keySet()); + allTypes.addAll(new HashSet(other.fields.keySet())); + + // Iterate through all the match types defined in the two filters + for (String type : allTypes) { + if (this.isAny(type) || other.isAny(type)) { + continue; + } + + MatchField thisField = this.getField(type); + MatchField otherField = other.getField(type); + + switch (type) { + case DlSrc.TYPE: + case DlDst.TYPE: + if (!Arrays.equals((byte[]) thisField.getValue(), (byte[]) otherField.getValue())) { + return false; + } + break; + case NwSrc.TYPE: + case NwDst.TYPE: + InetAddress thisAddress = (InetAddress) thisField.getValue(); + InetAddress otherAddress = (InetAddress) otherField.getValue(); + // Validity check + if (thisAddress instanceof Inet4Address && otherAddress instanceof Inet6Address + || thisAddress instanceof Inet6Address && otherAddress instanceof Inet4Address) { + return false; + } + InetAddress thisMask = (InetAddress) thisField.getMask(); + InetAddress otherMask = (InetAddress) otherField.getMask(); + if (NetUtils.inetAddressConflict(thisAddress, otherAddress, thisMask, otherMask) + && NetUtils.inetAddressConflict(otherAddress, thisAddress, otherMask, thisMask)) { + return false; + } + break; + default: + if (!thisField.getValue().equals(otherField.getValue())) { + return false; + } + } + } + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((fields == null) ? 0 : fields.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof Match)) { + return false; + } + Match other = (Match) obj; + if (fields == null) { + if (other.fields != null) { + return false; + } + } else if (!fields.equals(other.fields)) { + return false; + } + return true; + } + + @Override + public String toString() { + return "Match[" + fields.values() + "]"; + } +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/MatchField.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/MatchField.java new file mode 100644 index 0000000000..e7a5de3850 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/MatchField.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.sal.match.extensible; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Represents the generic matching field object + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public abstract class MatchField implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + private String type; + + // To satisfy JAXB + @SuppressWarnings("unused") + private MatchField() { + } + + public MatchField(String type) { + this.type = type; + } + + @XmlElement(name = "type") + public String getType() { + return type; + } + + /** + * Returns the value set for this match field + * + * @return + */ + public abstract T getValue(); + + @XmlElement(name = "value") + protected abstract String getValueString(); + + /** + * Returns the mask value set for this field match A null mask means this is + * a full match + * + * @return + */ + public abstract T getMask(); + + @XmlElement(name = "mask") + protected abstract String getMaskString(); + + /** + * Returns whether the field match configuration is valid or not + * + * @return true if valid, false otherwise + */ + public abstract boolean isValid(); + + public abstract boolean hasReverse(); + + /** + * Returns the reverse match field. For example for a MatchField matching on + * source ip 1.1.1.1 it will return a MatchField matching on destination IP + * 1.1.1.1. For not reversable MatchField, a copy of this MatchField will be + * returned + * + * @return the correspondent reverse MatchField object or a copy of this + * object if the field is not reversable + */ + public abstract MatchField getReverse(); + + /** + * Returns whether the match field is congruent with IPv6 frames + * + * @return true if congruent with IPv6 frames + */ + public abstract boolean isV6(); + + @Override + public abstract MatchField clone(); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof MatchField)) { + return false; + } + MatchField other = (MatchField) obj; + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + return true; + } + + @Override + public String toString() { + return (getMask() == null) ? String.format("%s(%s)", getType(), getValueString()) : + String.format("%s(%s,%s)", getType(), getValueString(), getMaskString()); + } + +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwDst.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwDst.java new file mode 100644 index 0000000000..42b6ba6cc0 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwDst.java @@ -0,0 +1,131 @@ +package org.opendaylight.controller.sal.match.extensible; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class NwDst extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "NW_DST"; + private InetAddress address; + private InetAddress mask; + + /** + * Creates a Match field for the network destination address + * + * @param address + * the network address + * @param mask + * the network mask + */ + public NwDst(InetAddress address, InetAddress mask) { + super(TYPE); + this.address = address; + this.mask = mask; + } + + // To satisfy JAXB + private NwDst() { + super(TYPE); + } + + public NwDst(InetAddress address) { + super(TYPE); + this.address = address; + this.mask = null; + } + + @Override + public InetAddress getValue() { + return address; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return address.getHostAddress(); + } + + @Override + public InetAddress getMask() { + return mask; + } + + @Override + @XmlElement(name = "mask") + protected String getMaskString() { + return (mask == null) ? "null" : mask.getHostAddress(); + } + + @Override + public boolean isValid() { + if (address != null) { + if (mask != null) { + return address instanceof Inet4Address && mask instanceof Inet4Address + || address instanceof Inet6Address && mask instanceof Inet6Address; + } + return true; + } + return false; + } + + @Override + public boolean hasReverse() { + return true; + } + + @Override + public NwSrc getReverse() { + return new NwSrc(address, mask); + } + + @Override + public NwDst clone() { + return new NwDst(address, mask); + } + + @Override + public boolean isV6() { + return address instanceof Inet6Address; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((address == null) ? 0 : address.hashCode()); + result = prime * result + ((mask == null) ? 0 : mask.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof NwDst)) { + return false; + } + NwDst other = (NwDst) obj; + // Equality to be checked against prefix addresses + int thisMaskLen = (this.mask == null) ? ((this.address instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(this.mask); + int otherMaskLen = (other.mask == null) ? ((other.address instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(other.mask); + + return NetUtils.getSubnetPrefix(address, thisMaskLen).equals( + NetUtils.getSubnetPrefix(other.address, otherMaskLen)); + } +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwProtocol.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwProtocol.java new file mode 100644 index 0000000000..c5b5315902 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwProtocol.java @@ -0,0 +1,116 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class NwProtocol extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "NW_PROTO"; + private static final short MAX = 255; + private byte protocol; + + /** + * Creates a Match field for the network protocol + * + * @param protocol + * the protocol number + */ + public NwProtocol(byte protocol) { + super(TYPE); + this.protocol = protocol; + } + + public NwProtocol(int protocol) { + super(TYPE); + this.protocol = (byte) protocol; + } + + public NwProtocol(short protocol) { + super(TYPE); + this.protocol = (byte) protocol; + } + + // To satisfy JAXB + private NwProtocol() { + super(TYPE); + } + + @Override + public Byte getValue() { + return protocol; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return String.format("0X%s", Integer.toHexString(NetUtils.getUnsignedByte(protocol))); + } + + @Override + public Byte getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + int intProtocol = NetUtils.getUnsignedByte(protocol); + return intProtocol >= 0 && intProtocol <= MAX; + } + + @Override + public boolean hasReverse() { + return false; + } + + @Override + public NwProtocol getReverse() { + return this.clone(); + } + + @Override + public NwProtocol clone() { + return new NwProtocol(protocol); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + protocol; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof NwProtocol)) { + return false; + } + NwProtocol other = (NwProtocol) obj; + if (protocol != other.protocol) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwSrc.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwSrc.java new file mode 100644 index 0000000000..4da43f53a0 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwSrc.java @@ -0,0 +1,131 @@ +package org.opendaylight.controller.sal.match.extensible; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class NwSrc extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "NW_SRC"; + private InetAddress address; + private InetAddress mask; + + /** + * Creates a Match field for the network source address + * + * @param address + * the network address + * @param mask + * the network mask + */ + public NwSrc(InetAddress address, InetAddress mask) { + super(TYPE); + this.address = address; + this.mask = mask; + } + + // To satisfy JAXB + private NwSrc() { + super(TYPE); + } + + public NwSrc(InetAddress address) { + super(TYPE); + this.address = address; + this.mask = null; + } + + @Override + public InetAddress getValue() { + return address; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return address.toString(); + } + + @Override + public InetAddress getMask() { + return mask; + } + + @Override + @XmlElement(name = "mask") + protected String getMaskString() { + return mask == null ? "null" : mask.toString(); + } + + @Override + public boolean isValid() { + if (address != null) { + if (mask != null) { + return address instanceof Inet4Address && mask instanceof Inet4Address + || address instanceof Inet6Address && mask instanceof Inet6Address; + } + return true; + } + return false; + } + + @Override + public boolean hasReverse() { + return true; + } + + @Override + public NwDst getReverse() { + return new NwDst(address, mask); + } + + @Override + public NwSrc clone() { + return new NwSrc(address, mask); + } + + @Override + public boolean isV6() { + return address instanceof Inet6Address; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((address == null) ? 0 : address.hashCode()); + result = prime * result + ((mask == null) ? 0 : mask.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof NwSrc)) { + return false; + } + NwSrc other = (NwSrc) obj; + // Equality to be checked against prefix addresses + int thisMaskLen = (this.mask == null) ? ((this.address instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(this.mask); + int otherMaskLen = (other.mask == null) ? ((other.address instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(other.mask); + + return NetUtils.getSubnetPrefix(address, thisMaskLen).equals( + NetUtils.getSubnetPrefix(other.address, otherMaskLen)); + } +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwTos.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwTos.java new file mode 100644 index 0000000000..ba5b562bd2 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/NwTos.java @@ -0,0 +1,115 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class NwTos extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "NW_TOS"; + private static final short MAX = 63; + private byte tos; + + /** + * Creates a Match field for the network TOS + * + * @param address + * the network TOS + */ + public NwTos(byte tos) { + super(TYPE); + this.tos = tos; + } + + public NwTos(int tos) { + super(TYPE); + this.tos = (byte) tos; + } + + public NwTos(short tos) { + super(TYPE); + this.tos = (byte) tos; + } + + // To satisfy JAXB + private NwTos() { + super(TYPE); + } + + @Override + public Byte getValue() { + return tos; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return String.format("0X%s", Integer.toHexString(NetUtils.getUnsignedByte(tos))); + } + + @Override + public Byte getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return tos >= 0 && tos <= MAX; + } + + @Override + public boolean hasReverse() { + return false; + } + + @Override + public NwTos getReverse() { + return this.clone(); + } + + @Override + public NwTos clone() { + return new NwTos(tos); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + tos; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof NwTos)) { + return false; + } + NwTos other = (NwTos) obj; + if (tos != other.tos) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/TpDst.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/TpDst.java new file mode 100644 index 0000000000..022db4cc17 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/TpDst.java @@ -0,0 +1,104 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class TpDst extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "TP_DST"; + private short port; + + /** + * Creates a Match field for the transport destination port + * + * @param port + * the transport port + */ + public TpDst(short port) { + super(TYPE); + this.port = port; + } + + // To satisfy JAXB + private TpDst() { + super(TYPE); + } + + @Override + public Short getValue() { + return port; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return String.valueOf(NetUtils.getUnsignedShort(port)); + } + + @Override + public Short getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public TpSrc getReverse() { + return new TpSrc(port); + } + + @Override + public boolean hasReverse() { + return true; + } + + @Override + public TpDst clone() { + return new TpDst(port); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + port; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof TpDst)) { + return false; + } + TpDst other = (TpDst) obj; + if (port != other.port) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/TpSrc.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/TpSrc.java new file mode 100644 index 0000000000..1c93d1e847 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/extensible/TpSrc.java @@ -0,0 +1,104 @@ +package org.opendaylight.controller.sal.match.extensible; + +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.controller.sal.utils.NetUtils; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class TpSrc extends MatchField { + private static final long serialVersionUID = 1L; + public static final String TYPE = "TP_SRC"; + private short port; + + /** + * Creates a Match field for the Transport source port + * + * @param port + * the transport port + */ + public TpSrc(short port) { + super(TYPE); + this.port = port; + } + + // To satisfy JAXB + private TpSrc() { + super(TYPE); + } + + @Override + public Short getValue() { + return port; + } + + @Override + @XmlElement(name = "value") + protected String getValueString() { + return String.valueOf(NetUtils.getUnsignedShort(port)); + } + + @Override + public Short getMask() { + return null; + } + + @Override + protected String getMaskString() { + return null; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean hasReverse() { + return true; + } + + @Override + public TpDst getReverse() { + return new TpDst(port); + } + + @Override + public TpSrc clone() { + return new TpSrc(port); + } + + @Override + public boolean isV6() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + port; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof TpSrc)) { + return false; + } + TpSrc other = (TpSrc) obj; + if (port != other.port) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchExtensibleTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchExtensibleTest.java new file mode 100644 index 0000000000..0f49f421d2 --- /dev/null +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchExtensibleTest.java @@ -0,0 +1,589 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.sal.match; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.match.extensible.DlDst; +import org.opendaylight.controller.sal.match.extensible.DlSrc; +import org.opendaylight.controller.sal.match.extensible.DlType; +import org.opendaylight.controller.sal.match.extensible.DlVlan; +import org.opendaylight.controller.sal.match.extensible.DlVlanPriority; +import org.opendaylight.controller.sal.match.extensible.InPort; +import org.opendaylight.controller.sal.match.extensible.Match; +import org.opendaylight.controller.sal.match.extensible.MatchField; +import org.opendaylight.controller.sal.match.extensible.NwDst; +import org.opendaylight.controller.sal.match.extensible.NwProtocol; +import org.opendaylight.controller.sal.match.extensible.NwSrc; +import org.opendaylight.controller.sal.match.extensible.NwTos; +import org.opendaylight.controller.sal.match.extensible.TpDst; +import org.opendaylight.controller.sal.match.extensible.TpSrc; +import org.opendaylight.controller.sal.utils.EtherTypes; +import org.opendaylight.controller.sal.utils.IPProtocols; +import org.opendaylight.controller.sal.utils.NodeConnectorCreator; +import org.opendaylight.controller.sal.utils.NodeCreator; + +public class MatchExtensibleTest { + @Test + public void testMatchCreation() { + Node node = NodeCreator.createOFNode(7L); + NodeConnector port = NodeConnectorCreator.createOFNodeConnector((short) 6, node); + MatchField field = new InPort(port); + + Assert.assertTrue(field != null); + Assert.assertEquals(field.getType(), InPort.TYPE); + Assert.assertEquals(field.getValue(), port); + Assert.assertTrue(field.isValid()); + + + byte mac[] = { (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 11, (byte) 22 }; + field = null; + field = new DlSrc(mac); + Assert.assertNotNull(field.getValue()); + + field = null; + field = new NwTos((byte) 0x22); + Assert.assertNotNull(field.getValue()); + } + + @Test + public void testMatchSetGet() { + Match x = new Match(); + short val = 2346; + NodeConnector inPort = NodeConnectorCreator.createOFNodeConnector(val, NodeCreator.createOFNode(1L)); + x.setField(new InPort(inPort)); + Assert.assertEquals(x.getField(InPort.TYPE).getValue(), inPort); + Assert.assertTrue((Short) ((NodeConnector) x.getField(InPort.TYPE).getValue()).getID() == val); + } + + @Test + public void testMatchSetGetMAC() { + Match x = new Match(); + byte mac[] = { (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 11, (byte) 22 }; + byte mac2[] = { (byte) 0xaa, (byte) 0xbb, 0, 0, 0, (byte) 0xbb }; + + x.setField(new DlSrc(mac)); + x.setField(new DlDst(mac2)); + Assert.assertArrayEquals(mac, (byte[]) x.getField(DlSrc.TYPE).getValue()); + Assert.assertFalse(Arrays.equals((byte[]) x.getField(DlSrc.TYPE).getValue(), (byte[]) x.getField(DlDst.TYPE) + .getValue())); + + x.setField(new DlDst(mac.clone())); + Assert.assertArrayEquals((byte[]) x.getField(DlSrc.TYPE).getValue(), (byte[]) x.getField(DlDst.TYPE).getValue()); + } + + @Test + public void testMatchSetGetNWAddr() throws UnknownHostException { + Match x = new Match(); + String ip = "172.20.231.23"; + InetAddress address = InetAddress.getByName(ip); + InetAddress mask = InetAddress.getByName("255.255.0.0"); + + x.setField(new NwSrc(address, mask)); + Assert.assertEquals(address, x.getField(NwSrc.TYPE).getValue()); + Assert.assertEquals(x.getField(NwSrc.TYPE).getMask(), mask); + } + + @Test + public void testMatchSetGetEtherType() throws UnknownHostException { + Match x = new Match(); + + x.setField(new DlType(EtherTypes.QINQ.shortValue())); + Assert.assertEquals(x.getField(DlType.TYPE).getValue(), EtherTypes.QINQ.shortValue()); + + x.setField(new DlType(EtherTypes.LLDP.shortValue())); + Assert.assertEquals(x.getField(DlType.TYPE).getValue(), EtherTypes.LLDP.shortValue()); + Assert.assertFalse(x.getField(DlType.TYPE).equals(EtherTypes.LLDP.intValue())); + } + + @Test + public void testSetGetNwTos() { + Match x = new Match(); + x.setField(new NwTos((byte) 0xb)); + + Byte t = new Byte((byte) 0xb); + + Object o = x.getField(NwTos.TYPE).getValue(); + Assert.assertEquals(o, t); + Assert.assertEquals(o, Byte.valueOf((byte)0xb)); + } + + @Test + public void testSetGetNwProto() { + Match x = new Match(); + Byte proto = (byte) 199; + x.setField(new NwProtocol(proto)); + + Byte o = (Byte) x.getField(NwProtocol.TYPE).getValue(); + Assert.assertEquals(o, proto); + } + + @Test + public void testSetTpSrc() { + // Minimum value validation. + Match match = new Match(); + short tp_src = 0; + match.setField(new TpSrc(tp_src)); + + Object o = match.getField(TpSrc.TYPE).getValue(); + Assert.assertEquals(o, tp_src); + + // Maximum value validation. + match = new Match(); + tp_src = (short) 0xffff; + match.setField(new TpSrc(tp_src)); + + o = match.getField(TpSrc.TYPE).getValue(); + Assert.assertEquals(o, tp_src); + } + + @Test + public void testSetTpDst() { + // Minimum value validation. + Match match = new Match(); + short tp_dst = 0; + match.setField(new TpDst(tp_dst)); + + Object o = match.getField(TpDst.TYPE).getValue(); + Assert.assertTrue(o.equals(tp_dst)); + + // Maximum value validation. + match = new Match(); + tp_dst = (short) 0xffff; + match.setField(new TpDst(tp_dst)); + + o = match.getField(TpDst.TYPE).getValue(); + Assert.assertEquals(o, tp_dst); + } + + @Test + public void testEquality() throws Exception { + Node node = NodeCreator.createOFNode(7L); + NodeConnector port = NodeConnectorCreator.createOFNodeConnector((short) 24, node); + NodeConnector port2 = NodeConnectorCreator.createOFNodeConnector((short) 24, node); + byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; + byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; + byte srcMac2[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; + byte dstMac2[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; + InetAddress srcIP = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + InetAddress dstIP = InetAddress.getByName("2001:420:281:1004:e123:e688:d655:a1b0"); + InetAddress ipMask = InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); + InetAddress ipMaskd = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"); + InetAddress ipMask2 = InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); + InetAddress ipMaskd2 = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"); + short ethertype = EtherTypes.IPv6.shortValue(); + short ethertype2 = EtherTypes.IPv6.shortValue(); + short vlan = (short) 27, vlan2 = (short) 27; + byte vlanPr = (byte) 3, vlanPr2 = (byte) 3; + Byte tos = 4, tos2 = 4; + byte proto = IPProtocols.UDP.byteValue(), proto2 = IPProtocols.UDP.byteValue(); + short src = (short) 5500, src2 = (short) 5500; + short dst = 80, dst2 = 80; + + /* + * Create a SAL Flow aFlow + */ + Match match1 = new Match(); + Match match2 = new Match(); + match1.setField(new InPort(port)); + match1.setField(new DlSrc(srcMac)); + match1.setField(new DlDst(dstMac)); + match1.setField(new DlType(ethertype)); + match1.setField(new DlVlan(vlan)); + match1.setField(new DlVlanPriority(vlanPr)); + match1.setField(new NwSrc(srcIP, ipMask)); + match1.setField(new NwDst(dstIP, ipMaskd)); + match1.setField(new NwTos(tos)); + match1.setField(new NwProtocol(proto)); + match1.setField(new TpSrc(src)); + match1.setField(new TpDst(dst)); + + match2.setField(new InPort(port2)); + match2.setField(new DlSrc(srcMac2)); + match2.setField(new DlDst(dstMac2)); + match2.setField(new DlType(ethertype2)); + match2.setField(new DlVlan(vlan2)); + match2.setField(new DlVlanPriority(vlanPr2)); + match2.setField(new NwSrc(srcIP, ipMask2)); + match2.setField(new NwDst(dstIP, ipMaskd2)); + match2.setField(new NwTos(tos2)); + match2.setField(new NwProtocol(proto2)); + match2.setField(new TpSrc(src2)); + match2.setField(new TpDst(dst2)); + + Assert.assertTrue(match1.equals(match2)); + + Set allFields = new HashSet(match1.getMatchesList()); + allFields.addAll(match2.getMatchesList()); + // Make sure all values are equals + for (String type : allFields) { + if (match1.isPresent(type)) { + Assert.assertEquals(match1.getField(type), match2.getField(type)); + } + } + + // Make none of the fields couples are pointing to the same reference + MatchField a = null, b = null; + for (String type : allFields) { + a = match1.getField(type); + b = match2.getField(type); + if (a != null && b != null) { + Assert.assertFalse(a == b); + } + } + } + + @Test + public void testEqualityNetMask() throws Exception { + + InetAddress srcIP = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask = InetAddress.getByName("255.255.255.255"); + InetAddress srcIP2 = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask2 = null; + short ethertype = EtherTypes.IPv4.shortValue(); + short ethertype2 = EtherTypes.IPv4.shortValue(); + + /* + * Create a SAL Flow aFlow + */ + Match match1 = new Match(); + Match match2 = new Match(); + + match1.setField(new DlType(ethertype)); + match1.setField(new NwSrc(srcIP, ipMask)); + + match2.setField(new DlType(ethertype2)); + match2.setField(new NwSrc(srcIP2, ipMask2)); + + Assert.assertTrue(match1.equals(match2)); + + ipMask2 = InetAddress.getByName("255.255.255.255"); + match2.setField(new NwSrc(srcIP2, ipMask2)); + + srcIP = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + srcIP2 = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + ipMask = null; + ipMask2 = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + ethertype = EtherTypes.IPv6.shortValue(); + ethertype2 = EtherTypes.IPv6.shortValue(); + + match1.setField(new DlType(ethertype)); + match1.setField(new NwSrc(srcIP, ipMask)); + + match2.setField(new DlType(ethertype2)); + match2.setField(new NwSrc(srcIP2, ipMask2)); + + Assert.assertEquals(match1, match2); + } + + @Test + public void testHashCodeWithReverseMatch() throws Exception { + InetAddress srcIP1 = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask1 = InetAddress.getByName("255.255.255.255"); + InetAddress srcIP2 = InetAddress.getByName("2.2.2.2"); + InetAddress ipMask2 = InetAddress.getByName("255.255.255.255"); + MatchField field1 = new NwSrc(srcIP1, ipMask1); + MatchField field2 = new NwDst(srcIP2, ipMask2); + Match match1 = new Match(); + match1.setField(field1); + match1.setField(field2); + Match match2 = match1.reverse(); + Assert.assertFalse(match1.hashCode() == match2.hashCode()); + } + + @Test + public void testHashCode() throws Exception { + byte srcMac1[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; + byte srcMac2[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; + byte dstMac1[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; + byte dstMac2[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; + short ethertype = EtherTypes.IPv4.shortValue(); + short ethertype2 = EtherTypes.IPv4.shortValue(); + InetAddress srcIP1 = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask1 = InetAddress.getByName("255.255.255.255"); + InetAddress srcIP2 = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask2 = InetAddress.getByName("255.255.255.255"); + + Match match1 = new Match(); + Match match2 = new Match(); + + MatchField field1 = new DlSrc(srcMac1); + MatchField field2 = new DlSrc(srcMac2); + Assert.assertTrue(field1.hashCode() == field2.hashCode()); + + match1.setField(field1); + match2.setField(field2); + Assert.assertTrue(match1.hashCode() == match2.hashCode()); + + MatchField field3 = new DlDst(dstMac1); + MatchField field4 = new DlDst(dstMac2); + Assert.assertTrue(field3.hashCode() == field4.hashCode()); + + match1.setField(field3); + match2.setField(field4); + Assert.assertTrue(match1.hashCode() == match2.hashCode()); + + MatchField field5 = new DlType(ethertype); + MatchField field6 = new DlType(ethertype2); + Assert.assertTrue(field5.hashCode() == field6.hashCode()); + + match1.setField(field5); + match2.setField(field6); + Assert.assertTrue(match1.hashCode() == match2 .hashCode()); + + MatchField field7 = new NwSrc(srcIP1, ipMask1); + MatchField field8 = new NwSrc(srcIP2, ipMask2); + Assert.assertTrue(field7.hashCode() == field8.hashCode()); + + match1.setField(field7); + match2.setField(field8); + Assert.assertTrue(match1.hashCode() == match2.hashCode()); + + } + + @Test + public void testCloning() throws Exception { + Node node = NodeCreator.createOFNode(7L); + NodeConnector port = NodeConnectorCreator.createOFNodeConnector((short) 24, node); + byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; + byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; + InetAddress srcIP = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + InetAddress dstIP = InetAddress.getByName("2001:420:281:1004:e123:e688:d655:a1b0"); + InetAddress ipMasks = InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); + InetAddress ipMaskd = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"); + short ethertype = EtherTypes.IPv6.shortValue(); + short vlan = (short) 27; + byte vlanPr = (byte) 3; + Byte tos = 4; + byte proto = IPProtocols.UDP.byteValue(); + short src = (short) 5500; + short dst = 80; + + /* + * Create a SAL Flow aFlow + */ + Match match = new Match(); + match.setField(new InPort(port)); + match.setField(new DlSrc(srcMac)); + match.setField(new DlDst(dstMac)); + match.setField(new DlType(ethertype)); + match.setField(new DlVlan(vlan)); + match.setField(new DlVlanPriority(vlanPr)); + match.setField(new NwSrc(srcIP, ipMasks)); + match.setField(new NwDst(dstIP, ipMaskd)); + match.setField(new NwTos(tos)); + match.setField(new NwProtocol(proto)); + match.setField(new TpSrc(src)); + match.setField(new TpDst(dst)); + + Match cloned = match.clone(); + + // Make sure all values are equals + for (String type : match.getMatchesList()) { + if (match.isPresent(type)) { + if (!match.getField(type).equals(cloned.getField(type))) { + Assert.assertEquals(match.getField(type), cloned.getField(type)); + } + } + } + + // Make sure none of the fields couples are pointing to the same + // reference + MatchField a = null, b = null; + for (String type : match.getMatchesList()) { + a = match.getField(type); + b = cloned.getField(type); + if (a != null && b != null) { + Assert.assertFalse(a == b); + } + } + + Assert.assertTrue(match.equals(cloned)); + + Assert.assertEquals(match.getField(DlSrc.TYPE), cloned.getField(DlSrc.TYPE)); + Assert.assertEquals(match.getField(NwDst.TYPE), cloned.getField(NwDst.TYPE)); + Assert.assertEquals(match.getField(NwDst.TYPE).getMask(), cloned.getField(NwDst.TYPE).getMask()); + Assert.assertEquals(match.hashCode(), cloned.hashCode()); + } + + @Test + public void testFlip() throws Exception { + Node node = NodeCreator.createOFNode(7L); + NodeConnector port = NodeConnectorCreator.createOFNodeConnector((short) 24, node); + byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; + byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; + InetAddress srcIP = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + InetAddress dstIP = InetAddress.getByName("2001:420:281:1004:e123:e688:d655:a1b0"); + InetAddress ipMasks = InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); + InetAddress ipMaskd = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"); + short ethertype = EtherTypes.IPv6.shortValue(); + short vlan = (short) 27; + byte vlanPr = (byte) 3; + Byte tos = 4; + byte proto = IPProtocols.UDP.byteValue(); + short src = (short) 5500; + short dst = 80; + + /* + * Create a SAL Flow aFlow + */ + Match match = new Match(); + match.setField(new InPort(port)); + match.setField(new DlSrc(srcMac)); + match.setField(new DlDst(dstMac)); + match.setField(new DlType(ethertype)); + match.setField(new DlVlan(vlan)); + match.setField(new DlVlanPriority(vlanPr)); + match.setField(new NwSrc(srcIP, ipMasks)); + match.setField(new NwDst(dstIP, ipMaskd)); + match.setField(new NwTos(tos)); + match.setField(new NwProtocol(proto)); + match.setField(new TpSrc(src)); + match.setField(new TpDst(dst)); + + Match flipped = match.reverse(); + + Assert.assertEquals(match.getField(DlType.TYPE), flipped.getField(DlType.TYPE)); + Assert.assertEquals(match.getField(DlVlan.TYPE), flipped.getField(DlVlan.TYPE)); + + Assert.assertArrayEquals((byte[]) match.getField(DlDst.TYPE).getValue(), (byte[]) flipped.getField(DlSrc.TYPE) + .getValue()); + + Assert.assertEquals(match.getField(NwDst.TYPE).getValue(), flipped.getField(NwSrc.TYPE).getValue()); + + Assert.assertEquals(match.getField(TpDst.TYPE).getValue(), flipped.getField(TpSrc.TYPE).getValue()); + + Match flipflip = flipped.reverse().reverse(); + Assert.assertEquals(flipflip, flipped); + + } + + @Test + public void testVlanNone() throws Exception { + // The value 0 is used to indicate that no VLAN ID is set + short vlan = (short) 0; + MatchField field = new DlVlan(vlan); + + Assert.assertTrue(field != null); + Assert.assertEquals(field.getValue(), new Short(vlan)); + Assert.assertTrue(field.isValid()); + } + + @Test + public void testIntersection() throws UnknownHostException { + Short ethType = Short.valueOf((short)0x800); + InetAddress ip1 = InetAddress.getByName("1.1.1.1"); + InetAddress ip2 = InetAddress.getByName("1.1.1.0"); + InetAddress ipm2 = InetAddress.getByName("255.255.255.0"); + InetAddress ip3 = InetAddress.getByName("1.3.0.0"); + InetAddress ipm3 = InetAddress.getByName("255.255.0.0"); + InetAddress ip4 = InetAddress.getByName("1.3.4.4"); + InetAddress ipm4 = InetAddress.getByName("255.255.255.0"); + + Match m1 = new Match(); + m1.setField(new DlType(ethType)); + m1.setField(new NwSrc(ip1)); + + Match m2 = new Match(); + m2.setField(new DlType(ethType)); + m2.setField(new NwSrc(ip2, ipm2)); + + Match m3 = new Match(); + m3.setField(new DlType(ethType)); + m3.setField(new NwSrc(ip3, ipm3)); + m3.setField(new NwProtocol(IPProtocols.TCP.byteValue())); + + Match m3r = m3.reverse(); + Assert.assertTrue(m3.intersetcs(m3r)); + + Assert.assertTrue(m1.intersetcs(m2)); + Assert.assertTrue(m2.intersetcs(m1)); + Assert.assertFalse(m1.intersetcs(m3)); + Assert.assertTrue(m1.intersetcs(m3r)); + Assert.assertFalse(m3.intersetcs(m1)); + Assert.assertTrue(m3.intersetcs(m1.reverse())); + Assert.assertFalse(m2.intersetcs(m3)); + Assert.assertFalse(m3.intersetcs(m2)); + Assert.assertTrue(m2.intersetcs(m3r)); + + + Match i = m1.getIntersection(m2); + Assert.assertTrue(((Short)i.getField(DlType.TYPE).getValue()).equals(ethType)); + // Verify intersection of IP addresses is correct + Assert.assertTrue(((InetAddress)i.getField(NwSrc.TYPE).getValue()).equals(ip1)); + Assert.assertNull(i.getField(NwSrc.TYPE).getMask()); + + // Empty set + i = m2.getIntersection(m3); + Assert.assertNull(i); + + Match m4 = new Match(); + m4.setField(new DlType(ethType)); + m4.setField(new NwProtocol(IPProtocols.TCP.byteValue())); + m3.setField(new NwSrc(ip4, ipm4)); + Assert.assertTrue(m4.intersetcs(m3)); + + // Verify intersection of IP and IP mask addresses is correct + Match ii = m3.getIntersection(m4); + Assert.assertTrue(((InetAddress)ii.getField(NwSrc.TYPE).getValue()).equals(ip4)); + Assert.assertTrue(((InetAddress)ii.getField(NwSrc.TYPE).getMask()).equals(ipm4)); + + Match m5 = new Match(); + m5.setField(new DlType(ethType)); + m3.setField(new NwSrc(ip3, ipm3)); + m5.setField(new NwProtocol(IPProtocols.UDP.byteValue())); + Assert.assertFalse(m5.intersetcs(m3)); + Assert.assertFalse(m5.intersetcs(m4)); + Assert.assertTrue(m5.intersetcs(m5)); + Assert.assertFalse(m3.intersetcs(m5)); + Assert.assertFalse(m4.intersetcs(m5)); + + + Match i2 = m4.getIntersection(m3); + Assert.assertFalse(i2.isEmpty()); + Assert.assertFalse(i2.getMatchesList().isEmpty()); + Assert.assertTrue(((InetAddress)i2.getField(NwSrc.TYPE).getValue()).equals(ip3)); + Assert.assertTrue(((InetAddress)i2.getField(NwSrc.TYPE).getMask()).equals(ipm3)); + Assert.assertTrue(((Byte)i2.getField(NwProtocol.TYPE).getValue()).equals(IPProtocols.TCP.byteValue())); + + byte src[] = {(byte)0, (byte)0xab,(byte)0xbc,(byte)0xcd,(byte)0xde,(byte)0xef}; + byte dst[] = {(byte)0x10, (byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15}; + Short srcPort = (short)1024; + Short dstPort = (short)80; + + // Check identity + Match m6 = new Match(); + m6.setField(new DlSrc(src)); + m6.setField(new DlDst(dst)); + m6.setField(new NwSrc(ip2, ipm2)); + m6.setField(new NwDst(ip3, ipm3)); + m6.setField(new NwProtocol(IPProtocols.UDP.byteValue())); + m6.setField(new TpSrc(srcPort)); + m6.setField(new TpDst(dstPort)); + Assert.assertTrue(m6.intersetcs(m6)); + Assert.assertTrue(m6.getIntersection(m6).equals(m6)); + + // Empty match, represents the universal set (all packets) + Match u = new Match(); + Assert.assertEquals(m6.getIntersection(u), m6); + Assert.assertEquals(u.getIntersection(m6), m6); + + // No intersection with null match, empty set + Assert.assertNull(m6.getIntersection(null)); + } +}