From 387e3b71744c4bc4cbec7e822f725661b8e307b9 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Mon, 18 Nov 2019 16:24:31 +0530 Subject: [PATCH] Decoupling SFC from NetVirt Change-Id: I3583b9ab4d06c29f96cd3eb151cbe21fce6b9d4a Signed-off-by: Abhinav Gupta --- artifacts/pom.xml | 24 - .../CloudScVpnInterfaceListener.java | 4 +- docs/user-guide/features.rst | 6 +- features/netvirt-features/pom.xml | 22 - features/odl-netvirt-sfc/pom.xml | 58 -- features/pom.xml | 16 - pom.xml | 13 - resources/README | 1 - .../NetvirtSfc.json.postman_collection | 189 ---- .../NetvirtSfc.v2.json.postman_collection | 449 --------- resources/commons/README | 2 - resources/commons/readable_flows.py | 1 - resources/demo/netvirtsfc-env/README.md | 147 --- resources/demo/netvirtsfc-env/Vagrantfile | 34 - resources/demo/netvirtsfc-env/bootstrap.sh | 34 - resources/demo/netvirtsfc-env/checkdemo.sh | 16 - resources/demo/netvirtsfc-env/cleandemo.sh | 17 - resources/demo/netvirtsfc-env/cleanodl.sh | 3 - .../demo-asymmetric-chain/rest.py | 346 ------- resources/demo/netvirtsfc-env/dpdumpflows.py | 17 - resources/demo/netvirtsfc-env/dumpflows.sh | 17 - resources/demo/netvirtsfc-env/env.sh | 9 - resources/demo/netvirtsfc-env/flowcount.sh | 19 - .../images/asymmetric-sfc-demo.png | Bin 134503 -> 0 bytes .../netvirtsfc-env/infrastructure_launch.py | 167 ---- resources/demo/netvirtsfc-env/ovswork.sh | 84 -- resources/demo/netvirtsfc-env/pollflows.sh | 4 - .../demo/netvirtsfc-env/resetcontroller.sh | 11 - resources/demo/netvirtsfc-env/rest-clean.py | 141 --- resources/demo/netvirtsfc-env/setsfc.sh | 27 - resources/demo/netvirtsfc-env/startdemo.sh | 53 -- resources/demo/netvirtsfc-env/traceflow.sh | 1 - resources/demo/netvirtsfc-env/utils/hosts | 12 - .../netvirtsfc-env/utils/overlay-flows.sh | 34 - .../demo/netvirtsfc-env/utils/setuphosts.sh | 11 - resources/demo/netvirtsfc-env/vmclean.sh | 12 - .../odltools/odltools/mdsal/models/Modules.py | 14 - .../odltools/odltools/netvirt/services.py | 20 +- .../tools/odltools/odltools/netvirt/tables.py | 10 - sfc/classifier/api/pom.xml | 51 - .../api/src/main/yang/netvirt-sfc-acl.yang | 53 -- .../src/main/yang/netvirt-sfc-classifier.yang | 48 - .../api/src/main/yang/netvirt-sfc.yang | 15 - sfc/classifier/impl/pom.xml | 148 --- .../listeners/NetvirtSfcAclListener.java | 71 -- .../NetvirtSfcClassifierListener.java | 73 -- .../listeners/NetvirtSfcRspListener.java | 72 -- .../listeners/NetvirtSfcSfpListener.java | 72 -- .../classifier/providers/GeniusProvider.java | 378 -------- .../classifier/providers/NetvirtProvider.java | 94 -- .../providers/OpenFlow13Provider.java | 493 ---------- .../sfc/classifier/providers/SfcProvider.java | 196 ---- .../classifier/service/ClassifierService.java | 79 -- .../service/domain/ClassifierEntry.java | 273 ------ .../domain/api/ClassifierEntryRenderer.java | 126 --- .../domain/api/ClassifierRenderableEntry.java | 32 - .../service/domain/api/ClassifierState.java | 19 - .../service/domain/impl/ClassifierUpdate.java | 56 -- .../impl/ConfigurationClassifierImpl.java | 345 ------- .../service/domain/impl/GeniusRenderer.java | 74 -- .../service/domain/impl/OpenflowRenderer.java | 192 ---- .../impl/OperationalClassifierImpl.java | 86 -- .../sfc/classifier/utils/AclMatches.java | 551 ----------- .../classifier/utils/LastTaskExecutor.java | 41 - .../sfc/classifier/utils/OpenFlow13Utils.java | 442 --------- .../OSGI-INF/blueprint/sfc-classifier.xml | 22 - .../providers/GeniusProviderTest.java | 198 ---- .../providers/GeniusProviderTestParams.java | 29 - .../providers/NetvirtProviderTest.java | 134 --- .../providers/OpenFlow13ProviderTest.java | 690 -------------- .../classifier/providers/SfcProviderTest.java | 227 ----- .../providers/TestInterfaceManager.java | 68 -- .../providers/TestOdlInterfaceRpcService.java | 94 -- .../service/domain/ClassifierEntryTest.java | 180 ---- .../domain/impl/ClassifierUpdateTest.java | 68 -- .../sfc/classifier/utils/AclMatchesTest.java | 879 ------------------ .../utils/LastTaskExecutorTest.java | 88 -- sfc/classifier/pom.xml | 49 - sfc/pom.xml | 50 - sfc/translator/pom.xml | 74 -- .../DelegatingDataTreeListener.java | 103 -- .../translator/INeutronSfcDataProcessor.java | 41 - .../sfc/translator/NeutronMdsalHelper.java | 93 -- .../OpenStackSFCTranslatorProvider.java | 61 -- .../sfc/translator/SfcMdsalHelper.java | 227 ----- .../FlowClassifierTranslator.java | 182 ---- .../NeutronFlowClassifierListener.java | 74 -- .../portchain/NeutronPortChainListener.java | 212 ----- .../NeutronPortPairGroupListener.java | 63 -- .../portchain/NeutronPortPairListener.java | 89 -- .../portchain/PortChainTranslator.java | 95 -- .../portchain/PortPairGroupTranslator.java | 145 --- .../portchain/PortPairTranslator.java | 116 --- .../OSGI-INF/blueprint/sfc-translator.xml | 18 - 94 files changed, 14 insertions(+), 10480 deletions(-) delete mode 100644 features/odl-netvirt-sfc/pom.xml delete mode 100644 resources/commons/NetvirtSfc.json.postman_collection delete mode 100644 resources/commons/NetvirtSfc.v2.json.postman_collection delete mode 100755 resources/demo/netvirtsfc-env/README.md delete mode 100644 resources/demo/netvirtsfc-env/Vagrantfile delete mode 100644 resources/demo/netvirtsfc-env/bootstrap.sh delete mode 100755 resources/demo/netvirtsfc-env/checkdemo.sh delete mode 100755 resources/demo/netvirtsfc-env/cleandemo.sh delete mode 100755 resources/demo/netvirtsfc-env/cleanodl.sh delete mode 100755 resources/demo/netvirtsfc-env/demo-asymmetric-chain/rest.py delete mode 100755 resources/demo/netvirtsfc-env/dpdumpflows.py delete mode 100755 resources/demo/netvirtsfc-env/dumpflows.sh delete mode 100755 resources/demo/netvirtsfc-env/env.sh delete mode 100755 resources/demo/netvirtsfc-env/flowcount.sh delete mode 100644 resources/demo/netvirtsfc-env/images/asymmetric-sfc-demo.png delete mode 100755 resources/demo/netvirtsfc-env/infrastructure_launch.py delete mode 100755 resources/demo/netvirtsfc-env/ovswork.sh delete mode 100755 resources/demo/netvirtsfc-env/pollflows.sh delete mode 100755 resources/demo/netvirtsfc-env/resetcontroller.sh delete mode 100755 resources/demo/netvirtsfc-env/rest-clean.py delete mode 100755 resources/demo/netvirtsfc-env/setsfc.sh delete mode 100755 resources/demo/netvirtsfc-env/startdemo.sh delete mode 100755 resources/demo/netvirtsfc-env/traceflow.sh delete mode 100644 resources/demo/netvirtsfc-env/utils/hosts delete mode 100755 resources/demo/netvirtsfc-env/utils/overlay-flows.sh delete mode 100755 resources/demo/netvirtsfc-env/utils/setuphosts.sh delete mode 100755 resources/demo/netvirtsfc-env/vmclean.sh delete mode 100644 sfc/classifier/api/pom.xml delete mode 100644 sfc/classifier/api/src/main/yang/netvirt-sfc-acl.yang delete mode 100644 sfc/classifier/api/src/main/yang/netvirt-sfc-classifier.yang delete mode 100644 sfc/classifier/api/src/main/yang/netvirt-sfc.yang delete mode 100644 sfc/classifier/impl/pom.xml delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcAclListener.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcClassifierListener.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcRspListener.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcSfpListener.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProvider.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProvider.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13Provider.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProvider.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/ClassifierService.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntry.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierEntryRenderer.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierRenderableEntry.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierState.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdate.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/GeniusRenderer.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OpenflowRenderer.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OperationalClassifierImpl.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatches.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutor.java delete mode 100644 sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/OpenFlow13Utils.java delete mode 100644 sfc/classifier/impl/src/main/resources/OSGI-INF/blueprint/sfc-classifier.xml delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTestParams.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProviderTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13ProviderTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProviderTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestInterfaceManager.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestOdlInterfaceRpcService.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntryTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdateTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatchesTest.java delete mode 100644 sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutorTest.java delete mode 100644 sfc/classifier/pom.xml delete mode 100644 sfc/pom.xml delete mode 100644 sfc/translator/pom.xml delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/DelegatingDataTreeListener.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/INeutronSfcDataProcessor.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/NeutronMdsalHelper.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/OpenStackSFCTranslatorProvider.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcMdsalHelper.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/FlowClassifierTranslator.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/NeutronFlowClassifierListener.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortChainListener.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairGroupListener.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairListener.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortChainTranslator.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairGroupTranslator.java delete mode 100644 sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairTranslator.java delete mode 100644 sfc/translator/src/main/resources/OSGI-INF/blueprint/sfc-translator.xml diff --git a/artifacts/pom.xml b/artifacts/pom.xml index 8b741c9835..017928bc76 100644 --- a/artifacts/pom.xml +++ b/artifacts/pom.xml @@ -54,28 +54,4 @@ and is available at http://www.eclipse.org/legal/epl-v10.html - - - - sfc - - true - - - - - ${project.groupId} - odl-netvirt-sfc - ${project.version} - features - xml - - - - - - - no-sfc - - diff --git a/cloud-servicechain/impl/src/main/java/org/opendaylight/netvirt/cloudservicechain/listeners/CloudScVpnInterfaceListener.java b/cloud-servicechain/impl/src/main/java/org/opendaylight/netvirt/cloudservicechain/listeners/CloudScVpnInterfaceListener.java index 522bef3f1d..12e44d3a5d 100644 --- a/cloud-servicechain/impl/src/main/java/org/opendaylight/netvirt/cloudservicechain/listeners/CloudScVpnInterfaceListener.java +++ b/cloud-servicechain/impl/src/main/java/org/opendaylight/netvirt/cloudservicechain/listeners/CloudScVpnInterfaceListener.java @@ -73,7 +73,7 @@ public class CloudScVpnInterfaceListener return; } } catch (ReadFailedException e) { - LOG.error("Error reading the SFC information for VPN {}", vpnName, e); + LOG.error("Error reading the ServiceChaining information for VPN {}", vpnName, e); } break; } @@ -102,7 +102,7 @@ public class CloudScVpnInterfaceListener vpnScHandler.bindScfOnVpnInterface(vpnIfaceAdded.key().getName(), optScfInfoForVpn.get().getScfTag()); } catch (ReadFailedException e) { - LOG.error("Error reading the SFC information for VPN {}", vpnName, e); + LOG.error("Error reading the ServiceChaining information for VPN {}", vpnName, e); } } } diff --git a/docs/user-guide/features.rst b/docs/user-guide/features.rst index 8fd73211cc..f677ef7f05 100644 --- a/docs/user-guide/features.rst +++ b/docs/user-guide/features.rst @@ -124,10 +124,10 @@ Carbon Features ,,,, DPDK,,,Full,conn-track based SNAT not supported until ovs 2.8 ,,,, - SFC classifier,Datapath,NSH based,WIP, + Datapath,NSH based,WIP, ,,non-NSH based,WIP, - ,Northbound,openstack-sfc,WIP, - ,,ODL SFC models,WIP, + ,Northbound,WIP, + ,,WIP, ,,,, LBaaS,Octavia implementation,,Partial,"L2 supported, L3 Partially" ,ODL implementation,,Future, diff --git a/features/netvirt-features/pom.xml b/features/netvirt-features/pom.xml index 79b70dc398..029fd86b78 100644 --- a/features/netvirt-features/pom.xml +++ b/features/netvirt-features/pom.xml @@ -46,26 +46,4 @@ - - - sfc - - true - - - - ${project.groupId} - odl-netvirt-sfc - ${project.version} - xml - features - - - - - - no-sfc - - - diff --git a/features/odl-netvirt-sfc/pom.xml b/features/odl-netvirt-sfc/pom.xml deleted file mode 100644 index a4fdb0ca24..0000000000 --- a/features/odl-netvirt-sfc/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - org.opendaylight.odlparent - single-feature-parent - 6.0.1 - - - - org.opendaylight.netvirt - odl-netvirt-sfc - 0.10.0-SNAPSHOT - OpenDaylight :: NetVirt :: SFC - feature - 4.0.0 - - - - ${project.groupId} - odl-netvirt-openstack - ${project.version} - xml - features - - - org.opendaylight.sfc - odl-sfc-genius - 0.11.0-SNAPSHOT - xml - features - - - org.opendaylight.sfc - odl-sfc-openflow-renderer - 0.11.0-SNAPSHOT - xml - features - - - ${project.groupId} - sfc.classifier-impl - ${project.version} - - - ${project.groupId} - sfc.translator - ${project.version} - - - diff --git a/features/pom.xml b/features/pom.xml index a1e1fd172d..f82538a81d 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -29,20 +29,4 @@ odl-netvirt-openstack - - - sfc - - true - - - odl-netvirt-sfc - - - - - no-sfc - - - diff --git a/pom.xml b/pom.xml index a096be07fe..3cde576937 100644 --- a/pom.xml +++ b/pom.xml @@ -86,19 +86,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html - - sfc - - true - - - sfc - - - - - no-sfc - sonar-jacoco-aggregate diff --git a/resources/README b/resources/README index 9f4b2625e9..e41e36f894 100644 --- a/resources/README +++ b/resources/README @@ -14,7 +14,6 @@ DIRECTORY ORGANIZATION for Network Virtualization. +-- net-virt-providers : Mostly contains data-path programming functionality via OpenFlow or potentially other protocols. - +-- net-virt-sfc : SFC implementation using the OVSDB project. - ovsdb-ui : Contains the DLUX implementation for displaying network virtualization diff --git a/resources/commons/NetvirtSfc.json.postman_collection b/resources/commons/NetvirtSfc.json.postman_collection deleted file mode 100644 index f73f0cb8f0..0000000000 --- a/resources/commons/NetvirtSfc.json.postman_collection +++ /dev/null @@ -1,189 +0,0 @@ -{ - "id": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "name": "NetvirtSfc", - "requests": [ - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"netvirt-sfc-acl:redirect-sfc\": \"acl\"\n }\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\n", - "id": "19b44f74-e2ea-9267-50af-ad79b6309859", - "method": "PUT", - "name": "ietf-acl redirect-sfc", - "time": 1445298337983, - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"service-function-forwarders\": {\n \"service-function-forwarder\": [\n {\n \"name\": \"SFF1\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw2\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"type\": \"service-function-type:firewall\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.71\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun2\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.71\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n },\n {\n \"name\": \"SFF2\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw4\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"dpi-74\",\n \"type\": \"service-function-type:dpi\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.73\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun4\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.73\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "id": "1b067065-f0d5-d871-28cf-5e7e195eb463", - "method": "PUT", - "name": "service-function-forwarders", - "time": 1445302610648, - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"permit\": \"true\"\n\n }\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\n", - "id": "62e3b4d9-2672-e2bd-25c9-70bfb6771026", - "method": "PUT", - "name": "ietf-acl", - "time": 1445298397905, - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"classifiers\": {\n \"classifier\": [\n {\n \"name\": \"http-classifier\",\n \"acl\": \"http-acl\",\n \"sffs\": {\n \"sff\": [\n {\n \"name\": \"sff1\"\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "id": "718ed9fd-f7f3-3862-4a53-b12d83c880ae", - "method": "PUT", - "name": "Classifier", - "time": 1444924721709, - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"permit\": {}\n }\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\n", - "id": "7412ee0c-b116-5cf1-0646-efa65f0da784", - "method": "GET", - "name": "ietf-acl", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"classifiers\": {\n \"classifier\": [\n {\n \"name\": \"http-classifier\",\n \"acl\": \"http-acl\",\n \"sffs\": {\n \"sff\": [\n {\n \"name\": \"sff1\"\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "id": "76b32432-5a24-9d6d-8ba2-76eb816411af", - "method": "DELETE", - "name": "Classifier", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"netvirt-sfc-acl:redirect-sfc\": \"acl\"\n }\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\n", - "id": "99dc6bb5-f01a-64cd-a024-c333fdf82643", - "method": "DELETE", - "name": "ietf-acl redirect-sfc", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n\t\"sfc\": {\n \"name\": \"sfc1\"\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "id": "9d418a4b-197d-47c2-e85f-e68f6b5f5c40", - "method": "GET", - "name": "Sfc", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/netvirt-sfc:sfc/", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"classifiers\": {\n \"classifier\": [\n {\n \"name\": \"http-classifier\",\n \"acl\": \"http-acl\",\n \"sffs\": {\n \"sff\": [\n {\n \"name\": \"sff1\"\n }\n ]\n }\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "id": "b2d13061-80e0-ad8f-d0e6-d6939ea2b0a4", - "method": "GET", - "name": "Classifier", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"service-functions\": {\n \"service-function\": [\n {\n \"name\": \"firewall-72\",\n \"ip-mgmt-address\": \"192.168.50.72\",\n \"type\": \"service-function-type:firewall\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"2\",\n \"port\": 6633,\n \"ip\": \"192.168.50.72\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF1\"\n }\n ]\n },\n {\n \"name\": \"dpi-74\",\n \"ip-mgmt-address\": \"192.168.50.74\",\n \"type\": \"service-function-type:dpi\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"3\",\n \"port\": 6633,\n \"ip\": \"192.168.50.74\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF2\"\n }\n ]\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "id": "bf4f1148-5192-fd7d-3026-5a11668db75d", - "method": "PUT", - "name": "service-functions", - "time": 1445302596335, - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/service-function:service-functions", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"service-function-forwarders\": {\n \"service-function-forwarder\": [\n {\n \"name\": \"SFF1\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw2\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"type\": \"service-function-type:firewall\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.71\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun2\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.71\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n },\n {\n \"name\": \"SFF2\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw4\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"dpi-74\",\n \"type\": \"service-function-type:dpi\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.73\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun4\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.73\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "id": "e6542ed1-832c-71c9-fe74-2d25c9e7f7ad", - "method": "GET", - "name": "service-function-forwarders", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n\t\"sfc\": {\n \"name\": \"sfc1\"\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "id": "ea1c70a0-6528-862c-cabc-a9b187d483c7", - "method": "PUT", - "name": "Sfc", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/netvirt-sfc:sfc/", - "version": 2 - }, - { - "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2", - "data": "{\n \"service-functions\": {\n \"service-function\": [\n {\n \"name\": \"firewall-72\",\n \"ip-mgmt-address\": \"192.168.50.72\",\n \"type\": \"service-function-type:firewall\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"2\",\n \"port\": 6633,\n \"ip\": \"192.168.50.72\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF1\"\n }\n ]\n },\n {\n \"name\": \"dpi-74\",\n \"ip-mgmt-address\": \"192.168.50.74\",\n \"type\": \"service-function-type:dpi\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"3\",\n \"port\": 6633,\n \"ip\": \"192.168.50.74\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF2\"\n }\n ]\n }\n ]\n }\n}", - "dataMode": "raw", - "description": "", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "id": "fff50fa7-aa2d-71a4-db49-4ea10b82937e", - "method": "GET", - "name": "service-functions", - "responses": [], - "timestamp": 0, - "url": "http://localhost:8181/restconf/config/service-function:service-functions", - "version": 2 - } - ], - "timestamp": 1444922427094 -} diff --git a/resources/commons/NetvirtSfc.v2.json.postman_collection b/resources/commons/NetvirtSfc.v2.json.postman_collection deleted file mode 100644 index 25b967ab7e..0000000000 --- a/resources/commons/NetvirtSfc.v2.json.postman_collection +++ /dev/null @@ -1,449 +0,0 @@ -{ - "id": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "name": "NetVirtSfc-v2", - "description": "", - "order": [ - "308700a7-ff1c-4635-eef5-be962a31bb7d", - "a0908269-eb4a-79ac-90a3-d9837014dc6f", - "c6439834-d4e3-b569-e3af-e11a13cf5ae0", - "880e7cf6-1b22-16fd-162d-dba99eb77910", - "9c663816-487b-d648-d6e0-cf333507ec03", - "8372af4c-3ed1-5408-5cb8-3e2e6546b92f", - "3e5806d3-b1d1-8fae-81af-bab9f52b4dd8", - "a4036ce7-2261-69a4-45ed-f6e60e10aecd", - "90f3e0ce-1464-58d1-556a-c7fba7597542", - "49e03f2e-ce17-e943-c57c-03746a2dee49", - "769366b8-93af-6b74-0c79-8f8e8672187a", - "640c6c38-eb96-5c39-774e-b0e3345cd832", - "c78e9578-4076-1fd3-7066-38952cf28b8d", - "865d6bd4-720f-3a1c-bf69-051a81d508ed", - "a1bd4157-09e1-d6a8-2ee7-8c503747511c", - "c951da62-d97e-2438-1be6-eacb6ce6ef6c", - "9fe30104-b3b5-b60d-f906-d6a9b720aace", - "4b34ca17-3492-ba55-5cfc-0f8bc94f1e38", - "eae5bb63-d729-dd2b-05ab-6e531b3966d8", - "908af89a-15ef-0b17-13eb-d4070a7ca39d", - "484d3b61-1d92-b112-09de-221b0c517a30", - "93de65de-a212-abc2-05f2-e93de7d8eefa", - "2df4a6ef-2156-04e1-a7da-bd0337779322", - "51b325ea-5d06-a702-6873-815cda4484ce" - ], - "folders": [], - "timestamp": 1461185801291, - "owner": "516672", - "remoteLink": "", - "public": false, - "requests": [ - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "2df4a6ef-2156-04e1-a7da-bd0337779322", - "name": "access-lists rsp-name", - "description": "", - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "method": "PUT", - "headers": "Content-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1461204989896, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"httpAcl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"httpRule\",\n \"matches\": {\n \"source-port-range\": {\n \"lower-port\": 0,\n \"upper-port\": 0\n },\n \"protocol\": 6,\n \"destination-port-range\": {\n \"lower-port\": 80,\n \"upper-port\": 80\n }\n },\n \"actions\": {\n \"netvirt-sfc-acl:rsp-name\": \"SFC-Path_rsp\",\n \"netvirt-sfc-acl:render-rsp\": false\n }\n }\n ]\n }\n }\n ]\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "308700a7-ff1c-4635-eef5-be962a31bb7d", - "name": "netvirt-providers-config", - "description": "", - "url": "http://localhost:8181/restconf/config/netvirt-providers-config:netvirt-providers-config", - "method": "GET", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "3e5806d3-b1d1-8fae-81af-bab9f52b4dd8", - "name": "service-functions", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function:service-functions", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "484d3b61-1d92-b112-09de-221b0c517a30", - "name": "rendered-service-paths", - "description": "", - "url": "http://localhost:8181/restconf/operations/rendered-service-path:create-rendered-path", - "method": "POST", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1461205788284, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"input\": {\n \"name\": \"SFC-Path_rsp\",\n \"parent-service-function-path\": \"SFC-Path\",\n \"symmetric\": \"false\"\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "49e03f2e-ce17-e943-c57c-03746a2dee49", - "name": "service-function", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function:service-functions/service-function/firewall-72", - "method": "PUT", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"service-function\": [\n {\n \"name\": \"firewall-72\",\n \"type\": \"\\\"service-function-type:firewall\",\n \"ip-mgmt-address\": \"10.2.1.1\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"sf1\",\n \"service-function-forwarder\": \"sff1\",\n \"ip\": \"10.2.1.1\",\n \"port\": \"6633\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-ovs:ovs-port\": {\n \"port-id\": \"tap-123456789ab\"\n }\n }\n ]\n }\n ]\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "4b34ca17-3492-ba55-5cfc-0f8bc94f1e38", - "name": "service-function-paths", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-path:service-function-paths", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "51b325ea-5d06-a702-6873-815cda4484ce", - "name": "access-lists sfc-name", - "description": "", - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "method": "PUT", - "headers": "Content-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"httpAcl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"httpRule\",\n \"matches\": {\n \"source-port-range\": {\n \"lower-port\": 0,\n \"upper-port\": 0\n },\n \"protocol\": 6,\n \"destination-port-range\": {\n \"lower-port\": 80,\n \"upper-port\": 80\n }\n },\n \"actions\": {\n \"netvirt-sfc-acl:sfc-name\": \"SFC\",\n \"netvirt-sfc-acl:render-rsp\": false\n }\n }\n ]\n }\n }\n ]\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "640c6c38-eb96-5c39-774e-b0e3345cd832", - "name": "service-function-forwarders", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders", - "method": "PUT", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1461203784214, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"service-function-forwarders\": {\n \"service-function-forwarder\": [\n {\n \"name\": \"sff1\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"br-int\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"sff-sf-data-plane-locator\": {\n \"sff-dpl-name\": \"vxgpe\",\n \"sf-dpl-name\": \"sf1\"\n }\n }\n ],\n \"service-function-forwarder-ovs:ovs-node\": {\n \"node-id\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://192.168.50.70:6640']\"\n },\n \"service-node\": \"ovsdb1\",\n \"sff-data-plane-locator\": [\n {\n \"name\": \"vxgpe\",\n \"data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.70\",\n \"transport\": \"service-locator:vxlan-gpe\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"nsp\": \"flow\",\n \"nshc4\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc1\": \"flow\",\n \"key\": \"flow\",\n \"dst-port\": \"6633\",\n \"nsi\": \"flow\",\n \"remote-ip\": \"flow\"\n }\n }\n ]\n }\n ]\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "769366b8-93af-6b74-0c79-8f8e8672187a", - "name": "service-function-forwarders", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "8372af4c-3ed1-5408-5cb8-3e2e6546b92f", - "name": "netvirt:1", - "description": "", - "url": "http://localhost:8181/restconf/config/network-topology:network-topology", - "method": "PUT", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"network-topology\": {\n \"topology\": [\n {\n \"topology-id\": \"test:1\"\n }\n ]\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "865d6bd4-720f-3a1c-bf69-051a81d508ed", - "name": "service-function-forwarder", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders/service-function-forwarder/sff1", - "method": "PUT", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"service-function-forwarder\": [\n {\n \"name\": \"sff1\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"br-int\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"sff-sf-data-plane-locator\": {\n \"sff-dpl-name\": \"vxgpe\",\n \"sf-dpl-name\": \"sf1\"\n }\n }\n ],\n \"service-function-forwarder-ovs:ovs-node\": {\n \"node-id\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://192.168.50.70:6640']\"\n },\n \"service-node\": \"ovsdb1\",\n \"sff-data-plane-locator\": [\n {\n \"name\": \"vxgpe\",\n \"data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.70\",\n \"transport\": \"service-locator:vxlan-gpe\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"nsp\": \"flow\",\n \"nshc4\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc1\": \"flow\",\n \"key\": \"flow\",\n \"dst-port\": \"6633\",\n \"nsi\": \"flow\",\n \"remote-ip\": \"flow\"\n }\n }\n ]\n }\n ]\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "880e7cf6-1b22-16fd-162d-dba99eb77910", - "name": "sfc-of-renderer-config", - "description": "", - "url": "http://localhost:8181/restconf/config/sfc-of-renderer:sfc-of-renderer-config ", - "method": "PUT", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"sfc-of-renderer-config\": {\n \"sfc-of-app-egress-table-offset\": 11,\n \"sfc-of-table-offset\": 150\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "908af89a-15ef-0b17-13eb-d4070a7ca39d", - "name": "rendered-service-paths", - "description": "", - "url": "http://localhost:8181/restconf/operational/rendered-service-path:rendered-service-paths", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "90f3e0ce-1464-58d1-556a-c7fba7597542", - "name": "service-function", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function:service-functions/service-function/firewall-72", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "93de65de-a212-abc2-05f2-e93de7d8eefa", - "name": "access-lists", - "description": "", - "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists", - "method": "GET", - "headers": "Content-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "9c663816-487b-d648-d6e0-cf333507ec03", - "name": "netvirt:1", - "description": "", - "url": "http://localhost:8181/restconf/config/network-topology:network-topology", - "method": "GET", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "9fe30104-b3b5-b60d-f906-d6a9b720aace", - "name": "service-function-chains", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-chain:service-function-chains", - "method": "PUT", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"service-function-chains\": {\n \"service-function-chain\": [\n {\n \"name\": \"SFC\",\n \"symmetric\": false,\n \"sfc-service-function\": [\n {\n \"name\": \"firewall-abstract\",\n \"type\": \"firewall\"\n }\n ]\n }\n ]\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "a0908269-eb4a-79ac-90a3-d9837014dc6f", - "name": "netvirt-providers-config", - "description": "", - "url": "http://localhost:8181/restconf/config/netvirt-providers-config:netvirt-providers-config", - "method": "PUT", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"netvirt-providers-config\": {\n \"table-offset\": 1\n }\n}" - }, - { - "id": "a1bd4157-09e1-d6a8-2ee7-8c503747511c", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders/service-function-forwarder/sff1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1461268899936, - "name": "service-function-forwarder nodeId:uuid", - "description": "This form is when the OVSDB node has connected to ODL and its OVSDB NodeId has a uuid.\n\nTo get the uuid you first GET the topology under the ovsdb:1 root. Then parse the output looking for the node you are interested in. This is typically done by searching for the br-int node with the termination-point that matches the tap port of the vm on br-int. Once that br-int node is known the managed-by value is the ovs node to be used.", - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "responses": [], - "rawModeData": "{\n \"service-function-forwarder\": [\n {\n \"name\": \"sff1\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"br-int\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"sff-sf-data-plane-locator\": {\n \"sff-dpl-name\": \"vxgpe\",\n \"sf-dpl-name\": \"sf1\"\n }\n }\n ],\n \"service-function-forwarder-ovs:ovs-node\": {\n \"node-id\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://uuid/ca80bc1d-a26b-479f-8a8a-ca3ad052a152']\"\n },\n \"service-node\": \"ovsdb1\",\n \"sff-data-plane-locator\": [\n {\n \"name\": \"vxgpe\",\n \"data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.70\",\n \"transport\": \"service-locator:vxlan-gpe\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"nsp\": \"flow\",\n \"nshc4\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc1\": \"flow\",\n \"key\": \"flow\",\n \"dst-port\": \"6633\",\n \"nsi\": \"flow\",\n \"remote-ip\": \"flow\"\n }\n }\n ]\n }\n ]\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "a4036ce7-2261-69a4-45ed-f6e60e10aecd", - "name": "service-functions", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function:service-functions", - "method": "PUT", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1461189578583, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"service-functions\": {\n \"service-function\": [\n {\n \"name\": \"firewall-72\",\n \"type\": \"service-function-type:firewall\",\n \"ip-mgmt-address\": \"10.2.1.1\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"sf1\",\n \"service-function-forwarder\": \"sff1\",\n \"ip\": \"10.2.1.1\",\n \"port\": \"6633\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-ovs:ovs-port\": {\n \"port-id\": \"tap-123456789ab\"\n }\n }\n ]\n }\n ]\n }\n}" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "c6439834-d4e3-b569-e3af-e11a13cf5ae0", - "name": "sfc-of-renderer-config", - "description": "", - "url": "http://localhost:8181/restconf/config/sfc-of-renderer:sfc-of-renderer-config ", - "method": "GET", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "c78e9578-4076-1fd3-7066-38952cf28b8d", - "name": "service-function-forwarder", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders/service-function-forwarder/sff1", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "c951da62-d97e-2438-1be6-eacb6ce6ef6c", - "name": "service-function-chains", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-chain:service-function-chains", - "method": "GET", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2, - "preRequestScript": "", - "tests": "", - "rawModeData": "" - }, - { - "collectionId": "9b368883-a4fd-3844-f29c-f682ba9a8dfd", - "id": "eae5bb63-d729-dd2b-05ab-6e531b3966d8", - "name": "service-function-paths", - "description": "", - "url": "http://localhost:8181/restconf/config/service-function-path:service-function-paths", - "method": "PUT", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "data": [], - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1461206089630, - "preRequestScript": "", - "tests": "", - "rawModeData": "{\n \"service-function-paths\": {\n \"service-function-path\": [\n {\n \"name\": \"SFC-Path\",\n \"symmetric\": false,\n \"service-chain-name\": \"SFC\",\n \"starting-index\": 255\n }\n ]\n }\n}" - } - ] -} diff --git a/resources/commons/README b/resources/commons/README index 01fab737dd..5ec8949609 100644 --- a/resources/commons/README +++ b/resources/commons/README @@ -27,8 +27,6 @@ Contents - 3-Node-Cluster-Setup-Environment-Variables.postman_environment : Postman environment file that defines variables for Restconf request for southbound plugin running in 3 node cluster environment -- NetvirtSfc.json.postman_collection : Collection of REST-APIs to interact with Netvirt-Sfc. - - Ovsdb-HwvtepSouthbound-Collection.json.postman_collection : Collection contains Restconf request for doing CRUD operations (hwvtep global node, physical switch, logical switch, physical locator, and physical port) on hwvtepsouthbound plugin running in standalone controller. - Qos-and-Queue-Collection-Environment-Variables.postman_environment : Postman environment file that defines variables used by the Qos-and-Queue-Collection.json.postman_collection diff --git a/resources/commons/readable_flows.py b/resources/commons/readable_flows.py index 5d5126c2fe..9c407db95a 100755 --- a/resources/commons/readable_flows.py +++ b/resources/commons/readable_flows.py @@ -31,7 +31,6 @@ TABLE_NAME = { \ 0: 'CLASSIFIER',\ 20: 'GATEWAY_RESOLVER',\ 10: 'DIRECTOR',\ -10: 'SFC_CLASSIFIER',\ 20: 'ARP_RESPONDER',\ 30: 'INBOUND_NAT',\ 40: 'EGRESS_ACL',\ diff --git a/resources/demo/netvirtsfc-env/README.md b/resources/demo/netvirtsfc-env/README.md deleted file mode 100755 index 4836655a55..0000000000 --- a/resources/demo/netvirtsfc-env/README.md +++ /dev/null @@ -1,147 +0,0 @@ -#SETUP - -This is a demonstration / development environment for show-casing OpenDaylight OVSDB NETVIRT with ServiceFunctionChaining (SFC) - -git clone https://github.com/flavio-fernandes/netvirtsfc-env.git - -This demo setup can also be found under the the ovsdb repo of the Opendaylight project: - -``` -https://github.com/opendaylight/ovsdb/tree/master/resources/demo/netvirtsfc-env -``` - -This demo is analogous to the demo done by the group-based-policy project of Opendaylight. In fact, the kudos -for initially putting it together goes to our friends Keith, Thomas, and others responsible for GBP: - -``` -https://github.com/alagalah/gbpsfc-env -``` - -The initial installation may take some time, with vagrant and docker image downloads. - -After the first time it is very quick. - -1. Set up Vagrant. - * Edit env.sh for NUM_NODES. (Keep all other vars the same for this version) - Also set 'ODL_ROOT_DIR' to point to the directory ./openstack/net-virt-sfc/karaf/target/assembly - - That directory will be available when you build the ovsdb project, or where the karaf distro - got unzipped. - - * Each VM takes approximately 1G RAM, 2GB used HDD (40GB) - - * demo-asymmetric-chain: 6 VMs. - -2. From the 'netvirtsfc-env' directory do: -``` -source ./env.sh -vagrant up -``` - * This takes quite some time initially. - -3. Start controller. - * Currently it is expected that that controller runs on the machine hosting the vagrant VMs. - * Tested using ovsdb netvirt beryllium. - - * Set config for your setup: - - Use the script 'setsfc.sh' to make the changes below. You only need to do it once after build. - - * Modify the NetvirtSfc config.xml to start in standalone mode. (i.e. set of13provider to standalone) - * Modify the logging levels to help with troubleshooting - * Start ODL with the following feature loaded: odl-ovsdb-sfc-ui - - * Start controller by running bin/karaf and make sure the following features are installed -``` - cd $ODL_ROOT_DIR ; ./bin/karaf -``` - -``` - opendaylight-user@root>feature:list -i | grep ovsdb-sfc - odl-ovsdb-sfc-test | 1.2.1-SNAPSHOT | x | odl-ovsdb-sfc-test1.2.1-SNAPSHOT | OpenDaylight :: ovsdb-sfc-test - odl-ovsdb-sfc-api | 1.2.1-SNAPSHOT | x | odl-ovsdb-sfc-1.2.1-SNAPSHOT | OpenDaylight :: ovsdb-sfc :: api - odl-ovsdb-sfc | 1.2.1-SNAPSHOT | x | odl-ovsdb-sfc-1.2.1-SNAPSHOT | OpenDaylight :: ovsdb-sfc - odl-ovsdb-sfc-rest | 1.2.1-SNAPSHOT | x | odl-ovsdb-sfc-1.2.1-SNAPSHOT | OpenDaylight :: ovsdb-sfc :: REST - odl-ovsdb-sfc-ui | 1.2.1-SNAPSHOT | x | odl-ovsdb-sfc-1.2.1-SNAPSHOT | OpenDaylight :: ovsdb-sfc :: UI -``` - - Note that if you missed running 'setsfc.sh' ODL will operate in non-standalone mode, which is going - to make ovsdb netvirt work with openstack/tacker environments. - - * Run `log:tail | grep SfcL2Renderer` and wait until the following message appears in the log: -``` - successfully started the SfcL2Renderer plugin -``` - * Now you can ^C the log:tail if you wish - -##demo-asymmetric-chain - - * Service Chain classifying HTTP traffic. - * Traffic in the forward direction is chained and in the reverse direction the traffic uses the normal VxLAN tunnel - * 2 docker containers in the same tenant space - -![asymmetric-chain demo diag](https://raw.githubusercontent.com/flavio-fernandes/netvirtsfc-env/master/images/asymmetric-sfc-demo.png) - -VMs: -* netvirtsfc1: netvirt (client initiates transactions from here) -* netvirtsfc2: sff -* netvirtsfc3: "sf" -* netvirtsfc4: sff -* netvirtsfc5: "sf" -* netvirtsfc6: netvirt (run a server here) - -Containers: -* h35_2 is on netvirtsfc1. This host serves as the client. -* h35_4 is netvirtsfc6. This host serves as the webserver. - -To run, from host folder where Vagrantfile located do: - -`./startdemo.sh demo-asymmetric-chain` - -### To test by sending traffic: -Start a test HTTP server on h35_4 in VM 6. - -*(don't) forget double ENTER after `docker attach`* -```bash -vagrant ssh netvirtsfc6 -docker ps -docker attach h35_4 -python -m SimpleHTTPServer 80 -``` - -Ctrl-P-Q to detach from docker without stopping the SimpleHTTPServer, and logoff netvirtsfc6. - -Now start client traffic, either ping or make HTTP requests to the server on h36_4. - -```bash -vagrant ssh netvirtsfc1 -docker ps -docker attach h35_2 -ping 10.0.35.4 -curl 10.0.35.4 -while true; do curl 10.0.35.4; sleep 1; done -``` - -Ctrl-P-Q to detach from docker, leaving the client making HTTP requests, and logoff netvirtsfc1. - -Look around: use "vagrant ssh" to the various machines. To run wireshark, ssh to the vms using the -XY flags: -``` -vagrant ssh netvirtsfcX -- -XY (e.g.: vagrant ssh netvirtsfc1 -- -XY) -sudo wireshark & -``` - - * take packet captures on eth1, as that is the interface used for communication between vms. - * sudo ovs-dpctl dump-flows - - -### When finished from host folder where Vagrantfile located do: - -`./cleandemo.sh` - -If you like `vagrant destroy` will remove all VMs - -##Preparing to run another demo -1. In the vagrant directory, run cleandemo.sh -2. stop controller (logout of karaf) -3. Remove data, journal and snapshot directories from controller directory. -4. Restart tests starting with restarting the controller, install features, wait, as above. diff --git a/resources/demo/netvirtsfc-env/Vagrantfile b/resources/demo/netvirtsfc-env/Vagrantfile deleted file mode 100644 index a092140cd6..0000000000 --- a/resources/demo/netvirtsfc-env/Vagrantfile +++ /dev/null @@ -1,34 +0,0 @@ - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - odl=ENV['ODL'] - config.vm.provider "virtualbox" do |vb| - vb.memory = "512" - end - - # run our bootstrapping for the system - config.vm.provision 'shell', path: 'bootstrap.sh', :args => odl - - num_nodes = (ENV['NUM_NODES'] || 1).to_i - - # ip configuration - ip_base = (ENV['SUBNET'] || "192.168.50.") - ips = num_nodes.times.collect { |n| ip_base + "#{n+70}" } - - num_nodes.times do |n| - config.vm.define "netvirtsfc#{n+1}", autostart: true do |compute| - vm_ip = ips[n] - vm_index = n+1 - compute.vm.box = "ubuntu/trusty64" - compute.vm.hostname = "netvirtsfc#{vm_index}" - compute.vm.network "private_network", ip: "#{vm_ip}" - compute.vm.provider :virtualbox do |vb| - vb.memory = 512 - vb.customize ["modifyvm", :id, "--ioapic", "on"] - vb.cpus = 1 - end - end - end -end diff --git a/resources/demo/netvirtsfc-env/bootstrap.sh b/resources/demo/netvirtsfc-env/bootstrap.sh deleted file mode 100644 index a11d562428..0000000000 --- a/resources/demo/netvirtsfc-env/bootstrap.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# vim: sw=4 ts=4 sts=4 et tw=72 : - -echo "---> Updating operating system" -apt update -qq - -echo "---> Installing OVSDB Netvirt requirements" -apt install -y software-properties-common -qq -apt install -y python-software-properties -qq -apt install -y python-pip -qq -apt install -y git-core git -qq -apt install -y curl -qq - -echo "---> Installing wireshark" -apt install -y xbase-clients -qq -apt install -y wireshark -qq - -# docker -curl -sSL https://get.docker.com/ | sh - -cat < /etc/default/docker - DOCKER_NETWORK_OPTIONS='--bip=10.250.0.254/24' -EOL - -docker pull alagalah/odlpoc_ovs230 -# OVS -curl https://raw.githubusercontent.com/pritesh/ovs/nsh-v8/third-party/start-ovs-deb.sh | bash - -# this part is just for local spinup DON'T copy it to releng bootstrap.sh -pip install ipaddr -echo "export PATH=$PATH:/vagrant" >> /home/vagrant/.profile -echo "export ODL=$1" >> /home/vagrant/.profile -usermod -aG docker vagrant diff --git a/resources/demo/netvirtsfc-env/checkdemo.sh b/resources/demo/netvirtsfc-env/checkdemo.sh deleted file mode 100755 index 0e084950f7..0000000000 --- a/resources/demo/netvirtsfc-env/checkdemo.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -e - - -echo "Checking demo from $demo with vars:" -echo "Number of nodes: " $NUM_NODES -echo "Opendaylight Controller: " $ODL -echo "Base subnet: " $SUBNET - -for i in `seq 1 $NUM_NODES`; do - hostname="netvirtsfc"$i - echo $hostname "flow count: " - vagrant ssh $hostname -c "sudo ovs-ofctl dump-flows sw$i -OOpenFlow13 | wc -l " -done - diff --git a/resources/demo/netvirtsfc-env/cleandemo.sh b/resources/demo/netvirtsfc-env/cleandemo.sh deleted file mode 100755 index aa5b3d3443..0000000000 --- a/resources/demo/netvirtsfc-env/cleandemo.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -set -e - -for i in `seq 1 $NUM_NODES`; do - hostname="netvirtsfc"$i - switchname="sw"$i - echo $hostname - vagrant ssh $hostname -c "sudo ovs-vsctl del-br $switchname; sudo ovs-vsctl del-manager; sudo /vagrant/vmclean.sh" - -done - -./rest-clean.py - -if [ -f "demo.lock" ] ; then - rm demo.lock -fi diff --git a/resources/demo/netvirtsfc-env/cleanodl.sh b/resources/demo/netvirtsfc-env/cleanodl.sh deleted file mode 100755 index 95a9f0f415..0000000000 --- a/resources/demo/netvirtsfc-env/cleanodl.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -rm -rf ${ODL_ROOT_DIR}/{data,journal,snapshots}/* diff --git a/resources/demo/netvirtsfc-env/demo-asymmetric-chain/rest.py b/resources/demo/netvirtsfc-env/demo-asymmetric-chain/rest.py deleted file mode 100755 index c3355e6726..0000000000 --- a/resources/demo/netvirtsfc-env/demo-asymmetric-chain/rest.py +++ /dev/null @@ -1,346 +0,0 @@ -#!/usr/bin/python -import argparse -import requests,json -from requests.auth import HTTPBasicAuth -from subprocess import call -import time -import sys -import os - - -DEFAULT_PORT='8181' - - -USERNAME='admin' -PASSWORD='admin' - - -OPER_NODES='/restconf/operational/opendaylight-inventory:nodes/' -CONF_TENANT='/restconf/config/policy:tenants' - -def get(host, port, uri): - url='http://'+host+":"+port+uri - #print url - r = requests.get(url, auth=HTTPBasicAuth(USERNAME, PASSWORD)) - jsondata=json.loads(r.text) - return jsondata - -def put(host, port, uri, data, debug=False): - '''Perform a PUT rest operation, using the URL and data provided''' - - url='http://'+host+":"+port+uri - - headers = {'Content-type': 'application/yang.data+json', - 'Accept': 'application/yang.data+json'} - if debug == True: - print "PUT %s" % url - print json.dumps(data, indent=4, sort_keys=True) - r = requests.put(url, data=json.dumps(data), headers=headers, auth=HTTPBasicAuth(USERNAME, PASSWORD)) - if debug == True: - print r.text - r.raise_for_status() - -def post(host, port, uri, data, debug=False): - '''Perform a POST rest operation, using the URL and data provided''' - - url='http://'+host+":"+port+uri - headers = {'Content-type': 'application/yang.data+json', - 'Accept': 'application/yang.data+json'} - if debug == True: - print "POST %s" % url - print json.dumps(data, indent=4, sort_keys=True) - r = requests.post(url, data=json.dumps(data), headers=headers, auth=HTTPBasicAuth(USERNAME, PASSWORD)) - if debug == True: - print r.text - r.raise_for_status() - -def get_service_functions_uri(): - return "/restconf/config/service-function:service-functions" - -def get_service_functions_data(): - return { - "service-functions": { - "service-function": [ - { - "name": "firewall-72", - "ip-mgmt-address": "192.168.50.72", - "type": "service-function-type:firewall", - "nsh-aware": "true", - "sf-data-plane-locator": [ - { - "name": "sf1Dpl", - "port": 6633, - "ip": "192.168.50.72", - "transport": "service-locator:vxlan-gpe", - "service-function-forwarder": "SFF1" - } - ] - }, - { - "name": "dpi-74", - "ip-mgmt-address": "192.168.50.74", - "type": "service-function-type:dpi", - "nsh-aware": "true", - "sf-data-plane-locator": [ - { - "name": "sf2Dpl", - "port": 6633, - "ip": "192.168.50.74", - "transport": "service-locator:vxlan-gpe", - "service-function-forwarder": "SFF2" - } - ] - } - ] - } -} - -def get_service_function_forwarders_uri(): - return "/restconf/config/service-function-forwarder:service-function-forwarders" - -def get_service_function_forwarders_data(): - return { - "service-function-forwarders": { - "service-function-forwarder": [ - { - "name": "SFF1", - "service-node": "OVSDB2", - "service-function-forwarder-ovs:ovs-bridge": { - "bridge-name": "sw2" - }, - "service-function-dictionary": [ - { - "name": "firewall-72", - "sff-sf-data-plane-locator": { - "sff-dpl-name": "sfc-tun2", - "sf-dpl-name": "sf1Dpl" - } - } - ], - "sff-data-plane-locator": [ - { - "name": "sfc-tun2", - "data-plane-locator": { - "transport": "service-locator:vxlan-gpe", - "port": 6633, - "ip": "192.168.50.71" - }, - "service-function-forwarder-ovs:ovs-options": { - "remote-ip": "flow", - "dst-port": "6633", - "key": "flow", - "nsp": "flow", - "nsi": "flow", - "nshc1": "flow", - "nshc2": "flow", - "nshc3": "flow", - "nshc4": "flow" - } - } - ] - }, - { - "name": "SFF2", - "service-node": "OVSDB2", - "service-function-forwarder-ovs:ovs-bridge": { - "bridge-name": "sw4" - }, - "service-function-dictionary": [ - { - "name": "dpi-74", - "sff-sf-data-plane-locator": { - "sff-dpl-name": "sfc-tun4", - "sf-dpl-name": "sf2Dpl" - } - } - ], - "sff-data-plane-locator": [ - { - "name": "sfc-tun4", - "data-plane-locator": { - "transport": "service-locator:vxlan-gpe", - "port": 6633, - "ip": "192.168.50.73" - }, - "service-function-forwarder-ovs:ovs-options": { - "remote-ip": "flow", - "dst-port": "6633", - "key": "flow", - "nsp": "flow", - "nsi": "flow", - "nshc1": "flow", - "nshc2": "flow", - "nshc3": "flow", - "nshc4": "flow" - } - } - ] - } - ] - } -} - -def get_service_function_chains_uri(): - return "/restconf/config/service-function-chain:service-function-chains/" - -def get_service_function_chains_data(): - return { - "service-function-chains": { - "service-function-chain": [ - { - "name": "SFCNETVIRT", - "symmetric": "false", - "sfc-service-function": [ - { - "name": "firewall-abstract1", - "type": "service-function-type:firewall" - }, - { - "name": "dpi-abstract1", - "type": "service-function-type:dpi" - } - ] - } - ] - } -} - -def get_service_function_paths_uri(): - return "/restconf/config/service-function-path:service-function-paths/" - -def get_service_function_paths_data(): - return { - "service-function-paths": { - "service-function-path": [ - { - "name": "SFCNETVIRT-Path", - "service-chain-name": "SFCNETVIRT", - "starting-index": 255, - "symmetric": "false" - - } - ] - } -} - -def get_ietf_acl_uri(): - return "/restconf/config/ietf-access-control-list:access-lists" - -def get_ietf_acl_data(): - return { - "access-lists": { - "acl": [ - { - "acl-name": "http-acl", - "access-list-entries": { - "ace": [ - { - "rule-name": "http-rule", - "matches": { - "protocol": "6", - "destination-port-range": { - "lower-port": "80", - "upper-port": "80" - }, - }, - "actions": { - "netvirt-sfc-acl:sfc-name": "SFCNETVIRT" - } - } - ] - } - } - ] - } - } - -def get_classifier_uri(): - return "/restconf/config/netvirt-sfc-classifier:classifiers" - -def get_classifier_data(): - return { - "classifiers": { - "classifier": [ - { - "name": "http-classifier", - "acl": "http-acl", - "sffs": { - "sff": [ - { - "name": "SFF1" - } - ] - }, - "bridges": { - "bridge": [ - { - "name": "sw1", - "direction": "ingress" - }, - { - "name": "sw6", - "direction": "egress" - } - ] - } - } - ] - } - } - -def get_netvirt_sfc_uri(): - return "/restconf/config/netvirt-sfc:sfc/" - -def get_netvirt_sfc_data(): - return { - "sfc": { - "name": "sfc1" - } - } - -if __name__ == "__main__": - # Launch main menu - - - # Some sensible defaults - controller=os.environ.get('ODL') - if controller == None: - sys.exit("No controller set.") - else: - print "Contacting controller at %s" % controller - - #tenants=get(controller,DEFAULT_PORT,CONF_TENANT) - - print "sending service functions" - put(controller, DEFAULT_PORT, get_service_functions_uri(), get_service_functions_data(), True) - print "sending service function forwarders" - put(controller, DEFAULT_PORT, get_service_function_forwarders_uri(), get_service_function_forwarders_data(), True) - - print "sf's and sff's created" - time.sleep(5) - print "sending service function chains" - put(controller, DEFAULT_PORT, get_service_function_chains_uri(), get_service_function_chains_data(), True) - print "sending service function paths" - put(controller, DEFAULT_PORT, get_service_function_paths_uri(), get_service_function_paths_data(), True) - - print "sfc's and sfp's created" - time.sleep(5) - print "sending netvirt-sfc" - put(controller, DEFAULT_PORT, get_netvirt_sfc_uri(), get_netvirt_sfc_data(), True) - time.sleep(1) - print "sending ietf-acl" - put(controller, DEFAULT_PORT, get_ietf_acl_uri(), get_ietf_acl_data(), True) - time.sleep(1) - print "sending classifier" - put(controller, DEFAULT_PORT, get_classifier_uri(), get_classifier_data(), True) - - - # print "sending tunnel -- SKIPPED" - ## put(controller, DEFAULT_PORT, get_tunnel_uri(), get_tunnel_data(), True) - # print "sending tenant -- SKIPPED" - ## put(controller, DEFAULT_PORT, get_tenant_uri(), get_tenant_data(),True) - # print "registering endpoints -- SKIPPED" - ## for endpoint in get_endpoint_data(): - ## post(controller, DEFAULT_PORT, get_endpoint_uri(),endpoint,True) - - diff --git a/resources/demo/netvirtsfc-env/dpdumpflows.py b/resources/demo/netvirtsfc-env/dpdumpflows.py deleted file mode 100755 index a92034401f..0000000000 --- a/resources/demo/netvirtsfc-env/dpdumpflows.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/python - -from subprocess import check_output - - -def call_dpctl(): - cmd="ovs-dpctl dump-flows" - listcmd=cmd.split() - return check_output(listcmd) - -if __name__ == "__main__" : - flows=call_dpctl().split("recirc_id") - for flow in flows: - print flow - - - diff --git a/resources/demo/netvirtsfc-env/dumpflows.sh b/resources/demo/netvirtsfc-env/dumpflows.sh deleted file mode 100755 index fa27cc204f..0000000000 --- a/resources/demo/netvirtsfc-env/dumpflows.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -set -e -hostnum=${HOSTNAME#"netvirtsfc"} -sw="sw$hostnum" - -TABLE=$1 - -clear -ovs-ofctl dump-groups $sw -OOpenFlow13 -if [ "$TABLE" ] -then - ovs-ofctl dump-flows $sw -OOpenFlow13 table=$TABLE -else - ovs-ofctl dump-flows $sw -OOpenFlow13 -fi - diff --git a/resources/demo/netvirtsfc-env/env.sh b/resources/demo/netvirtsfc-env/env.sh deleted file mode 100755 index dac82d8bb4..0000000000 --- a/resources/demo/netvirtsfc-env/env.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -export NUM_NODES=6 -export ODL="192.168.50.1" -export SUBNET="192.168.50." - -#rootdir="/home/shague/git/ovsdb/openstack/net-virt-sfc/karaf/target/assembly" -rootdir="/Users/ffernand/ODL/projects/ovsdb.git/openstack/net-virt-sfc/karaf/target/assembly" - -export ODL_ROOT_DIR=$rootdir diff --git a/resources/demo/netvirtsfc-env/flowcount.sh b/resources/demo/netvirtsfc-env/flowcount.sh deleted file mode 100755 index 1b8ca9397c..0000000000 --- a/resources/demo/netvirtsfc-env/flowcount.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -hostnum=${HOSTNAME#"netvirtsfc"} -sw="sw$hostnum" -set -e -if [ "$1" ] -then - echo;echo "FLOWS:";ovs-ofctl dump-flows $sw -OOpenFlow13 table=$1 --rsort=priority - echo - printf "Flow count: " - echo $(($(ovs-ofctl dump-flows $sw -OOpenFlow13 table=$1 | wc -l)-1)) -else - echo;echo "FLOWS:";ovs-ofctl dump-flows $sw -OOpenFlow13 - printf "No table entered. $sw flow count: "; - echo $(($(ovs-ofctl dump-flows $sw -OOpenFlow13 | wc -l)-1)) - printf "\nTable0: base: "; echo $(($(ovs-ofctl dump-flows $sw -OOpenFlow13 table=0| wc -l)-1)) - printf "\nTable50: sfc: "; echo $(($(ovs-ofctl dump-flows $sw -OOpenFlow13 table=6| wc -l)-1)) -fi - diff --git a/resources/demo/netvirtsfc-env/images/asymmetric-sfc-demo.png b/resources/demo/netvirtsfc-env/images/asymmetric-sfc-demo.png deleted file mode 100644 index 5ccf5488093196f327837722bef06d4cb5bbefa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134503 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%0A1R= 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 diff --git a/resources/demo/netvirtsfc-env/infrastructure_launch.py b/resources/demo/netvirtsfc-env/infrastructure_launch.py deleted file mode 100755 index 81ab714b66..0000000000 --- a/resources/demo/netvirtsfc-env/infrastructure_launch.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/python - -import socket -import os -import re -import time -import sys -import ipaddr -import commands -from subprocess import call -from subprocess import check_output -from infrastructure_config import * - -def addController(sw, ip): - call(['ovs-vsctl', 'set-controller', sw, 'tcp:%s:6653' % ip ]) - -def addManager(ip): - cmd="ovs-vsctl set-manager tcp:%s:6640" % ip - listcmd=cmd.split() - print check_output(listcmd) - -def addSwitch(name, dpid=None): - call(['ovs-vsctl', 'add-br', name]) #Add bridge - if dpid: - if len(dpid) < 16: #DPID must be 16-bytes in later versions of OVS - filler='0000000000000000' - dpid=filler[:len(filler)-len(dpid)]+dpid - elif len(dpid) > 16: - print 'DPID: %s is too long' % dpid - sys.exit(3) - call(['ovs-vsctl','set','bridge', name,'other-config:datapath-id=%s'%dpid]) - -def addHost(net, switch, name, ip, mac): - containerID=launchContainer() - -#,OpenFlow12,OpenFlow10 -def setOFVersion(sw, version='OpenFlow13'): - call(['ovs-vsctl', 'set', 'bridge', sw, 'protocols={}'.format(version)]) - -def addTunnel(sw, port, sourceIp=None, remoteIp=None): - ifaceName = '{}-vxlan-0'.format(sw) - cmd = ['ovs-vsctl', 'add-port', sw, ifaceName, - '--', 'set', 'Interface', ifaceName, - 'type=vxlan', - 'options:local_ip=%s'%sourceIp, - 'options:remote_ip=%s'%remoteIp, - 'options:key=4096', - 'ofport_request=%s'%port] -# if sourceIp is not None: -# cmd.append('options:source_ip={}'.format(sourceIp)) - call(cmd) - -def addGpeTunnel(sw, sourceIp=None): - ifaceName = '{}-vxlangpe-0'.format(sw) - cmd = ['ovs-vsctl', 'add-port', sw, ifaceName, - '--', 'set', 'Interface', ifaceName, - 'type=vxlan', - 'options:remote_ip=flow', - 'options:dst_port=6633', - 'options:nshc1=flow', - 'options:nshc2=flow', - 'options:nshc3=flow', - 'options:nshc4=flow', - 'options:nsp=flow', - 'options:nsi=flow', - 'options:key=flow', - 'ofport_request=7'] -# if sourceIp is not None: -# cmd.append('options:source_ip={}'.format(sourceIp)) - call(cmd) - -def launchContainer(host,containerImage): - containerID= check_output(['docker','run','-d','--net=none','--name=%s'%host['name'],'-h',host['name'],'-t', '-i','--privileged=True',containerImage,'/bin/bash']) #docker run -d --net=none --name={name} -h {name} -t -i {image} /bin/bash - #print "created container:", containerID[:-1] - return containerID[:-1] #Remove extraneous \n from output of above - -def connectContainerToSwitch(sw,host,containerID,of_port): - hostIP=host['ip'] - mac=host['mac'] - nw = ipaddr.IPv4Network(hostIP) - broadcast = "{}".format(nw.broadcast) - router = "{}".format(nw.network + 1) - cmd=['/vagrant/ovswork.sh',sw,containerID,hostIP,broadcast,router,mac,of_port,host['name']] - if host.has_key('vlan'): - cmd.append(host['vlan']) - call(cmd) - -def doCmd(cmd): - listcmd=cmd.split() - print check_output(listcmd) - -def launch(switches, hosts, contIP='127.0.0.1'): - - for sw in switches: - addManager(contIP) - ports=0 - first_host=True - for host in hosts: - if host['switch'] == sw['name']: - if first_host: - dpid=sw['dpid'] - addSwitch(sw['name'],sw['dpid']) - setOFVersion(sw['name']) - addController(sw['name'], contIP) - addGpeTunnel(sw['name']) - if host['switch'] == "sw1": - addTunnel(sw['name'], 5, "192.168.50.70", "192.168.50.75") - if host['switch'] == "sw6": - addTunnel(sw['name'], 5, "192.168.50.75", "192.168.50.70") - first_host=False - containerImage=defaultContainerImage #from Config - if host.has_key('container_image'): #from Config - containerImage=host['container_image'] - containerID=launchContainer(host,containerImage) - ports+=1 - connectContainerToSwitch(sw['name'],host,containerID,str(ports)) - host['port-name']='vethl-'+host['name'] - print "Created container: %s with IP: %s. Connect using 'docker attach %s', disconnect with ctrl-p-q." % (host['name'],host['ip'],host['name']) - -if __name__ == "__main__" : -# print "Cleaning environment..." -# doCmd('/vagrant/clean.sh') - sw_index=int(socket.gethostname().split("netvirtsfc",1)[1])-1 - if sw_index in range(0,len(switches)+1): - - controller=os.environ.get('ODL') - sw_type = switches[sw_index]['type'] - sw_name = switches[sw_index]['name'] - if sw_type == 'netvirt': - print "*****************************" - print "Configuring %s as a NETVIRT node." % sw_name - print "*****************************" - print - launch([switches[sw_index]],hosts,controller) - print "*****************************" - doCmd('sudo /vagrant/utils/overlay-flows.sh') - print "*****************************" - print "OVS status:" - print "-----------" - print - doCmd('ovs-vsctl show') - doCmd('ovs-ofctl -O OpenFlow13 dump-flows %s'%sw_name) - print - print "Docker containers:" - print "------------------" - doCmd('docker ps') - print "*****************************" - elif sw_type == 'sff': - print "*****************************" - print "Configuring %s as an SFF." % sw_name - print "*****************************" - doCmd('sudo ovs-vsctl set-manager tcp:%s:6640' % controller) - time.sleep(1) - dpid=switches[sw_index]['dpid'] - addSwitch(sw_name,dpid) - setOFVersion(sw_name) - addController(sw_name, controller) - #addGpeTunnel(sw_name) - #doCmd('sudo ovs-vsctl set-manager tcp:%s:6640' % controller) - print - elif sw_type == 'sf': - print "*****************************" - print "Configuring %s as an SF." % sw_name - print "*****************************" - doCmd('sudo /vagrant/sf-config.sh') - #addGpeTunnel(switches[sw_index]['name']) - diff --git a/resources/demo/netvirtsfc-env/ovswork.sh b/resources/demo/netvirtsfc-env/ovswork.sh deleted file mode 100755 index 12d14b84b8..0000000000 --- a/resources/demo/netvirtsfc-env/ovswork.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash -set -e - -BRIDGE=$1 -GUEST_ID=$2 -IPADDR=$3 -BROADCAST=$4 -GWADDR=$5 -MAC=$6 -OF_PORT=$7 -GUESTNAME=$8 -VLANTAG=$9 - -[ "$IPADDR" ] || { - echo "Syntax:" - echo "pipework / [vlan tag]" - exit 1 -} - -# Step 1: Find the guest (for now, we only support LXC containers) -while read dev mnt fstype options dump fsck -do - [ "$fstype" != "cgroup" ] && continue - echo $options | grep -qw devices || continue - CGROUPMNT=$mnt -done < /proc/mounts - -[ "$CGROUPMNT" ] || { - echo "Could not locate cgroup mount point." - exit 1 -} - -N=$(find "$CGROUPMNT" -name "$GUEST_ID*" | wc -l) -case "$N" in - 0) - echo "Could not find any container matching $GUEST_ID" - exit 1 - ;; - 1) - true - ;; - *) - echo "Found more than one container matching $GUEST_ID" - exit 1 - ;; -esac - -NSPID=$(head -n 1 $(find "$CGROUPMNT" -name "$GUEST_ID*" | head -n 1)/tasks) -[ "$NSPID" ] || { - echo "Could not find a process inside container $GUEST_ID" - exit 1 -} - -# Step 2: Prepare the working directory -mkdir -p /var/run/netns -rm -f /var/run/netns/$NSPID -ln -s /proc/$NSPID/ns/net /var/run/netns/$NSPID - -# Step 3: Creating virtual interfaces -LOCAL_IFNAME=vethl-$GUESTNAME #$NSPID -GUEST_IFNAME=vethg-$GUESTNAME #$NSPID -ip link add name $LOCAL_IFNAME type veth peer name $GUEST_IFNAME -ip link set $LOCAL_IFNAME up - -# Step 4: Adding the virtual interface to the bridge -ip link set $GUEST_IFNAME netns $NSPID -if [ "$VLANTAG" ] -then - ovs-vsctl add-port $BRIDGE $LOCAL_IFNAME tag=$VLANTAG - echo $LOCAL_IFNAME -else - ovs-vsctl add-port $BRIDGE $LOCAL_IFNAME - echo $LOCAL_IFNAME -fi - -# Step 5: Configure netwroking within the container -ip netns exec $NSPID ip link set $GUEST_IFNAME name eth0 -ip netns exec $NSPID ip addr add $IPADDR broadcast $BROADCAST dev eth0 -ip netns exec $NSPID ifconfig eth0 hw ether $MAC -ip netns exec $NSPID ip addr add 127.0.0.1 dev lo -ip netns exec $NSPID ip link set eth0 up -ip netns exec $NSPID ip link set lo up -ip netns exec $NSPID ip route add default via $GWADDR - diff --git a/resources/demo/netvirtsfc-env/pollflows.sh b/resources/demo/netvirtsfc-env/pollflows.sh deleted file mode 100755 index cb5569d3f7..0000000000 --- a/resources/demo/netvirtsfc-env/pollflows.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -TABLE=$1 -watch -n 1 -d "sudo /vagrant/flowcount.sh $1" - diff --git a/resources/demo/netvirtsfc-env/resetcontroller.sh b/resources/demo/netvirtsfc-env/resetcontroller.sh deleted file mode 100755 index 07ff657bec..0000000000 --- a/resources/demo/netvirtsfc-env/resetcontroller.sh +++ /dev/null @@ -1,11 +0,0 @@ -hostnum=${HOSTNAME#"netvirtsfc"} -sw="sw$hostnum" -echo "Deleting controller for $sw" -ovs-vsctl del-controller $sw; -if [[ $? -ne 0 ]] ; then - exit 1 -fi -echo "Sleeping for 6sec..." -sleep 6 -echo "Setting controller to $ODL" -ovs-vsctl set-controller $sw tcp:$ODL:6653 diff --git a/resources/demo/netvirtsfc-env/rest-clean.py b/resources/demo/netvirtsfc-env/rest-clean.py deleted file mode 100755 index a70544aee1..0000000000 --- a/resources/demo/netvirtsfc-env/rest-clean.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/python -import argparse -import requests,json -from requests.auth import HTTPBasicAuth -from subprocess import call -import time -import sys -import os - - -DEFAULT_PORT='8181' - - -USERNAME='admin' -PASSWORD='admin' - - -OPER_NODES='/restconf/operational/opendaylight-inventory:nodes/' -CONF_TENANT='/restconf/config/policy:tenants' - -def get(host, port, uri): - url='http://'+host+":"+port+uri - #print url - r = requests.get(url, auth=HTTPBasicAuth(USERNAME, PASSWORD)) - jsondata=json.loads(r.text) - return jsondata - -def rest_delete(host, port, uri, debug=False): - '''Perform a DELETE rest operation, using the URL and data provided''' - url='http://'+host+":"+port+uri - headers = {'Content-type': 'application/yang.data+json', - 'Accept': 'application/yang.data+json'} - if debug == True: - print "DELETE %s" % url - try: - r = requests.delete(url, headers=headers, auth=HTTPBasicAuth(USERNAME, PASSWORD)) - except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as e: - print "oops: ", e - return - if debug == True: - print r.text - try: - r.raise_for_status() - except: - print "oops: ", sys.exc_info()[0] - - -def post(host, port, uri, data, debug=False): - '''Perform a POST rest operation, using the URL and data provided''' - url='http://'+host+":"+port+uri - headers = {'Content-type': 'application/yang.data+json', - 'Accept': 'application/yang.data+json'} - if debug == True: - print "POST %s" % url - print json.dumps(data, indent=4, sort_keys=True) - r = requests.post(url, data=json.dumps(data), headers=headers, auth=HTTPBasicAuth(USERNAME, PASSWORD)) - if debug == True: - print r.text - r.raise_for_status() - -def get_service_functions_uri(): - return "/restconf/config/service-function:service-functions" - -def get_service_function_forwarders_uri(): - return "/restconf/config/service-function-forwarder:service-function-forwarders" - -def get_service_function_chains_uri(): - return "/restconf/config/service-function-chain:service-function-chains/" - -def get_service_function_paths_uri(): - return "/restconf/config/service-function-path:service-function-paths/" - -def get_tenant_uri(): - return "/restconf/config/policy:tenants/policy:tenant/f5c7d344-d1c7-4208-8531-2c2693657e12" - -def get_tunnel_uri(): - return "/restconf/config/opendaylight-inventory:nodes" - -def get_endpoint_uri(): - return "/restconf/operations/endpoint:unregister-endpoint" - -def get_ietf_acl_uri(): - return "/restconf/config/ietf-access-control-list:access-lists" - -def get_classifier_uri(): - return "/restconf/config/netvirt-sfc-classifier:classifiers" - -def get_netvirt_sfc_uri(): - return "/restconf/config/netvirt-sfc:sfc/" - -if __name__ == "__main__": - # Launch main menu - - - # Some sensible defaults - controller=os.environ.get('ODL') - if controller == None: - sys.exit("No controller set.") - else: - print "Contacting controller at %s" % controller - - #resp=get(controller,DEFAULT_PORT,'/restconf/operational/endpoint:endpoints') - #l2_eps=resp['endpoints']['endpoint'] - #l3_eps=resp['endpoints']['endpoint-l3'] - - print "deleting service function paths" - rest_delete(controller, DEFAULT_PORT, get_service_function_paths_uri(), True) - - print "deleting service function chains" - rest_delete(controller, DEFAULT_PORT, get_service_function_chains_uri(), True) - - print "deleting service functions" - rest_delete(controller, DEFAULT_PORT, get_service_functions_uri(), True) - - print "deleting service function forwarders" - rest_delete(controller, DEFAULT_PORT, get_service_function_forwarders_uri(), True) - - #print "deleting tunnel" - #rest_delete(controller, DEFAULT_PORT, get_tunnel_uri(), True) - - #print "deleting tenant" - #rest_delete(controller, DEFAULT_PORT, get_tenant_uri(), True) - - #print "unregistering L2 endpoints" - #for endpoint in l2_eps: - #data={ "input": { "l2": [ { "l2-context": endpoint['l2-context'] ,"mac-address": endpoint['mac-address'] } ] } } - # post(controller, DEFAULT_PORT, get_endpoint_uri(),data,True) - - #print "unregistering L3 endpoints" - #for endpoint in l3_eps: - #data={ "input": { "l3": [ { "l3-context": endpoint['l3-context'] ,"ip-address": endpoint['ip-address'] } ] } } - # post(controller, DEFAULT_PORT, get_endpoint_uri(),data,True) - - print "deleting acl" - rest_delete(controller, DEFAULT_PORT, get_ietf_acl_uri(), True) - - print "deleting classifier" - rest_delete(controller, DEFAULT_PORT, get_classifier_uri(), True) - - print "deleting netvirt sfc" - rest_delete(controller, DEFAULT_PORT, get_netvirt_sfc_uri(), True) diff --git a/resources/demo/netvirtsfc-env/setsfc.sh b/resources/demo/netvirtsfc-env/setsfc.sh deleted file mode 100755 index b9f7e7b2b8..0000000000 --- a/resources/demo/netvirtsfc-env/setsfc.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -ovsdbversion="1.2.1-SNAPSHOT" - -# Attempt to keep l2switch from monkeying with the flows -#sed -i 's/true<\/is-proactive-flood-mode>/false<\/is-proactive-flood-mode>/' ${ODL_ROOT_DIR}/system/org/opendaylight/l2switch/arphandler/arphandler-config/$l2switchversion/arphandler-config-$l2switchversion-config.xml -#sed -i 's/true<\/is-install-lldp-flow>/false<\/is-install-lldp-flow>/' ${ODL_ROOT_DIR}/system/org/opendaylight/l2switch/loopremover/loopremover-config/$l2switchversion/loopremover-config-$l2switchversion-config.xml - -# enable NetvirtSfc for standalone mode -sed -i -e 's/[a-z]\{1,\}<\/of13provider>/standalone<\/of13provider>/g' ${ODL_ROOT_DIR}/system/org/opendaylight/ovsdb/openstack.net-virt-sfc-impl/$ovsdbversion/openstack.net-virt-sfc-impl-$ovsdbversion-config.xml - -# Automatically install the feature odl-ovsdb-sfc-ui upon ODL start -ODL_NETVIRT_SFC_KARAF_FEATURE='odl-ovsdb-sfc-ui' -ODLFEATUREMATCH=$(cat ${ODL_ROOT_DIR}/etc/org.apache.karaf.features.cfg | \ - grep -e "featuresBoot=" -e "featuresBoot =" | grep $ODL_NETVIRT_SFC_KARAF_FEATURE) -if [ "$ODLFEATUREMATCH" == "" ]; then - sed -i -e "/^featuresBoot[ ]*=/ s/$/,$ODL_NETVIRT_SFC_KARAF_FEATURE/" \ - ${ODL_ROOT_DIR}/etc/org.apache.karaf.features.cfg -fi - -# Set the logging levels for troubleshooting -logcfg=${ODL_ROOT_DIR}/etc/org.ops4j.pax.logging.cfg -echo "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc = TRACE" >> $logcfg -#echo "log4j.logger.org.opendaylight.ovsdb.lib = INFO" >> $logcfg -echo "log4j.logger.org.opendaylight.sfc = TRACE" >> $logcfg -echo "log4j.logger.org.opendaylight.openflowplugin.applications.statistics.manager.impl.StatListenCommitFlow = ERROR" >> $logcfg - diff --git a/resources/demo/netvirtsfc-env/startdemo.sh b/resources/demo/netvirtsfc-env/startdemo.sh deleted file mode 100755 index c0251af1d3..0000000000 --- a/resources/demo/netvirtsfc-env/startdemo.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -set -e - -demo=${1%/} - -echo $demo - -if [ -f "demo.lock" ]; then - echo "There is already a demo running:" - cat demo.lock - exit -fi - -cp $demo/infrastructure_config.py . -cp $demo/sf-config.sh . - -echo "Starting demo from $demo with vars:" -echo "Number of nodes: " $NUM_NODES -echo "Opendaylight Controller: " $ODL -echo "Base subnet: " $SUBNET - -for i in `seq 1 $NUM_NODES`; do -#for i in 1 6; do - hostname="netvirtsfc"$i - echo $hostname - vagrant ssh $hostname -c "sudo -E /vagrant/infrastructure_launch.py" -done - -# Looks like SFC is not including l2switch anymore so this is not needed. But just in case... -#sleep 5 -#echo "Clean l2switch flows" -#for i in 1 2 4 6; do -# hostname="netvirtsfc"$i -# sw="sw"$i -# echo $hostname -# vagrant ssh $hostname -c "sudo ovs-ofctl -O OpenFlow13 --strict del-flows br-int priority=1,arp" -# vagrant ssh $hostname -c "sudo ovs-ofctl -O OpenFlow13 --strict del-flows $sw priority=1,arp" -#done - -echo "Configuring controller..." -./$demo/rest.py - -sleep 5 -for i in 1 6; do - hostname="netvirtsfc"$i - sw="sw"$i - echo $hostname - vagrant ssh $hostname -c "sudo ovs-vsctl show; sudo ovs-ofctl -O OpenFlow13 dump-flows $sw" -done - -echo "$demo" > demo.lock - diff --git a/resources/demo/netvirtsfc-env/traceflow.sh b/resources/demo/netvirtsfc-env/traceflow.sh deleted file mode 100755 index ca2426e592..0000000000 --- a/resources/demo/netvirtsfc-env/traceflow.sh +++ /dev/null @@ -1 +0,0 @@ -ovs-appctl ofproto/trace $1 diff --git a/resources/demo/netvirtsfc-env/utils/hosts b/resources/demo/netvirtsfc-env/utils/hosts deleted file mode 100644 index 1ed1fb4453..0000000000 --- a/resources/demo/netvirtsfc-env/utils/hosts +++ /dev/null @@ -1,12 +0,0 @@ -127.0.0.1 localhost -192.168.50.70 netvirtsfc1 -192.168.50.71 netvirtsfc2 -192.168.50.72 netvirtsfc3 -192.168.50.73 netvirtsfc4 -192.168.50.74 netvirtsfc5 -192.168.50.75 netvirtsfc6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters diff --git a/resources/demo/netvirtsfc-env/utils/overlay-flows.sh b/resources/demo/netvirtsfc-env/utils/overlay-flows.sh deleted file mode 100755 index ed9050afaa..0000000000 --- a/resources/demo/netvirtsfc-env/utils/overlay-flows.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -# Add flows for the normal overlay that Netvirt would have added -# sw1: h35_2, dl_src=00:00:00:00:35:02 -# sw6: h35_4, dl_src=00:00:00:00:35:04 - -set -e -hostnum=${HOSTNAME#"netvirtsfc"} -sw="sw$hostnum" - -if [ "$hostnum" -eq "1" ]; then - # ARP responder for h35_4 - sudo ovs-ofctl -O OpenFlow13 add-flow $sw "table=0,arp,arp_tpa=10.0.35.4,arp_op=1 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:00:00:00:00:35:04->eth_src,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],load:0x000000003504->NXM_NX_ARP_SHA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0x0a002304->NXM_OF_ARP_SPA[],IN_PORT" - - #port=$(ip -o link | grep veth | awk '{print$2}' | sed 's/://') - # l2 forward of local traffic to the normal vxlan - sudo ovs-ofctl -O OpenFlow13 add-flow $sw "table=0,priority=150,in_port=1,dl_src=00:00:00:00:35:02,dl_dst=00:00:00:00:35:04,actions=output:5" - - # l2 forward of incoming vxlan traffic to the local port - sudo ovs-ofctl -O OpenFlow13 add-flow $sw "table=0,priority=150,in_port=5,dl_src=00:00:00:00:35:04,dl_dst=00:00:00:00:35:02,actions=output:1" - -elif [ "$hostnum" -eq "6" ]; then - # ARP responder for h35_4 - sudo ovs-ofctl -O OpenFlow13 add-flow $sw "table=0,arp,arp_tpa=10.0.35.2,arp_op=1 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:00:00:00:00:35:02->eth_src,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],load:0x000000003502->NXM_NX_ARP_SHA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0x0a002302->NXM_OF_ARP_SPA[],IN_PORT" - - # l2 forward of local traffic to the normal vxlan - sudo ovs-ofctl -O OpenFlow13 add-flow $sw "table=0,priority=150,in_port=1,dl_src=00:00:00:00:35:04,dl_dst=00:00:00:00:35:02,actions=output:5" - - # l2 forward of incoming vxlan traffic to the local port - sudo ovs-ofctl -O OpenFlow13 add-flow $sw "table=0,priority=150,in_port=5,dl_src=00:00:00:00:35:02,dl_dst=00:00:00:00:35:04,actions=output:1" - -else - echo "Invalid SF for this demo"; - exit -fi diff --git a/resources/demo/netvirtsfc-env/utils/setuphosts.sh b/resources/demo/netvirtsfc-env/utils/setuphosts.sh deleted file mode 100755 index 5e481bea59..0000000000 --- a/resources/demo/netvirtsfc-env/utils/setuphosts.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -e - -for i in `seq 1 $NUM_NODES`; do - hostname="netvirtsfc"$i - echo $hostname - vagrant ssh $hostname -c "sudo cp /vagrant/utils/hosts /etc/hosts" -done - - diff --git a/resources/demo/netvirtsfc-env/vmclean.sh b/resources/demo/netvirtsfc-env/vmclean.sh deleted file mode 100755 index 3974b386aa..0000000000 --- a/resources/demo/netvirtsfc-env/vmclean.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -docker stop -t=1 $(docker ps -a -q) > /dev/null 2>&1 -docker rm $(docker ps -a -q) > /dev/null 2>&1 - -/etc/init.d/openvswitch-switch stop > /dev/null -rm /etc/openvswitch/conf.db > /dev/null -/etc/init.d/openvswitch-switch start > /dev/null - - -ovs-vsctl show - diff --git a/resources/tools/odltools/odltools/mdsal/models/Modules.py b/resources/tools/odltools/odltools/mdsal/models/Modules.py index 35eccdf7f7..3f1449b415 100644 --- a/resources/tools/odltools/odltools/mdsal/models/Modules.py +++ b/resources/tools/odltools/odltools/mdsal/models/Modules.py @@ -63,17 +63,3 @@ netvirt_data_models = [ 'operational/odl-nat:intext-ip-map', 'operational/opendaylight-inventory:nodes' ] - -netvirt_sfc_data_models = [ - 'config/service-function-chain:service-function-chains', - 'config/service-function-classifier:service-function-classifiers', - 'config/service-function-forwarder:service-function-forwarders', - 'config/service-function-group:service-function-groups', - 'config/service-function-mapping:sff-dpl-by-sf-dpl-mappings', - 'config/service-function-path:service-function-paths', - 'config/service-function-path-metadata:service-function-metadata', - 'config/service-function-type:service-function-types', - 'config/service-function:service-functions', - 'config/sfc-of-renderer:sfc-of-renderer-config', - 'operational/rendered-service-path:rendered-service-path' -] diff --git a/resources/tools/odltools/odltools/netvirt/services.py b/resources/tools/odltools/odltools/netvirt/services.py index cfc08b93de..703d3229d5 100644 --- a/resources/tools/odltools/odltools/netvirt/services.py +++ b/resources/tools/odltools/odltools/netvirt/services.py @@ -1,16 +1,14 @@ services = { 0: None, - 1: 'SFC', - 2: 'ACL', - 3: 'IN_CTRS', - 4: 'SFC_CLASS', - 5: 'DHCP', - 6: 'QoS', - 7: 'IPv6', - 8: 'COE', - 9: 'L3VPN', - 10: 'ELAN', - 11: 'L3VPN6' + 1: 'ACL', + 2: 'IN_CTRS', + 3: 'DHCP', + 4: 'QoS', + 5: 'IPv6', + 6: 'COE', + 7: 'L3VPN', + 8: 'ELAN', + 9: 'L3VPN6' } diff --git a/resources/tools/odltools/odltools/netvirt/tables.py b/resources/tools/odltools/odltools/netvirt/tables.py index ab9ccf1a74..fe17ef6cfa 100644 --- a/resources/tools/odltools/odltools/netvirt/tables.py +++ b/resources/tools/odltools/odltools/netvirt/tables.py @@ -34,14 +34,7 @@ tables = { 75: "SCF_CHAIN_FWD", 80: "L3_INTF", 81: "ARP_RESPONDER", - 82: "SFC_TRANS_CLASS", - 83: "SFC_TRANS_IN", - 84: "SFC_TRANS_PMAP", - 86: "SFC_TRANS_PMAP_NHOP", - 87: "SFC_TRANS_EG", 90: "QOS_DSCP", - 100: "SFC_IN_CLASS_FILTER", - 101: "SFC_IN_CLASS_ACL", 210: "IN_ACL_ASPF", 211: "IN_ACL_CTRK_CLASS", 212: "IN_ACL_CTRK_SNDR", @@ -52,9 +45,6 @@ tables = { 217: "IN_ACL_CMTR", 219: "IN_CTRS", 220: "EG_LPORT_DISP", - 221: "EG_SFC_CLASS_FLTR", - 222: "EG_SFC_CLASS_NHOP", - 223: "EG_SFC_CLASS_EG", 230: "EG_POL_CLASS", 231: "EG_POL_RT", 239: "EG_ACL_DUMMY", diff --git a/sfc/classifier/api/pom.xml b/sfc/classifier/api/pom.xml deleted file mode 100644 index 0c8f378150..0000000000 --- a/sfc/classifier/api/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - org.opendaylight.netvirt - binding-parent - 0.10.0-SNAPSHOT - ../../../commons/binding-parent - - - sfc.classifier-api - ODL :: netvirt :: ${project.artifactId} - bundle - 4.0.0 - - - - org.opendaylight.mdsal.model - ietf-access-control-list - - - org.opendaylight.mdsal.model - yang-ext - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - - org.opendaylight.yang.gen.v1.* - - - - - - - diff --git a/sfc/classifier/api/src/main/yang/netvirt-sfc-acl.yang b/sfc/classifier/api/src/main/yang/netvirt-sfc-acl.yang deleted file mode 100644 index a479b18d2a..0000000000 --- a/sfc/classifier/api/src/main/yang/netvirt-sfc-acl.yang +++ /dev/null @@ -1,53 +0,0 @@ -module netvirt-sfc-acl { - yang-version 1; - namespace "urn:opendaylight:netvirt:sfc:acl"; - prefix "acl"; - - import ietf-access-control-list { prefix ietf-acl; revision-date 2016-02-18; } - import yang-ext { prefix ext; } - - revision "2015-01-05" { - description "Initial revision of netvirt extensions to ietf-acl model"; - } - - augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:matches" { - description "Neutron network uuid"; - ext:augment-identifier "neutron-network"; - leaf network-uuid { - type string; - } - } - - augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:matches" { - description "Match traffic based on its source or destination neutron port"; - ext:augment-identifier "neutron-ports"; - leaf source-port-uuid { - type string; - } - leaf destination-port-uuid { - type string; - } - } - - grouping netvirtsfc-acl-actions { - leaf sfc-name { - type string; - } - leaf sfp-name { - type string; - } - leaf rsp-name { - type string; - } - leaf render-rsp { - type boolean; - default "false"; - } - } - - augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:actions" { - description "Redirect traffic to SFC identified by either SFC, SFP or RSP"; - ext:augment-identifier "redirect-to-sfc"; - uses netvirtsfc-acl-actions; - } -} diff --git a/sfc/classifier/api/src/main/yang/netvirt-sfc-classifier.yang b/sfc/classifier/api/src/main/yang/netvirt-sfc-classifier.yang deleted file mode 100644 index c9f4564b07..0000000000 --- a/sfc/classifier/api/src/main/yang/netvirt-sfc-classifier.yang +++ /dev/null @@ -1,48 +0,0 @@ -module netvirt-sfc-classifier { - yang-version 1; - namespace "urn:opendaylight:netvirt:sfc:classifier"; - prefix "classifier"; - - revision "2015-01-05" { - description "Initial revision of netvirt classifier model"; - } - - container classifiers { - description "Classifier container which represents the ACL being applied, - attachment point and the associated chain"; - - list classifier { - description "A list of SFC classifiers"; - key "name"; - leaf name { - type string; - } - leaf acl { - type string; - } - container sffs { - list sff { - description "The classifier will be attached to these SFFs"; - key "name"; - leaf name { - type string; - } - } - } - container bridges { - list bridge { - key "name"; - leaf name { - type string; - } - leaf direction { - type enumeration { - enum ingress; - enum egress; - } - } - } - } - } - } -} diff --git a/sfc/classifier/api/src/main/yang/netvirt-sfc.yang b/sfc/classifier/api/src/main/yang/netvirt-sfc.yang deleted file mode 100644 index e00ddb6239..0000000000 --- a/sfc/classifier/api/src/main/yang/netvirt-sfc.yang +++ /dev/null @@ -1,15 +0,0 @@ -module netvirt-sfc { - yang-version 1; - namespace "urn:opendaylight:params:xml:ns:yang:netvirt:sfc"; - prefix "netvirt-sfc"; - - revision "2015-01-05" { - description "Initial revision of the netvirt sfc model"; - } - - container sfc { - leaf name { - type string; - } - } -} diff --git a/sfc/classifier/impl/pom.xml b/sfc/classifier/impl/pom.xml deleted file mode 100644 index ac52e5a8e4..0000000000 --- a/sfc/classifier/impl/pom.xml +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - org.opendaylight.netvirt - binding-parent - 0.10.0-SNAPSHOT - ../../../commons/binding-parent - - - sfc.classifier-impl - ODL :: netvirt :: ${project.artifactId} - bundle - 4.0.0 - - - 0.11.0-SNAPSHOT - - - - - org.opendaylight.genius - interfacemanager-api - ${genius.version} - - - org.opendaylight.genius - mdsalutil-api - ${genius.version} - - - org.opendaylight.infrautils - inject - ${infrautils.version} - - - org.opendaylight.mdsal.binding.model.iana - iana-if-type - - - org.opendaylight.mdsal.model - ietf-packet-fields - - - org.opendaylight.mdsal.model - ietf-topology - - - ${project.groupId} - sfc.classifier-api - ${project.version} - - - ${project.groupId} - neutronvpn-api - ${project.version} - - - org.opendaylight.openflowplugin - openflowjava-extension-nicira - - - org.opendaylight.openflowplugin - openflowplugin-extension-nicira - - - org.opendaylight.openflowplugin.model - model-flow-base - - - org.opendaylight.openflowplugin.model - model-flow-service - - - org.opendaylight.ovsdb - southbound-api - ${ovsdb.version} - - - org.opendaylight.ovsdb - southbound-impl - ${ovsdb.version} - - - org.opendaylight.sfc - sfc-model - ${sfc.version} - - - org.opendaylight.sfc - sfc-provider - ${sfc.version} - - - - - org.opendaylight.yangtools - testutils - test - - - org.opendaylight.controller - sal-binding-broker-impl - test-jar - test - - - org.opendaylight.controller - sal-binding-broker-impl - test - - - com.google.guava - guava-testlib - - - - - - - org.apache.aries.blueprint - blueprint-maven-plugin - - - org.apache.felix - maven-bundle-plugin - true - - - - - - - - - - diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcAclListener.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcAclListener.java deleted file mode 100644 index ca84a27044..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcAclListener.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat, 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.netvirt.sfc.classifier.listeners; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; -import org.opendaylight.netvirt.sfc.classifier.service.ClassifierService; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Data tree listener for AccessList. - */ -@Singleton -public class NetvirtSfcAclListener - extends AsyncDataTreeChangeListenerBase { - - private final DataBroker dataBroker; - private final ClassifierService classifierService; - - @Inject - public NetvirtSfcAclListener(final DataBroker dataBroker, final ClassifierService classifierService) { - super(Acl.class, NetvirtSfcAclListener.class); - this.dataBroker = dataBroker; - this.classifierService = classifierService; - } - - @Override - @PostConstruct - public void init() { - registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker); - } - - @Override - protected InstanceIdentifier getWildCardPath() { - return InstanceIdentifier - .create(AccessLists.class) - .child(Acl.class); - } - - @Override - protected NetvirtSfcAclListener getDataTreeChangeListener() { - return this; - } - - @Override - protected void add(InstanceIdentifier key, Acl acl) { - classifierService.updateAll(); - } - - @Override - protected void remove(InstanceIdentifier key, Acl acl) { - classifierService.updateAll(); - } - - @Override - protected void update(InstanceIdentifier key, Acl aclBefore, Acl aclAfter) { - classifierService.updateAll(); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcClassifierListener.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcClassifierListener.java deleted file mode 100644 index b39e8ce0a3..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcClassifierListener.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat, 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.netvirt.sfc.classifier.listeners; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; -import org.opendaylight.netvirt.sfc.classifier.service.ClassifierService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.classifier.rev150105.Classifiers; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.classifier.rev150105.classifiers.Classifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Data tree listener for Classifier. - */ -@Singleton -public class NetvirtSfcClassifierListener - extends AsyncDataTreeChangeListenerBase { - - private final DataBroker dataBroker; - private final ClassifierService classifierService; - - @Inject - public NetvirtSfcClassifierListener(final DataBroker dataBroker, final ClassifierService classifierService) { - super(Classifier.class, NetvirtSfcClassifierListener.class); - - this.dataBroker = dataBroker; - this.classifierService = classifierService; - } - - @Override - @PostConstruct - public void init() { - registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker); - } - - @Override - protected InstanceIdentifier getWildCardPath() { - return InstanceIdentifier - .create(Classifiers.class) - .child(Classifier.class); - } - - @Override - protected NetvirtSfcClassifierListener getDataTreeChangeListener() { - return this; - } - - @Override - protected void add(InstanceIdentifier key, Classifier classifier) { - classifierService.updateAll(); - } - - @Override - protected void remove(InstanceIdentifier key, Classifier classifier) { - classifierService.updateAll(); - } - - @Override - protected void update(InstanceIdentifier key, Classifier classifierBefore, - Classifier classifierAfter) { - classifierService.updateAll(); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcRspListener.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcRspListener.java deleted file mode 100644 index edbc89734f..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcRspListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat, 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.netvirt.sfc.classifier.listeners; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; -import org.opendaylight.netvirt.sfc.classifier.service.ClassifierService; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Data tree listener for AccessList. - */ -@Singleton -public class NetvirtSfcRspListener extends AsyncDataTreeChangeListenerBase { - - private final DataBroker dataBroker; - private final ClassifierService classifierService; - - @Inject - public NetvirtSfcRspListener(final DataBroker dataBroker, final ClassifierService classifierService) { - super(RenderedServicePath.class, NetvirtSfcRspListener.class); - - this.dataBroker = dataBroker; - this.classifierService = classifierService; - } - - @Override - @PostConstruct - public void init() { - registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker); - } - - @Override - protected InstanceIdentifier getWildCardPath() { - return InstanceIdentifier - .create(RenderedServicePaths.class) - .child(RenderedServicePath.class); - } - - @Override - protected NetvirtSfcRspListener getDataTreeChangeListener() { - return this; - } - - @Override - protected void add(InstanceIdentifier key, RenderedServicePath rsp) { - classifierService.updateAll(); - } - - @Override - protected void remove(InstanceIdentifier key, RenderedServicePath rsp) { - classifierService.updateAll(); - } - - @Override - protected void update(InstanceIdentifier key, RenderedServicePath rspBefore, - RenderedServicePath rspAfter) { - classifierService.updateAll(); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcSfpListener.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcSfpListener.java deleted file mode 100644 index 74edc9324a..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/listeners/NetvirtSfcSfpListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * 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.netvirt.sfc.classifier.listeners; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; -import org.opendaylight.netvirt.sfc.classifier.service.ClassifierService; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsState; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.state.ServiceFunctionPathState; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Data tree listener for AccessList. - */ -@Singleton -public class NetvirtSfcSfpListener extends - AsyncDataTreeChangeListenerBase { - - private final DataBroker dataBroker; - private final ClassifierService classifierService; - - @Inject - public NetvirtSfcSfpListener(final DataBroker dataBroker, final ClassifierService classifierService) { - super(ServiceFunctionPathState.class, NetvirtSfcSfpListener.class); - - this.dataBroker = dataBroker; - this.classifierService = classifierService; - } - - @Override - @PostConstruct - public void init() { - registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker); - } - - @Override - protected InstanceIdentifier getWildCardPath() { - return InstanceIdentifier - .create(ServiceFunctionPathsState.class) - .child(ServiceFunctionPathState.class); - } - - @Override - protected NetvirtSfcSfpListener getDataTreeChangeListener() { - return this; - } - - @Override - protected void add(InstanceIdentifier key, ServiceFunctionPathState sfp) { - classifierService.updateAll(); - } - - @Override - protected void remove(InstanceIdentifier key, ServiceFunctionPathState sfp) { - classifierService.updateAll(); - } - - @Override - protected void update(InstanceIdentifier key, ServiceFunctionPathState sfpBefore, - ServiceFunctionPathState sfpAfter) { - classifierService.updateAll(); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProvider.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProvider.java deleted file mode 100644 index 8e791e882f..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProvider.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import com.google.common.net.InetAddresses; -import java.math.BigInteger; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.get.dpn._interface.list.output.Interfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.bound.services.instruction.instruction.apply.actions._case.apply.actions.action.action.ServiceBindingNxActionRegLoadApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.Uint64; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class GeniusProvider { - private static final Logger LOG = LoggerFactory.getLogger(GeniusProvider.class); - public static final String OPTION_KEY_REMOTE_IP = "remote_ip"; - public static final String OPTION_VALUE_FLOW = "flow"; - - private final DataBroker dataBroker; - private final IInterfaceManager interfaceMgr; - private final OdlInterfaceRpcService interfaceManagerRpcService; - - @Inject - public GeniusProvider(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry, - final IInterfaceManager interfaceMgr) { - this.dataBroker = dataBroker; - this.interfaceMgr = interfaceMgr; - this.interfaceManagerRpcService = rpcProviderRegistry.getRpcService(OdlInterfaceRpcService.class); - } - - // Package local constructor used by UT for simplification - GeniusProvider(final DataBroker dataBroker, final OdlInterfaceRpcService interfaceManagerRpcService, - final IInterfaceManager interfaceMgr) { - this.dataBroker = dataBroker; - this.interfaceMgr = interfaceMgr; - this.interfaceManagerRpcService = interfaceManagerRpcService; - } - - public void bindPortOnIngressClassifier(String interfaceName) { - bindService( - getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, interfaceName, true), - NwConstants.SFC_CLASSIFIER_INDEX, - NwConstants.SFC_CLASSIFIER_SERVICE_NAME, - NwConstants.SFC_SERVICE_INDEX, - NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE, - OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE); - } - - public void bindPortOnEgressClassifier(String interfaceName, String destinationIp) { - bindService( - getBindServiceId(NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, interfaceName, false), - NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, - NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_NAME, - NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, - NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE, - OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_COOKIE, - Collections.singletonList( - createServiceBindingActionNxLoadReg0( - InetAddresses.coerceToInteger( - InetAddresses.forString(destinationIp)) & 0xffffffffL, - 0) - )); - } - - public void unbindPortOnIngressClassifier(String interfaceName) { - unbindService(getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, interfaceName, true)); - } - - public void unbindPortOnEgressClassifier(String interfaceName) { - unbindService(getBindServiceId(NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, interfaceName, false)); - } - - public Optional getNodeIdFromLogicalInterface(String logicalInterface) { - Optional dpnId = getDpnIdFromInterfaceName(logicalInterface); - - if (!dpnId.isPresent()) { - LOG.warn("getNodeIdFromLogicalInterface empty dpnId for logicalInterface [{}]", logicalInterface); - return Optional.empty(); - } - - return getNodeIdFromDpnId(dpnId.get()); - } - - public Optional getNodeIdFromDpnId(DpnIdType dpnId) { - if (dpnId == null) { - return Optional.empty(); - } - - if (dpnId.getValue() == null) { - return Optional.empty(); - } - - return Optional.of(new NodeId("openflow:" + dpnId.getValue())); - } - - // TODO Should better use the Genius InterfaceManager to avoid duplicate code - // https://bugs.opendaylight.org/show_bug.cgi?id=8127 - public Optional getIpFromDpnId(DpnIdType dpnid) { - GetEndpointIpForDpnInputBuilder builder = new GetEndpointIpForDpnInputBuilder(); - builder.setDpid(dpnid.getValue()); - GetEndpointIpForDpnInput input = builder.build(); - - if (interfaceManagerRpcService == null) { - LOG.error("getIpFromDpnId({}) failed (service couldn't be retrieved)", input); - return Optional.empty(); - } - - try { - LOG.debug("getIpFromDpnId: invoking rpc"); - RpcResult output = interfaceManagerRpcService.getEndpointIpForDpn(input).get(); - if (!output.isSuccessful()) { - LOG.error("getIpFromDpnId({}) failed: {}", input, output); - return Optional.empty(); - } - LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output); - List localIps = output.getResult().getLocalIps(); - - // TODO need to figure out why it returns a list, using first entry for now - return Optional.ofNullable(localIps) - .filter(ipAddresses -> !ipAddresses.isEmpty()) - .map(ipAddresses -> ipAddresses.get(0)) - .map(IpAddress::getIpv4Address) - .map(Ipv4Address::getValue); - } catch (InterruptedException | ExecutionException e) { - LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e); - } - - return Optional.empty(); - } - - public Optional getDpnIdFromInterfaceName(String interfaceName) { - LOG.debug("getDpnIdFromInterfaceName: starting (logical interface={})", interfaceName); - GetDpidFromInterfaceInputBuilder builder = new GetDpidFromInterfaceInputBuilder(); - builder.setIntfName(interfaceName); - GetDpidFromInterfaceInput input = builder.build(); - - if (interfaceManagerRpcService == null) { - LOG.error("getDpnIdFromInterfaceName({}) failed (service couldn't be retrieved)", input); - return Optional.empty(); - } - - try { - LOG.debug("getDpnIdFromInterfaceName: invoking rpc"); - RpcResult output = interfaceManagerRpcService.getDpidFromInterface(input).get(); - if (!output.isSuccessful()) { - LOG.error("getDpnIdFromInterfaceName({}) failed: {}", input, output); - return Optional.empty(); - } - - BigInteger dpnId = output.getResult().getDpid() != null ? output.getResult().getDpid().toJava() : null; - if (dpnId == null) { - return Optional.empty(); - } - LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output); - - return Optional.of(new DpnIdType(dpnId)); - } catch (InterruptedException | ExecutionException e) { - LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e); - } - - return Optional.empty(); - } - - public Optional getNodeConnectorIdFromInterfaceName(String interfaceName) { - LOG.debug("getDpnIdFromInterfaceName: starting (logical interface={})", interfaceName); - GetNodeconnectorIdFromInterfaceInputBuilder builder = new GetNodeconnectorIdFromInterfaceInputBuilder(); - builder.setIntfName(interfaceName); - GetNodeconnectorIdFromInterfaceInput input = builder.build(); - - if (interfaceManagerRpcService == null) { - LOG.error("getNodeConnectorIdFromInterfaceName({}) failed (service couldn't be retrieved)", input); - return Optional.empty(); - } - - try { - LOG.debug("getNodeConnectorIdFromInterfaceName: invoking rpc"); - RpcResult output = - interfaceManagerRpcService.getNodeconnectorIdFromInterface(input).get(); - if (!output.isSuccessful()) { - LOG.error("getNodeConnectorIdFromInterfaceName({}) failed: {}", input, output); - return Optional.empty(); - } - NodeConnectorId nodeConnId = output.getResult().getNodeconnectorId(); - if (nodeConnId == null) { - return Optional.empty(); - } - LOG.debug("getNodeConnectorIdFromInterfaceName({}) succeeded: {}", input, output); - - return Optional.ofNullable(nodeConnId.getValue()); - } catch (InterruptedException | ExecutionException e) { - LOG.error("getNodeConnectorIdFromInterfaceName failed to retrieve target interface name: ", e); - } - - return Optional.empty(); - } - - public Optional getEgressVxlanPortForNode(BigInteger dpnId) { - List tpList = interfaceMgr.getTunnelPortsOnBridge(Uint64.valueOf(dpnId)); - if (tpList == null) { - // Most likely the bridge doesnt exist for this dpnId - LOG.warn("getEgressVxlanPortForNode Tunnel Port TerminationPoint list not available for dpnId [{}]", - dpnId); - return Optional.empty(); - } - - for (OvsdbTerminationPointAugmentation tp : tpList) { - if (tp == null) { - // Technically we should never have a list with NULL entries, but - // in a preliminary version of interfaceMgr.getTunnelPortsOnBridge() - // we were getting a list where all termination point entries were - // null. Leaving this check for now for protection. - LOG.error("getEgressVxlanPortForNode received a NULL termination point from tpList on dpnId [{}]", - dpnId); - continue; - } - - Class ifType = tp.getInterfaceType(); - if (InterfaceTypeVxlan.class.equals(ifType)) { - for (Options tpOption : tp.nonnullOptions()) { - // From the VXLAN Tunnels, we want the one with the GPE option set - if (OPTION_KEY_REMOTE_IP.equals(tpOption.key().getOption())) { - if (OPTION_VALUE_FLOW.equals(tpOption.getValue()) && tp.getOfport() != null) { - return Optional.ofNullable(tp.getOfport().toJava()); - } - } - } - } - } - - LOG.warn("getEgressVxlanPortForNode no Vxgpe tunnel ports available for dpnId [{}]", dpnId); - - return Optional.empty(); - } - - public List getInterfacesFromNode(NodeId nodeId) { - // getPortsOnBridge() only returns Tunnel ports, so instead using getDpnInterfaceList. - GetDpnInterfaceListInputBuilder inputBuilder = new GetDpnInterfaceListInputBuilder(); - inputBuilder.setDpid(BigInteger.valueOf(Long.parseLong(nodeId.getValue().split(":")[1]))); - GetDpnInterfaceListInput input = inputBuilder.build(); - - try { - LOG.debug("getInterfacesFromNode: invoking rpc"); - RpcResult output = - interfaceManagerRpcService.getDpnInterfaceList(input).get(); - if (!output.isSuccessful()) { - LOG.error("getInterfacesFromNode({}) failed: {}", input, output); - return Collections.emptyList(); - } - LOG.debug("getInterfacesFromNode({}) succeeded: {}", input, output); - return output.getResult().getInterfaces(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("getInterfacesFromNode failed to retrieve target interface name: ", e); - } - - return Collections.emptyList(); - } - - public InstanceIdentifier getBindServiceId(short serviceId, String interfaceName, - boolean isIngress) { - ServicesInfoKey servicesInfoKey = isIngress - ? new ServicesInfoKey(interfaceName, ServiceModeIngress.class) : - new ServicesInfoKey(interfaceName, ServiceModeEgress.class); - InstanceIdentifier id = InstanceIdentifier.builder(ServiceBindings.class) - .child(ServicesInfo.class, servicesInfoKey) - .child(BoundServices.class, new BoundServicesKey(serviceId)).build(); - - return id; - } - - private void bindService(InstanceIdentifier id, short serviceId, String serviceName, - int servicePriority, short serviceDestTable, BigInteger serviceTableCookie) { - bindService( - id, - serviceId, - serviceName, - servicePriority, - serviceDestTable, - serviceTableCookie, - Collections.emptyList()); - } - - private void bindService(InstanceIdentifier id, short serviceId, String serviceName, - int servicePriority, short serviceDestTable, BigInteger serviceTableCookie, List extraActions) { - InstructionsBuilder isb = extraActions.isEmpty() - ? new InstructionsBuilder() - : OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(extraActions); - isb = OpenFlow13Utils.appendGotoTableInstruction(isb, serviceDestTable); - StypeOpenflow stypeOpenflow = new StypeOpenflowBuilder() - .setFlowCookie(serviceTableCookie) - .setFlowPriority(servicePriority) - .setInstruction(isb.build().getInstruction()) - .build(); - BoundServices boundServices = new BoundServicesBuilder().setServiceName(serviceName) - .setServicePriority(serviceId).setServiceType(ServiceTypeFlowBased.class) - .addAugmentation(StypeOpenflow.class, stypeOpenflow).build(); - LOG.info("Binding Service ID [{}] name [{}] priority [{}] table [{}] cookie [{}] extraActions [{}]", - serviceId, serviceName, servicePriority, serviceDestTable, serviceTableCookie, extraActions); - - MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION, id, boundServices); - } - - private void unbindService(InstanceIdentifier id) { - MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION, id); - } - - public Optional getRemoteIpAddress(String interfaceName) { - return Optional.ofNullable(interfaceMgr.getInterfaceInfoFromConfigDataStore(interfaceName)) - .map(anInterface -> anInterface.augmentation(IfTunnel.class)) - .map(IfTunnel::getTunnelDestination) - .map(IpAddress::getIpv4Address) - .map(Ipv4Address::getValue); - } - - public static Action createServiceBindingActionNxLoadReg0(long value, int order) { - return OpenFlow13Utils.createAction( - new ServiceBindingNxActionRegLoadApplyActionsCaseBuilder() - .setNxRegLoad(OpenFlow13Utils.createNxLoadReg0(value)) - .build(), - order); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProvider.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProvider.java deleted file mode 100644 index bc8170def6..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProvider.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NeutronNetwork; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class NetvirtProvider { - - private static final Logger LOG = LoggerFactory.getLogger(NetvirtProvider.class); - private final DataBroker dataBroker; - - @Inject - public NetvirtProvider(final DataBroker dataBroker) { - this.dataBroker = dataBroker; - } - - public List getLogicalInterfacesFromNeutronNetwork(NeutronNetwork nw) { - InstanceIdentifier networkMapIdentifier = - getNetworkMapIdentifier(new Uuid(nw.getNetworkUuid())); - - NetworkMap networkMap = - MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier).orNull(); - if (networkMap == null) { - LOG.warn("getLogicalInterfacesFromNeutronNetwork cant get NetworkMap for NW UUID [{}]", - nw.getNetworkUuid()); - return Collections.emptyList(); - } - - List interfaces = new ArrayList<>(); - List subnetUuidList = networkMap.getSubnetIdList(); - if (subnetUuidList != null) { - for (Uuid subnetUuid : subnetUuidList) { - InstanceIdentifier subnetId = getSubnetMapIdentifier(subnetUuid); - Subnetmap subnet = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetId).orNull(); - if (subnet == null) { - LOG.warn( - "getLogicalInterfacesFromNeutronNetwork cant get Subnetmap for NW UUID [{}] Subnet UUID " - + "[{}]", - nw.getNetworkUuid(), subnetUuid.getValue()); - continue; - } - - if (subnet.getPortList() == null || subnet.getPortList().isEmpty()) { - LOG.warn("getLogicalInterfacesFromNeutronNetwork No ports on Subnet: NW UUID [{}] Subnet UUID [{}]", - nw.getNetworkUuid(), subnetUuid.getValue()); - continue; - } - - subnet.getPortList().forEach(portId -> interfaces.add(portId.getValue())); - } - } - - return interfaces; - } - - // - // Internal Util methods - // - - private InstanceIdentifier getNetworkMapIdentifier(Uuid nwUuid) { - return InstanceIdentifier.builder(NetworkMaps.class) - .child(NetworkMap.class,new NetworkMapKey(nwUuid)).build(); - } - - private InstanceIdentifier getSubnetMapIdentifier(Uuid subnetUuid) { - return InstanceIdentifier.builder(Subnetmaps.class) - .child(Subnetmap.class, new SubnetmapKey(subnetUuid)).build(); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13Provider.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13Provider.java deleted file mode 100644 index 088e4d40f9..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13Provider.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import com.google.common.net.InetAddresses; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import javax.inject.Singleton; -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.genius.infra.Datastore.Configuration; -import org.opendaylight.genius.infra.TypedWriteTransaction; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.netvirt.sfc.classifier.utils.AclMatches; -import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -@Singleton -public class OpenFlow13Provider { - // Unique cookie values for each type of flow - public static final BigInteger INGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000001", 16); - public static final BigInteger INGRESS_CLASSIFIER_ACL_COOKIE = new BigInteger("F005BA1100000002", 16); - public static final BigInteger EGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000003", 16); - public static final BigInteger EGRESS_CLASSIFIER_NEXTHOP_COOKIE = new BigInteger("F005BA1100000004", 16); - public static final BigInteger EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE = new BigInteger("F005BA1100000005", 16); - public static final BigInteger INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE = - new BigInteger("F005BA1100000006", 16); - - // Priorities for each flow - public static final int INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY = 10; - public static final int INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY = 520; - public static final int INGRESS_CLASSIFIER_FILTER_NSH_TUN_PRIORITY = 510; - public static final int INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 511; - public static final int INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 500; - public static final int INGRESS_CLASSIFIER_ACL_MATCH_PRIORITY = 500; - public static final int INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY = 10; - public static final int EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 260; - public static final int EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 250; - public static final int EGRESS_CLASSIFIER_NEXTHOP_PRIORITY = 250; - public static final int EGRESS_CLASSIFIER_EGRESS_PRIORITY = 250; - - // Flow names for each table - public static final String INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME = - "nvsfc_ingr_class_capture_sfc_tunnel_eth_nsh"; - public static final String INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME = - "nvsfc_ingr_class_capture_sfc_tunnel_nsh"; - public static final String INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME = - "nvsfc_ingr_class_filter_chain_egress"; - public static final String INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME = "nvsfc_ingr_class_filter_nsh_tun"; - public static final String INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME = "nvsfc_ingr_class_filter_nsh"; - public static final String INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME = "nvsfc_ingr_class_filter_eth_nsh"; - public static final String INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_ingr_class_filter_nonsh"; - public static final String INGRESS_CLASSIFIER_ACL_FLOW_NAME = "nvsfc_ingr_class_acl"; - public static final String EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME = "nvsfc_egr_class_filter_nsh"; - public static final String EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_egr_class_filter_nonsh"; - public static final String EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME = "nvsfc_egr_class_nexthop_noc1c2"; - public static final String EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME = "nvsfc_egr_class_ tport egress"; - - public static final long SFC_TUNNEL_ID = 0L; - public static final String OF_URI_SEPARATOR = ":"; - public static final Ipv4Address NULL_IP = new Ipv4Address("0.0.0.0"); - - @Nullable - public List getMatchBuilderFromAceMatches(Matches matches) { - if (matches == null) { - return null; - } - - return new AclMatches(matches).buildMatch(); - } - - public void appendFlowForCreate(NodeId node, Flow flow, TypedWriteTransaction tx) { - NodeKey nodeKey = new NodeKey(node); - InstanceIdentifier iidFlow = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, nodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(flow.getTableId())) - .child(Flow.class, flow.key()) - .build(); - - tx.put(iidFlow, flow, WriteTransaction.CREATE_MISSING_PARENTS); - } - - public void appendFlowForDelete(NodeId node, Flow flow, TypedWriteTransaction tx) { - NodeKey nodeKey = new NodeKey(node); - InstanceIdentifier iidFlow = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, nodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(flow.getTableId())) - .child(Flow.class, flow.key()) - .build(); - - tx.delete(iidFlow); - } - - /* - * Ingress Classifier SFC Tunnel Traffic Capture Flow - * Captures eth+nsh traffic coming from tunnel port, normalizes - * the packet type to nsh by removing the outer ethernet header - * and redirects it to the ingress classifier pipeline. - */ - public Flow createIngressClassifierTunnelEthNshTrafficCaptureFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - OpenFlow13Utils.addMatchTunId(match, SFC_TUNNEL_ID); - OpenFlow13Utils.addMatchEthNsh(match); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionNxDecap(actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - String flowIdStr = INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME + nodeId.getValue(); - - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INTERNAL_TUNNEL_TABLE, - INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY, - INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE, - INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier SFC Tunnel Traffic Capture Flow - * Captures nsh traffic coming from tunnel port, - * and redirects it to the ingress classifier pipeline. - */ - public Flow createIngressClassifierTunnelNshTrafficCaptureFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - OpenFlow13Utils.addMatchTunId(match, SFC_TUNNEL_ID); - OpenFlow13Utils.addMatchPacketTypeNsh(match); - - InstructionsBuilder isb = new InstructionsBuilder(); - OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - String flowIdStr = INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME + nodeId.getValue(); - - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INTERNAL_TUNNEL_TABLE, - INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY, - INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE, - INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier Filter tunnel packet type NSH flow: - * Prevents nsh packets coming from a tunnel port to proceed. - * This is the least priority filter flow so it wont match - * packets coming from other than tunnel ports. - * Since no service port binding and thus no dispatching is - * available on tunnel port, resubmit direct to SFC pipeline. - */ - public Flow createIngressClassifierFilterTunnelNshFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - OpenFlow13Utils.addMatchPacketTypeNsh(match); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE, - INGRESS_CLASSIFIER_FILTER_NSH_TUN_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE, - INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier Filter Eth NSH flow: - * Prevents eth+nsh packets coming from other than a tunnel port - * to proceed. Verify that packet are not coming from tunnel - * by verifying there is no tunnel ip set with high priority - * flow. Resubmit to ingress dispatcher so that other nsh - * service handles the packet. - */ - public Flow createIngressClassifierFilterEthNshFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - OpenFlow13Utils.addMatchEthNsh(match); - OpenFlow13Utils.addMatchTunDstIp(match, NULL_IP); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE, - INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE, - INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier Filter packet type NSH floww: - * Prevents nsh packets coming from other than a tunnel port - * to proceed. Verify that packet are not coming from tunnel - * by checking there is no tunnel ip set with high priority - * flow. Resubmit to ingress dispatcher so that other nsh - * service handles the packet. - */ - public Flow createIngressClassifierFilterNshFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - OpenFlow13Utils.addMatchPacketTypeNsh(match); - OpenFlow13Utils.addMatchTunDstIp(match, NULL_IP); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE, - INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE, - INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Classifier chain termination flow: - * Handle packets at the end of the chain for which the final - * destination might be the classifier node. - * Match nsh packets on classified paths at their final index. - * Restores the lport tag on reg6, removes the nsh header and - * resubmits to egress dispatcher. - */ - public Flow createIngressClassifierFilterChainEgressFlow(NodeId nodeId, long nsp, short egressNsi) { - - MatchBuilder match = new MatchBuilder(); - OpenFlow13Utils.addMatchPacketTypeNsh(match); - OpenFlow13Utils.addMatchNsp(match, nsp); - OpenFlow13Utils.addMatchNsi(match, egressNsi); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionNxMoveNsc4ToReg6Register(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxDecap(actionList.size())); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp; - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE, - INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE, - INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier Filter No NSH flow: - * Non nsh packets, those that have not been matched by other - * higher priority nsh matching flows, proceed to the ACL - * table. - */ - public Flow createIngressClassifierFilterNoNshFlow(NodeId nodeId) { - // MatchAny - MatchBuilder match = new MatchBuilder(); - - InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(), - NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE); - String flowIdStr = INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE, - INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE, - INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier ACL flow: - * Performs the ACL classification, and sends packets to back - * to ingress dispatcher. - * Add the in_port (corresponds to Neutron NW/tenant) to the ACL match, - * and sets the nsp and nsi on the registry for later usage. - */ - public Flow createIngressClassifierAclFlow(NodeId nodeId, MatchBuilder match, Long port, long nsp, short nsi) { - OpenFlow13Utils.addMatchInPort(match, nodeId, port); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionNxLoadNspToReg2High(nsp, actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxLoadNsiToReg2Low(nsi, actionList.size())); - - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - - // The flowIdStr needs to be unique, so the best way to make it unique is to use the match - String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue() + match.build().toString(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE, - INGRESS_CLASSIFIER_ACL_MATCH_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE, INGRESS_CLASSIFIER_ACL_FLOW_NAME, - flowIdStr, match, isb).build(); - } - - /* - * Ingress Classifier ACL NoMatch flow: - * If there are no ACL classification matches, then resubmit back to - * the Ingress Dispatcher to let other services handle the packet. - */ - public Flow createIngressClassifierAclNoMatchFlow(NodeId nodeId) { - // This is a MatchAny flow - MatchBuilder match = new MatchBuilder(); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - - String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE, - INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE, - INGRESS_CLASSIFIER_ACL_FLOW_NAME, flowIdStr, match, isb).build(); - } - - // - // Internal EgressFlow util methods - // - - /* - * Egress Classifier Filter NoNsh flow: - * Filters out packets that have not been classified in the - * ingress classifier, those for which registry has not - * been set with nsp and nsi. Resubmit to egress dispatcher. - */ - public Flow createEgressClassifierFilterNoNshFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - - OpenFlow13Utils.addMatchReg2(match, 0); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE, - EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE, - EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Egress Classifier Filter Nsh flow. - * Packets proceed to NextHop table. - */ - public Flow createEgressClassifierFilterNshFlow(NodeId nodeId) { - MatchBuilder match = new MatchBuilder(); - - InstructionsBuilder isb = new InstructionsBuilder(); - isb = OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE); - String flowIdStr = EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE, - EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE, - EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Egress Classifier NextHop flow: - * Encapsulates the packet and sets the NSH header values. - * Packets proceed to TransportEgress table. - */ - public Flow createEgressClassifierNextHopFlow(NodeId nodeId) { - final MatchBuilder match = new MatchBuilder(); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionNxEncapNsh(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxMoveReg2HighToNsp(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxMoveReg2LowToNsi(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxLoadReg2(0, actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxMoveReg0ToNsc1Register(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxMoveTunIdToNsc2Register(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxMoveReg6ToNsc4Register(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxLoadTunId(SFC_TUNNEL_ID, actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE); - String flowIdStr = EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME + nodeId.getValue(); - - return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE, - EGRESS_CLASSIFIER_NEXTHOP_PRIORITY, EGRESS_CLASSIFIER_NEXTHOP_COOKIE, - EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Egress Classifier TransportEgress Local Flow - * First SFF is located on same node. NSH packets are - * sent to the SFC pipeline. - */ - public Flow createEgressClassifierTransportEgressLocalFlow(NodeId nodeId, long nsp) { - MatchBuilder match = new MatchBuilder(); - - OpenFlow13Utils.addMatchPacketTypeNsh(match); - OpenFlow13Utils.addMatchNsp(match, nsp); - - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE, - actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp; - - return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE, - EGRESS_CLASSIFIER_EGRESS_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE, - EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Egress Classifier TransportEgress Remote Flow - * Sends packet to a remote SFF ip though a tunnel port. - * Packets are not encapsulated with an extra ethernet header. - */ - public Flow createEgressClassifierTransportEgressRemoteNshFlow(NodeId nodeId, long nsp, long outport, - String firstHopIp) { - MatchBuilder match = new MatchBuilder(); - - OpenFlow13Utils.addMatchPacketTypeNsh(match); - OpenFlow13Utils.addMatchNsp(match, nsp); - - Long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(firstHopIp)) & 0xffffffffL; - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionNxLoadTunIpv4Dst(ipl, actionList.size())); - actionList.add(OpenFlow13Utils.createActionOutPort("output:" + outport, actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp; - - return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE, - EGRESS_CLASSIFIER_EGRESS_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE, - EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build(); - } - - /* - * Egress Classifier TransportEgress Remote Flow - * Sends packet to a remote SFF ip though a tunnel port. - * Packets are encapsulated with an extra ethernet header. - */ - public Flow createEgressClassifierTransportEgressRemoteEthNshFlow(NodeId nodeId, long nsp, long outport, - String firstHopIp) { - MatchBuilder match = new MatchBuilder(); - - OpenFlow13Utils.addMatchPacketTypeNsh(match); - OpenFlow13Utils.addMatchNsp(match, nsp); - - Long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(firstHopIp)) & 0xffffffffL; - List actionList = new ArrayList<>(); - actionList.add(OpenFlow13Utils.createActionNxEncapEthernet(actionList.size())); - actionList.add(OpenFlow13Utils.createActionNxLoadTunIpv4Dst(ipl, actionList.size())); - actionList.add(OpenFlow13Utils.createActionOutPort("output:" + outport, actionList.size())); - - InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList); - String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp; - - return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE, - EGRESS_CLASSIFIER_EGRESS_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE, - EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build(); - } - - - - public static Long getPortNoFromNodeConnector(String connector) { - /* - * NodeConnectorId is of the form 'openflow:dpnid:portnum' - */ - return Long.valueOf(connector.split(OF_URI_SEPARATOR)[2]); - } - - public static BigInteger getDpnIdFromNodeId(NodeId nodeId) { - /* - * NodeId is of the form 'openflow:dpnid' - */ - return BigInteger.valueOf(Long.parseLong(nodeId.getValue().split(OF_URI_SEPARATOR)[1])); - } - -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProvider.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProvider.java deleted file mode 100644 index c91892c098..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProvider.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffDataPlaneLocatorName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfpName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarderBase; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarders; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.ServiceFunctionDictionary; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsState; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.state.ServiceFunctionPathState; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.state.ServiceFunctionPathStateKey; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.LogicalInterfaceLocator; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.data.plane.locator.locator.type.LogicalInterface; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class SfcProvider { - - private static final Logger LOG = LoggerFactory.getLogger(SfcProvider.class); - private final DataBroker dataBroker; - - @Inject - public SfcProvider(final DataBroker dataBroker) { - this.dataBroker = dataBroker; - } - - public Optional getRenderedServicePath(String rspName) { - RenderedServicePathKey renderedServicePathKey = new RenderedServicePathKey(new RspName(rspName)); - InstanceIdentifier rspIid = InstanceIdentifier.builder(RenderedServicePaths.class) - .child(RenderedServicePath.class, renderedServicePathKey).build(); - - - return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, rspIid).toJavaUtil(); - } - - public Optional getRenderedServicePathFromSfc(String sfcName) { - Optional rsp = Optional.empty(); - - // TODO need to finish this - - return rsp; - } - - public Optional> readServicePathState(String sfpName) { - ServiceFunctionPathStateKey serviceFunctionPathStateKey = new ServiceFunctionPathStateKey(new SfpName(sfpName)); - InstanceIdentifier sfpIiD; - sfpIiD = InstanceIdentifier.builder(ServiceFunctionPathsState.class) - .child(ServiceFunctionPathState.class, serviceFunctionPathStateKey) - .build(); - return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, sfpIiD) - .toJavaUtil() - .map(ServiceFunctionPathState::getSfpRenderedServicePath) - .map(sfpRenderedServicePaths -> sfpRenderedServicePaths.stream() - .map(sfpRenderedServicePath -> sfpRenderedServicePath.getName().getValue()) - .collect(Collectors.toList())); - } - - public Optional getFirstHopIngressInterfaceFromRsp(RenderedServicePath rsp) { - // The ingres interface on the first hop is specified in the forward DPL - // in a forward path or the reverse DPL otherwise - boolean useForwardDpl = !rsp.isReversePath(); - return getRspFirstHop(rsp).flatMap(rspHop -> getHopSfInterface(rspHop, useForwardDpl)); - } - - public Optional getLastHopEgressInterfaceFromRsp(RenderedServicePath rsp) { - // The egress interface on the first hop is specified in the forward DPL - // in a forward path or the reverse DPL otherwise - boolean useForwardDpl = rsp.isReversePath(); - return getRspLastHop(rsp).flatMap(rspHop -> getHopSfInterface(rspHop, useForwardDpl)); - } - - private Optional getHopSfInterface(RenderedServicePathHop hop, boolean useForwardDpl) { - - LOG.trace("getHopSfInterface of hop {}", hop); - - SfName sfName = hop.getServiceFunctionName(); - if (sfName == null) { - LOG.warn("getHopSfInterface hop has no SF"); - return Optional.empty(); - } - - SffName sffName = hop.getServiceFunctionForwarder(); - if (sffName == null) { - LOG.warn("getHopSfInterface hop has no SFF"); - return Optional.empty(); - } - - Optional sff = getServiceFunctionForwarder(sffName); - if (!sff.isPresent()) { - LOG.warn("getHopSfInterface SFF [{}] does not exist", sffName.getValue()); - return Optional.empty(); - } - - // Find the SFF-SF data plane locator for the SF pair - SffSfDataPlaneLocator sffSfDataPlaneLocator = sff.map(ServiceFunctionForwarder::getServiceFunctionDictionary) - .orElse(Collections.emptyList()) - .stream() - .filter(serviceFunctionDictionary -> Objects.equals(serviceFunctionDictionary.getName(), sfName)) - .findAny() - .map(ServiceFunctionDictionary::getSffSfDataPlaneLocator) - .orElse(null); - - if (sffSfDataPlaneLocator == null) { - LOG.warn("getHopSfInterface SFF [{}] has not dictionary for SF [{}]", - sffName.getValue(), - sffName.getValue()); - return Optional.empty(); - } - - // Get the forward or reverse locator name as appropriate if any, - // otherwise default to non directional locator - SffDataPlaneLocatorName sffDataPlaneLocatorName = null; - if (useForwardDpl) { - sffDataPlaneLocatorName = sffSfDataPlaneLocator.getSffForwardDplName(); - } else { - sffDataPlaneLocatorName = sffSfDataPlaneLocator.getSffReverseDplName(); - } - if (sffDataPlaneLocatorName == null) { - sffDataPlaneLocatorName = sffSfDataPlaneLocator.getSffDplName(); - } - - // Get the interface name value of the locator with such name - SffDataPlaneLocatorName locatorName = sffDataPlaneLocatorName; - Optional interfaceName = sff.map(ServiceFunctionForwarderBase::getSffDataPlaneLocator) - .orElse(Collections.emptyList()) - .stream() - .filter(sffDataPlaneLocator -> Objects.equals(sffDataPlaneLocator.getName(), locatorName)) - .findAny() - .map(SffDataPlaneLocator::getDataPlaneLocator) - .filter(dataPlaneLocator -> dataPlaneLocator.getLocatorType() instanceof LogicalInterface) - .map(dataPlaneLocator -> (LogicalInterfaceLocator) dataPlaneLocator.getLocatorType()) - .map(LogicalInterfaceLocator::getInterfaceName); - - return interfaceName; - } - - private Optional getServiceFunctionForwarder(SffName name) { - ServiceFunctionForwarderKey serviceFunctionForwarderKey = new ServiceFunctionForwarderKey(name); - InstanceIdentifier sffIid; - sffIid = InstanceIdentifier.builder(ServiceFunctionForwarders.class) - .child(ServiceFunctionForwarder.class, serviceFunctionForwarderKey) - .build(); - - return MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, sffIid).toJavaUtil(); - } - - private Optional getRspFirstHop(RenderedServicePath rsp) { - List hops = rsp.getRenderedServicePathHop(); - if (hops == null || hops.isEmpty()) { - LOG.warn("getRspFirstHop RSP [{}] has no hops list", rsp.getName().getValue()); - return Optional.empty(); - } - - return Optional.ofNullable(hops.get(0)); - } - - private Optional getRspLastHop(RenderedServicePath rsp) { - List hops = rsp.getRenderedServicePathHop(); - if (hops == null || hops.isEmpty()) { - LOG.warn("getRspLastHop RSP [{}] has no hops list", rsp.getName().getValue()); - return Optional.empty(); - } - - return Optional.ofNullable(hops.get(hops.size() - 1)); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/ClassifierService.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/ClassifierService.java deleted file mode 100644 index a1c572e084..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/ClassifierService.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.infrautils.utils.concurrent.Executors; -import org.opendaylight.netvirt.sfc.classifier.providers.GeniusProvider; -import org.opendaylight.netvirt.sfc.classifier.providers.NetvirtProvider; -import org.opendaylight.netvirt.sfc.classifier.providers.OpenFlow13Provider; -import org.opendaylight.netvirt.sfc.classifier.providers.SfcProvider; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierState; -import org.opendaylight.netvirt.sfc.classifier.service.domain.impl.ClassifierUpdate; -import org.opendaylight.netvirt.sfc.classifier.service.domain.impl.ConfigurationClassifierImpl; -import org.opendaylight.netvirt.sfc.classifier.service.domain.impl.GeniusRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.impl.OpenflowRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.impl.OperationalClassifierImpl; -import org.opendaylight.netvirt.sfc.classifier.utils.LastTaskExecutor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class ClassifierService { - - private final NetvirtProvider netvirtProvider; - private final GeniusProvider geniusProvider; - private final SfcProvider sfcProvider; - private final DataBroker dataBroker; - private final Executor lastTaskExecutor; - private final OperationalClassifierImpl operationalClassifier = new OperationalClassifierImpl(); - private final List classifierRenderers = new ArrayList<>(); - private static final Logger LOG = LoggerFactory.getLogger(ClassifierService.class); - - @Inject - public ClassifierService(final NetvirtProvider netvirtProvider, final GeniusProvider geniusProvider, - final SfcProvider sfcProvider, final OpenFlow13Provider openFlow13Provider, - final DataBroker dataBroker) { - this.netvirtProvider = netvirtProvider; - this.geniusProvider = geniusProvider; - this.sfcProvider = sfcProvider; - this.dataBroker = dataBroker; - this.lastTaskExecutor = new LastTaskExecutor( - Executors.newSingleThreadExecutor(getClass().getSimpleName(), LOG)); - classifierRenderers.add(new OpenflowRenderer(openFlow13Provider, geniusProvider, dataBroker)); - classifierRenderers.add(new GeniusRenderer(geniusProvider)); - classifierRenderers.add(operationalClassifier.getRenderer()); - } - - public void updateAll() { - lastTaskExecutor.execute(this::doUpdateAll); - } - - private void doUpdateAll() { - - ClassifierState configurationClassifier = new ConfigurationClassifierImpl( - geniusProvider, - netvirtProvider, - sfcProvider, - dataBroker); - - ClassifierUpdate classifierUpdate = new ClassifierUpdate( - configurationClassifier, - operationalClassifier, - classifierRenderers); - - classifierUpdate.run(); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntry.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntry.java deleted file mode 100644 index ef21749f19..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntry.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain; - -import com.google.common.base.MoreObjects; -import java.util.Objects; -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierRenderableEntry; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; - -/** - * A generic {@link ClassifierRenderableEntry} implementation that supports all - * the different render types. - */ -public final class ClassifierEntry implements ClassifierRenderableEntry { - - private enum EntryType { - NODE_ENTRY_TYPE, - INGRESS_INTERFACE_ENTRY_TYPE, - PATH_ENTRY_TYPE, - MATCH_ENTRY_TYPE, - EGRESS_INTERFACE_ENTRY_TYPE - } - - private final EntryType entryType; - // TODO skitt Rework using a class hierarchy so we can enforce null constraints - private final @Nullable NodeId node; - private final @Nullable InterfaceKey interfaceKey; - private final @Nullable String connector; - private final @Nullable Matches matches; - private final @Nullable Long nsp; - private final @Nullable Short nsi; - private final @Nullable Short nsl; - private final @Nullable String destinationIp; - private final @Nullable String firstHopIp; - - private ClassifierEntry(EntryType entryType, @Nullable NodeId node, @Nullable InterfaceKey interfaceKey, - @Nullable String connector, @Nullable Matches matches, @Nullable Long nsp, - @Nullable Short nsi, @Nullable Short nsl, @Nullable String destinationIp, - @Nullable String firstHopIp) { - this.entryType = entryType; - this.node = node; - this.interfaceKey = interfaceKey; - this.connector = connector; - this.matches = matches; - this.nsp = nsp; - this.nsi = nsi; - this.nsl = nsl; - this.destinationIp = destinationIp; - this.firstHopIp = firstHopIp; - } - - @Override - public int hashCode() { - return Objects.hash( - entryType, - node, - interfaceKey, - connector, - matches, - nsp, - nsi, - nsl, - destinationIp, - firstHopIp); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!ClassifierEntry.class.equals(obj.getClass())) { - return false; - } - ClassifierEntry other = (ClassifierEntry) obj; - return Objects.equals(entryType, other.entryType) - && Objects.equals(node, other.node) - && Objects.equals(interfaceKey, other.interfaceKey) - && Objects.equals(connector, other.connector) - && Objects.equals(matches, other.matches) - && Objects.equals(nsp, other.nsp) - && Objects.equals(nsi, other.nsi) - && Objects.equals(destinationIp, other.destinationIp) - && Objects.equals(nsl, other.nsl) - && Objects.equals(firstHopIp, other.firstHopIp); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("entryType", entryType) - .add("node", node) - .add("interfaceKey", interfaceKey) - .add("connector", connector) - .add("matches", matches) - .add("nsp", nsp) - .add("nsi", nsi) - .add("nsl", nsl) - .add("destinationIp", destinationIp) - .add("firstHopIp", firstHopIp) - .toString(); - } - - @Override - public void render(ClassifierEntryRenderer classifierEntryRenderer) { - switch (entryType) { - case NODE_ENTRY_TYPE: - classifierEntryRenderer.renderNode(node); - break; - case INGRESS_INTERFACE_ENTRY_TYPE: - classifierEntryRenderer.renderIngress(interfaceKey); - break; - case PATH_ENTRY_TYPE: - classifierEntryRenderer.renderPath(node, nsp, nsi, nsl, firstHopIp); - break; - case MATCH_ENTRY_TYPE: - classifierEntryRenderer.renderMatch(node, connector, matches, nsp, nsi); - break; - case EGRESS_INTERFACE_ENTRY_TYPE: - classifierEntryRenderer.renderEgress(interfaceKey, destinationIp); - break; - default: - } - } - - @Override - public void suppress(ClassifierEntryRenderer classifierEntryRenderer) { - switch (entryType) { - case NODE_ENTRY_TYPE: - classifierEntryRenderer.suppressNode(node); - break; - case INGRESS_INTERFACE_ENTRY_TYPE: - classifierEntryRenderer.suppressIngress(interfaceKey); - break; - case PATH_ENTRY_TYPE: - classifierEntryRenderer.suppressPath(node, nsp, nsi, nsl, firstHopIp); - break; - case MATCH_ENTRY_TYPE: - classifierEntryRenderer.suppressMatch(node, connector, matches, nsp, nsi); - break; - case EGRESS_INTERFACE_ENTRY_TYPE: - classifierEntryRenderer.suppressEgress(interfaceKey, destinationIp); - break; - default: - } - } - - /** - * Build a {@code ClassifierEntry} supporting an ingress render type. - * - * @param interfaceKey the ingress interface. - * @return the {@code ClassifierEntry}. - */ - public static ClassifierEntry buildIngressEntry(InterfaceKey interfaceKey) { - return new ClassifierEntry( - EntryType.INGRESS_INTERFACE_ENTRY_TYPE, - null, - interfaceKey, - null, - null, - null, - null, - null, - null, - null); - } - - /** - * Build a {@code ClassifierEntry} supporting an node render type. - * - * @param node the classifier node identifier. - * @return the {@code ClassifierEntry}. - */ - public static ClassifierEntry buildNodeEntry(NodeId node) { - return new ClassifierEntry( - EntryType.NODE_ENTRY_TYPE, - node, - null, - null, - null, - null, - null, - null, - null, - null); - } - - /** - * Build a {@code ClassifierEntry} supporting a path render type. - * - * @param node the classifier node identifier. - * @param nsp the path identifier. - * @param nsi the path starting index. - * @param nsl the path length. - * @param firstHopIp the first SFF ip address. Null if the SFF is nodeId. - * @return the {@code ClassifierEntry}. - */ - public static ClassifierEntry buildPathEntry(NodeId node, Long nsp, short nsi, short nsl, - @Nullable String firstHopIp) { - return new ClassifierEntry( - EntryType.PATH_ENTRY_TYPE, - node, - null, - null, - null, - nsp, - nsi, - nsl, - null, - firstHopIp); - } - - /** - * Build a {@code ClassifierEntry} supporting an match render type. - * - * @param node the classifier node identifier. - * @param connector the node connector for the ingress interface. - * @param matches the ACL matches. - * @param nsp the path identifier. - * @param nsi the initial path index. - * @return the {@code ClassifierEntry}. - */ - public static ClassifierEntry buildMatchEntry(NodeId node, String connector, Matches matches, Long nsp, Short nsi) { - return new ClassifierEntry( - EntryType.MATCH_ENTRY_TYPE, - node, - null, - connector, - matches, - nsp, - nsi, - null, - null, - null); - } - - /** - * Build a {@code ClassifierEntry} supporting a remote egress render type. - * - * @param interfaceKey the egress interface key. - * @param destinationIp the destination IP address associated to the - * interface. If the interface is a local interface, - * this should be a node local IP address, otherwise - * the remote IP address. - * @return the {@code ClassifierEntry}. - */ - public static ClassifierEntry buildEgressEntry(InterfaceKey interfaceKey, String destinationIp) { - return new ClassifierEntry( - EntryType.EGRESS_INTERFACE_ENTRY_TYPE, - null, - interfaceKey, - null, - null, - null, - null, - null, - destinationIp, - null); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierEntryRenderer.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierEntryRenderer.java deleted file mode 100644 index c3121ebf1e..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierEntryRenderer.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.api; - -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; - -/** - * The interface of classifier entry renderers. - * - *

- * There are different independent render types: - * - Ingress (i.e. ingress bind to interface). - * - Node (i.e. node initialization). - * - Path (i.e. write path egress flows). - * - Match (i.e. write ACL flow). - * - Egress (i.e egress bind to interface). - * - *

- * A renderer may not implement all the render types and is responsible to know - * if the render applies to it or not (for example, an openflow renderer should - * not write to a non openflow node). - */ -public interface ClassifierEntryRenderer { - - /** - * Render ingress interface actions. - * - * @param interfaceKey the ingress interface key. - */ - void renderIngress(InterfaceKey interfaceKey); - - /** - * Render node wide actions. - * - * @param nodeId the classifier node identifier. - */ - void renderNode(NodeId nodeId); - - /** - * Render path based actions. - * - * @param nodeId the classifier node identifier. - * @param nsp the path identifier. - * @param nsi the path starting index. - * @param nsl the path length. - * @param firstHopIp the first SFF ip address. Null if the SFF is nodeId. - */ - void renderPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp); - - /** - * Rended match based actions. - * - * @param nodeId the classifier node identifier. - * @param connector the node connector for the ingress interface. - * @param matches the ACL matches. - * @param nsp the path identifier. - * @param nsi the initial path index. - */ - void renderMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi); - - /** - * Render egress interface actions. - * - * @param interfaceKey the egress interface key. - * @param destinationIp the destination IP address associated to the - * interface. If the interface is a local interface, - * this should be a node local IP address, otherwise - * the remote IP address. - */ - void renderEgress(InterfaceKey interfaceKey, String destinationIp); - - /** - * Suppress ingress interface actions. - * - * @param interfaceKey the ingress interface key. - */ - void suppressIngress(InterfaceKey interfaceKey); - - /** - * Suppress node wide actions. - * - * @param nodeId the classifier node identifier. - */ - void suppressNode(NodeId nodeId); - - /** - * Supress path based actions. - * - * @param nodeId the classifier node identifier. - * @param nsp the path identifier. - * @param nsi the path starting index. - * @param nsl the path length. - * @param firstHopIp the first SFF ip address. Null if the SFF is nodeId. - */ - void suppressPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp); - - /** - * Supress match based actions. - * - * @param nodeId the classifier node identifier. - * @param connector the node connector for the ingress interface. - * @param matches the ACL matches. - * @param nsp the path identifier. - * @param nsi the initial path index. - */ - void suppressMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi); - - /** - * Supress egress interface actions. - * - * @param interfaceKey the egress interface key. - * @param destinationIp the destination IP address associated to the - * interface. If the interface is a local interface, - * this should be a node local IP address, otherwise - * the remote IP address. - */ - void suppressEgress(InterfaceKey interfaceKey, String destinationIp); -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierRenderableEntry.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierRenderableEntry.java deleted file mode 100644 index 08c978db32..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierRenderableEntry.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.api; - -/** - * A {@code ClassifierRenderableEntry} represents a unit of classifier - * information that may be used to consistently perform ("render") - * actions to southbound APIs that can also be consistently reversed - * ("suppress"). - */ -public interface ClassifierRenderableEntry { - - /** - * Render the entry using the provided {@code ClassifierEntryRenderer}. - * - * @param classifierEntryRenderer the renderer. - */ - void render(ClassifierEntryRenderer classifierEntryRenderer); - - /** - * Suppress the entry using the provided {@code ClassifierEntryRenderer}. - * - * @param classifierEntryRenderer the renderer. - */ - void suppress(ClassifierEntryRenderer classifierEntryRenderer); -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierState.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierState.java deleted file mode 100644 index e890d6e716..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/api/ClassifierState.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.api; - -import java.util.Set; - -/** - * The classifier state defined by a collection of {@link - * ClassifierRenderableEntry}. - */ -public interface ClassifierState { - Set getAllEntries(); -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdate.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdate.java deleted file mode 100644 index 67c2497822..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdate.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.impl; - -import com.google.common.collect.Sets; -import java.util.List; -import java.util.Set; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierRenderableEntry; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierState; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ClassifierUpdate implements Runnable { - - private final ClassifierState configurationClassifier; - private final ClassifierState operationalClassifier; - private final List classifierRenderers; - private static final Logger LOG = LoggerFactory.getLogger(ClassifierUpdate.class); - - public ClassifierUpdate(ClassifierState configurationClassifier, ClassifierState operationalClassifier, - List classifierRenderers) { - this.configurationClassifier = configurationClassifier; - this.operationalClassifier = operationalClassifier; - this.classifierRenderers = classifierRenderers; - } - - @Override - public void run() { - Set configurationEntries = configurationClassifier.getAllEntries(); - Set operationalEntries = operationalClassifier.getAllEntries(); - Set entriesToAdd = - Sets.difference(configurationEntries, operationalEntries).immutableCopy(); - Set entriesToRemove = - Sets.difference(operationalEntries, configurationEntries).immutableCopy(); - - LOG.trace("Configuration entries: {}", configurationEntries); - LOG.trace("Operational entries: {}", operationalEntries); - LOG.trace("Entries to add: {}", entriesToAdd); - LOG.trace("Entries to remove: {}", entriesToRemove); - - classifierRenderers.forEach( - classifierRenderer -> { - entriesToRemove.forEach(classifierRenderableEntry -> - classifierRenderableEntry.suppress(classifierRenderer)); - entriesToAdd.forEach(classifierRenderableEntry -> - classifierRenderableEntry.render(classifierRenderer)); - }); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java deleted file mode 100644 index a28b506e39..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.impl; - -import com.google.common.base.Strings; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.netvirt.sfc.classifier.providers.GeniusProvider; -import org.opendaylight.netvirt.sfc.classifier.providers.NetvirtProvider; -import org.opendaylight.netvirt.sfc.classifier.providers.OpenFlow13Provider; -import org.opendaylight.netvirt.sfc.classifier.providers.SfcProvider; -import org.opendaylight.netvirt.sfc.classifier.service.domain.ClassifierEntry; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierRenderableEntry; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierState; -import org.opendaylight.netvirt.sfc.classifier.utils.AclMatches; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.get.dpn._interface.list.output.Interfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NetvirtsfcAclActions; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NeutronNetwork; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NeutronPorts; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.RedirectToSfc; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConfigurationClassifierImpl implements ClassifierState { - - private final SfcProvider sfcProvider; - private final DataBroker dataBroker; - private final GeniusProvider geniusProvider; - private final NetvirtProvider netvirtProvider; - private static final Logger LOG = LoggerFactory.getLogger(ConfigurationClassifierImpl.class); - private static final String LOCAL_HOST_IP = "127.0.0.1"; - - public ConfigurationClassifierImpl(GeniusProvider geniusProvider, - NetvirtProvider netvirtProvider, - SfcProvider sfcProvider, - DataBroker dataBroker) { - this.geniusProvider = geniusProvider; - this.netvirtProvider = netvirtProvider; - this.sfcProvider = sfcProvider; - this.dataBroker = dataBroker; - } - - @Override - public Set getAllEntries() { - return readAcls().stream() - .map(Acl::getAccessListEntries) - .filter(Objects::nonNull) - .map(AccessListEntries::getAce) - .filter(Objects::nonNull) - .flatMap(List::stream) - .map(this::getEntriesForAce) - .flatMap(Set::stream) - .collect(Collectors.toSet()); - } - - private List readAcls() { - InstanceIdentifier aclsIID = InstanceIdentifier.builder(AccessLists.class).build(); - Optional acls; - acls = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, aclsIID).toJavaUtil(); - LOG.trace("Acls read from datastore: {}", acls); - return acls.map(AccessLists::getAcl).orElse(Collections.emptyList()); - } - - private Set getEntriesForAce(Ace ace) { - String ruleName = ace.getRuleName(); - LOG.debug("Generating classifier entries for Ace: {}", ruleName); - LOG.trace("Ace details: {}", ace); - - Optional sfcActions = Optional.ofNullable(ace.getActions()) - .map(actions -> actions.augmentation(RedirectToSfc.class)); - String rspName = sfcActions.map(NetvirtsfcAclActions::getRspName).map(Strings::emptyToNull).orElse(null); - String sfpName = sfcActions.map(NetvirtsfcAclActions::getSfpName).map(Strings::emptyToNull).orElse(null); - - if (rspName == null && sfpName == null) { - LOG.debug("Ace {} ignored: no valid SFC redirect action", ruleName); - return Collections.emptySet(); - } - if (rspName != null && sfpName != null) { - LOG.warn("Ace {} ignored: both SFP and a RSP as redirect actions not supported", ruleName); - return Collections.emptySet(); - } - - Matches matches = ace.getMatches(); - if (matches == null) { - LOG.warn("Ace {} ignored: no matches", ruleName); - return Collections.emptySet(); - } - - NeutronNetwork network = matches.augmentation(NeutronNetwork.class); - if (sfpName != null && network != null) { - LOG.warn("Ace {} ignored: SFP redirect action with neutron network match not supported", ruleName); - return Collections.emptySet(); - } - - String sourcePort = Optional.ofNullable(matches.augmentation(NeutronPorts.class)) - .map(NeutronPorts::getSourcePortUuid) - .map(Strings::emptyToNull) - .orElse(null); - String destinationPort = Optional.ofNullable(matches.augmentation(NeutronPorts.class)) - .map(NeutronPorts::getDestinationPortUuid) - .map(Strings::emptyToNull) - .orElse(null); - - if (rspName != null) { - return getEntriesForRspRedirect(ruleName, sourcePort, destinationPort, network, rspName, matches); - } - - return getEntriesForSfpRedirect(ruleName, sourcePort, destinationPort, sfpName, matches); - } - - private Set getEntriesForRspRedirect( - String ruleName, - String sourcePort, - String destinationPort, - NeutronNetwork neutronNetwork, - String rspName, - Matches matches) { - - RenderedServicePath rsp = sfcProvider.getRenderedServicePath(rspName).orElse(null); - if (rsp == null) { - LOG.debug("Ace {} ignored: RSP {} not yet available", ruleName, rspName); - return Collections.emptySet(); - } - - if (destinationPort != null) { - LOG.warn("Ace {}: destination port is ignored combined with RSP redirect", ruleName); - } - - List interfaces = new ArrayList<>(); - if (neutronNetwork != null) { - interfaces.addAll(netvirtProvider.getLogicalInterfacesFromNeutronNetwork(neutronNetwork)); - } - if (sourcePort != null) { - interfaces.add(sourcePort); - } - - if (interfaces.isEmpty()) { - LOG.debug("Ace {} ignored: no interfaces to match against", ruleName); - return Collections.emptySet(); - } - - return this.buildEntries(ruleName, interfaces, matches, rsp); - } - - private Set getEntriesForSfpRedirect( - String ruleName, - String srcPort, - String dstPort, - String sfpName, - Matches matches) { - - if (srcPort == null && dstPort == null) { - LOG.warn("Ace {} ignored: no source or destination port to match against", ruleName); - return Collections.emptySet(); - } - - if (Objects.equals(srcPort, dstPort)) { - LOG.warn("Ace {} ignored: equal source and destination port not supported", ruleName); - return Collections.emptySet(); - } - - List rsps = sfcProvider.readServicePathState(sfpName) - .orElse(Collections.emptyList()) - .stream() - .map(sfcProvider::getRenderedServicePath) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); - - // The classifier might be configured at the same time as the SFP. - // The RSPs that are automatically added from that SFP might still - // be missing. It will be handled on a later listener event. - if (rsps.isEmpty()) { - LOG.debug("Ace {} ignored: no RSPs for SFP {} yet available", ruleName, sfpName); - return Collections.emptySet(); - } - - // An SFP will have two RSPs associated if symmetric, one otherwise. - if (rsps.size() > 2) { - LOG.warn("Ace {} ignored: more than two RSPs associated to SFP {} not supported", ruleName, sfpName); - return Collections.emptySet(); - } - - RenderedServicePath forwardRsp = rsps.stream() - .filter(rsp -> !rsp.isReversePath()) - .findAny() - .orElse(null); - RenderedServicePath reverseRsp = rsps.stream() - .filter(RenderedServicePath::isReversePath) - .filter(rsp -> forwardRsp != null && Objects.equals(rsp.getSymmetricPathId(), forwardRsp.getPathId())) - .findAny() - .orElse(null); - - if (srcPort != null && forwardRsp == null) { - LOG.debug("Ace {} ignored: no forward RSP yet available for SFP {} and source port {}", - ruleName, sfpName, srcPort); - return Collections.emptySet(); - } - - if (dstPort != null && reverseRsp == null) { - LOG.debug("Ace {} ignored: no reverse RSP yet available for SFP {} and destination port {}", - ruleName, sfpName, dstPort); - return Collections.emptySet(); - } - - Set entries = new HashSet<>(); - if (srcPort != null) { - entries.addAll(this.buildEntries(ruleName, Collections.singletonList(srcPort), matches, forwardRsp)); - } - if (dstPort != null) { - Matches invertedMatches = AclMatches.invertMatches(matches); - entries.addAll( - this.buildEntries(ruleName, Collections.singletonList(dstPort), invertedMatches, reverseRsp)); - } - - return entries; - } - - private Set buildEntries( - String ruleName, - @NonNull List interfaces, - @NonNull Matches matches, - @NonNull RenderedServicePath rsp) { - - String rspName = rsp.getName().getValue(); - Long nsp = rsp.getPathId().longValue(); - Short nsi = rsp.getStartingIndex().shortValue(); - Short nsl = rsp.getRenderedServicePathHop() == null ? null : (short) rsp.getRenderedServicePathHop().size(); - - if (nsp == null || nsi == null || nsl == null) { - LOG.warn("Ace {} RSP {} ignored: no valid NSI or NSP or length", ruleName, rspName); - return Collections.emptySet(); - } - - DpnIdType firstHopDpn = sfcProvider.getFirstHopIngressInterfaceFromRsp(rsp) - .flatMap(geniusProvider::getDpnIdFromInterfaceName) - .orElse(null); - - if (firstHopDpn == null) { - LOG.warn("Ace {} RSP {} ignored: no valid first hop DPN", ruleName, rspName); - return Collections.emptySet(); - } - - String lastHopInterface = sfcProvider.getLastHopEgressInterfaceFromRsp(rsp).orElse(null); - if (lastHopInterface == null) { - LOG.warn("Ace {} RSP {} ignored: has no valid last hop interface", ruleName, rspName); - return Collections.emptySet(); - } - - DpnIdType lastHopDpn = geniusProvider.getDpnIdFromInterfaceName(lastHopInterface).orElse(null); - if (lastHopDpn == null) { - LOG.warn("Ace {} RSP {} ignored: has no valid last hop DPN", ruleName, rspName); - return Collections.emptySet(); - } - - Map> nodeToInterfaces = new HashMap<>(); - for (String iface : interfaces) { - geniusProvider.getNodeIdFromLogicalInterface(iface).ifPresent(nodeId -> - nodeToInterfaces.computeIfAbsent(nodeId, key -> new ArrayList<>()).add(new InterfaceKey(iface))); - } - - LOG.trace("Ace {} RSP {}: got classifier nodes and interfaces: {}", ruleName, rspName, nodeToInterfaces); - - String firstHopIp = geniusProvider.getIpFromDpnId(firstHopDpn).orElse(null); - Set entries = new HashSet<>(); - nodeToInterfaces.forEach((nodeId, ifaces) -> { - // Get node info - DpnIdType nodeDpn = new DpnIdType(OpenFlow13Provider.getDpnIdFromNodeId(nodeId)); - - if (firstHopIp == null && !nodeDpn.equals(firstHopDpn)) { - LOG.warn("Ace {} RSP {} classifier {} ignored: no IP to reach first hop DPN {}", - ruleName, rspName, nodeId, firstHopDpn); - return; - } - - // Add entries that are not based on ingress or egress interface - entries.add(ClassifierEntry.buildNodeEntry(nodeId)); - entries.add(ClassifierEntry.buildPathEntry( - nodeId, - nsp, - nsi, - nsl, - nodeDpn.equals(firstHopDpn) ? null : firstHopIp)); - - // Add entries based on ingress interface - ifaces.forEach(interfaceKey -> { - entries.add(ClassifierEntry.buildIngressEntry(interfaceKey)); - entries.add(ClassifierEntry.buildMatchEntry( - nodeId, - geniusProvider.getNodeConnectorIdFromInterfaceName(interfaceKey.getName()).get(), - matches, - nsp, - nsi)); - }); - - // To handle chain egress when origin, last SF and destination are on the same node, - // we need to bind to the SF interface so that SFC pipeline to classifier pipeline - // hand-off can happen through the dispatcher table - if (nodeDpn.equals(lastHopDpn)) { - entries.add(ClassifierEntry.buildIngressEntry(new InterfaceKey(lastHopInterface))); - } - - // Egress services must bind to egress ports. Since we dont know before-hand what - // the egress ports will be, we will bind on all switch ports. If the packet - // doesnt have NSH, it will be returned to the the egress dispatcher table. - String nodeIp = geniusProvider.getIpFromDpnId(nodeDpn).orElse(LOCAL_HOST_IP); - List interfaceUuidStrList = geniusProvider.getInterfacesFromNode(nodeId); - interfaceUuidStrList.forEach(interfaceUuidStr -> { - InterfaceKey interfaceKey = new InterfaceKey(interfaceUuidStr.getInterfaceName()); - Optional remoteIp = geniusProvider.getRemoteIpAddress(interfaceUuidStr.getInterfaceName()); - entries.add(ClassifierEntry.buildEgressEntry(interfaceKey, remoteIp.orElse(nodeIp))); - }); - }); - - return entries; - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/GeniusRenderer.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/GeniusRenderer.java deleted file mode 100644 index eedaf6c698..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/GeniusRenderer.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.impl; - -import org.opendaylight.netvirt.sfc.classifier.providers.GeniusProvider; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; - -public class GeniusRenderer implements ClassifierEntryRenderer { - - private final GeniusProvider geniusProvider; - - public GeniusRenderer(GeniusProvider geniusProvider) { - this.geniusProvider = geniusProvider; - } - - @Override - public void renderIngress(InterfaceKey interfaceKey) { - geniusProvider.bindPortOnIngressClassifier(interfaceKey.getName()); - } - - @Override - public void renderNode(NodeId nodeId) { - // noop - } - - @Override - public void renderPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp) { - // noop - } - - @Override - public void renderMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi) { - // noop - } - - @Override - public void renderEgress(InterfaceKey interfaceKey, String destinationIp) { - geniusProvider.bindPortOnEgressClassifier(interfaceKey.getName(), destinationIp); - } - - @Override - public void suppressIngress(InterfaceKey interfaceKey) { - geniusProvider.unbindPortOnIngressClassifier(interfaceKey.getName()); - } - - @Override - public void suppressNode(NodeId nodeId) { - // noop - } - - @Override - public void suppressPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp) { - // noop - } - - @Override - public void suppressMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi) { - // noop - } - - @Override - public void suppressEgress(InterfaceKey interfaceKey, String destinationIp) { - geniusProvider.unbindPortOnEgressClassifier(interfaceKey.getName()); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OpenflowRenderer.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OpenflowRenderer.java deleted file mode 100644 index 32b089f0ba..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OpenflowRenderer.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.impl; - -import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.ArrayList; -import java.util.List; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.genius.infra.ManagedNewTransactionRunner; -import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; -import org.opendaylight.infrautils.utils.concurrent.ListenableFutures; -import org.opendaylight.netvirt.sfc.classifier.providers.GeniusProvider; -import org.opendaylight.netvirt.sfc.classifier.providers.OpenFlow13Provider; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OpenflowRenderer implements ClassifierEntryRenderer { - - private static final Logger LOG = LoggerFactory.getLogger(OpenflowRenderer.class); - - private final OpenFlow13Provider openFlow13Provider; - private final GeniusProvider geniusProvider; - private final ManagedNewTransactionRunner txRunner; - - public OpenflowRenderer(OpenFlow13Provider openFlow13Provider, GeniusProvider geniusProvider, - DataBroker dataBroker) { - this.openFlow13Provider = openFlow13Provider; - this.geniusProvider = geniusProvider; - this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); - } - - @Override - public void renderIngress(InterfaceKey interfaceKey) { - // noop - } - - @Override - // FindBugs reports "Useless object stored in variable flows" however it doesn't recognize the usage of forEach. - @SuppressFBWarnings("UC_USELESS_OBJECT") - public void renderNode(NodeId nodeId) { - List flows = new ArrayList<>(); - flows.add(this.openFlow13Provider.createIngressClassifierFilterTunnelNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierFilterEthNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierFilterNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierFilterNoNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierAclNoMatchFlow(nodeId)); - - flows.add(this.openFlow13Provider.createIngressClassifierTunnelEthNshTrafficCaptureFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierTunnelNshTrafficCaptureFlow(nodeId)); - - flows.add(this.openFlow13Provider.createEgressClassifierFilterNoNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createEgressClassifierFilterNshFlow(nodeId)); - - flows.add(this.openFlow13Provider.createEgressClassifierNextHopFlow(nodeId)); - - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, - tx -> flows.forEach(flow -> this.openFlow13Provider.appendFlowForCreate(nodeId, flow, tx))), LOG, - "Error rendering node"); - } - - @Override - // FindBugs reports "Useless object stored in variable flows" however it doesn't recognize the usage of forEach. - @SuppressFBWarnings("UC_USELESS_OBJECT") - public void renderPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp) { - - List flows = new ArrayList<>(); - if (firstHopIp != null) { - Long port = geniusProvider.getEgressVxlanPortForNode(OpenFlow13Provider.getDpnIdFromNodeId(nodeId)) - .orElse(null); - if (port == null) { - LOG.error("OpenflowRenderer: cant get egressPort for nodeId [{}]", nodeId.getValue()); - return; - } - Flow flow; - flow = openFlow13Provider.createEgressClassifierTransportEgressRemoteEthNshFlow( - nodeId, nsp, port, firstHopIp); - flows.add(flow); - } else { - Flow flow; - flow = openFlow13Provider.createEgressClassifierTransportEgressLocalFlow(nodeId, nsp); - flows.add(flow); - } - short egressNsi = (short) (nsi - nsl); - flows.add(openFlow13Provider.createIngressClassifierFilterChainEgressFlow(nodeId, nsp, egressNsi)); - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, - tx -> flows.forEach(flow -> this.openFlow13Provider.appendFlowForCreate(nodeId, flow, tx))), LOG, - "Error rendering a path"); - } - - @Override - public void renderMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi) { - Long port = OpenFlow13Provider.getPortNoFromNodeConnector(connector); - List matchBuilds = this.openFlow13Provider.getMatchBuilderFromAceMatches(matches); - for (MatchBuilder match : matchBuilds) { - Flow flow = this.openFlow13Provider.createIngressClassifierAclFlow(nodeId, match, port, nsp, nsi); - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, - tx -> this.openFlow13Provider.appendFlowForCreate(nodeId, flow, tx)), LOG, "Error rendering a match"); - } - } - - @Override - public void renderEgress(InterfaceKey interfaceKey, String destinationIp) { - // noop - } - - @Override - public void suppressIngress(InterfaceKey interfaceKey) { - // noop - } - - @Override - // FindBugs reports "Useless object stored in variable flows" however it doesn't recognize the usage of forEach. - @SuppressFBWarnings("UC_USELESS_OBJECT") - public void suppressNode(NodeId nodeId) { - List flows = new ArrayList<>(); - flows.add(this.openFlow13Provider.createIngressClassifierFilterTunnelNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierFilterEthNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierFilterNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierFilterNoNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierAclNoMatchFlow(nodeId)); - - flows.add(this.openFlow13Provider.createIngressClassifierTunnelEthNshTrafficCaptureFlow(nodeId)); - flows.add(this.openFlow13Provider.createIngressClassifierTunnelNshTrafficCaptureFlow(nodeId)); - - flows.add(this.openFlow13Provider.createEgressClassifierFilterNoNshFlow(nodeId)); - flows.add(this.openFlow13Provider.createEgressClassifierFilterNshFlow(nodeId)); - - flows.add(this.openFlow13Provider.createEgressClassifierNextHopFlow(nodeId)); - - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, - tx -> flows.forEach(flow -> this.openFlow13Provider.appendFlowForDelete(nodeId, flow, tx))), LOG, - "Error deleting a node"); - } - - @Override - // FindBugs reports "Useless object stored in variable flows" however it doesn't recognize the usage of forEach. - @SuppressFBWarnings("UC_USELESS_OBJECT") - public void suppressPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp) { - List flows = new ArrayList<>(); - if (firstHopIp != null) { - Long port = geniusProvider.getEgressVxlanPortForNode(OpenFlow13Provider.getDpnIdFromNodeId(nodeId)) - .orElse(null); - if (port == null) { - LOG.error("OpenflowRenderer: cant get egressPort for nodeId [{}]", nodeId.getValue()); - return; - } - Flow flow; - flow = openFlow13Provider.createEgressClassifierTransportEgressRemoteEthNshFlow( - nodeId, nsp, port, firstHopIp); - flows.add(flow); - } else { - Flow flow; - flow = openFlow13Provider.createEgressClassifierTransportEgressLocalFlow(nodeId, nsp); - flows.add(flow); - } - short egressNsi = (short) (nsi - nsl); - flows.add(openFlow13Provider.createIngressClassifierFilterChainEgressFlow(nodeId, nsp, egressNsi)); - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, - tx -> flows.forEach(flow -> this.openFlow13Provider.appendFlowForDelete(nodeId, flow, tx))), LOG, - "Error deleting a path"); - } - - @Override - public void suppressMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi) { - Long port = OpenFlow13Provider.getPortNoFromNodeConnector(connector); - List matchBuilds = this.openFlow13Provider.getMatchBuilderFromAceMatches(matches); - for (MatchBuilder match : matchBuilds) { - Flow flow = this.openFlow13Provider.createIngressClassifierAclFlow(nodeId, match, port, nsp, nsi); - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, - tx -> this.openFlow13Provider.appendFlowForDelete(nodeId, flow, tx)), LOG, "Error deleting a match"); - } - } - - @Override - public void suppressEgress(InterfaceKey interfaceKey, String destinationIp) { - // noop - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OperationalClassifierImpl.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OperationalClassifierImpl.java deleted file mode 100644 index f5da0e2a97..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OperationalClassifierImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.impl; - -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import org.opendaylight.netvirt.sfc.classifier.service.domain.ClassifierEntry; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierRenderableEntry; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; - -public class OperationalClassifierImpl implements ClassifierState { - - private final Set entries = ConcurrentHashMap.newKeySet(); - - @Override - public Set getAllEntries() { - return Collections.unmodifiableSet(entries); - } - - public ClassifierEntryRenderer getRenderer() { - return new ClassifierEntryRenderer() { - - @Override - public void renderIngress(InterfaceKey interfaceKey) { - entries.add(ClassifierEntry.buildIngressEntry(new InterfaceKey(interfaceKey))); - } - - @Override - public void renderNode(NodeId nodeId) { - entries.add(ClassifierEntry.buildNodeEntry(nodeId)); - } - - @Override - public void renderPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp) { - entries.add(ClassifierEntry.buildPathEntry(nodeId, nsp, nsi, nsl, firstHopIp)); - } - - @Override - public void renderMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi) { - entries.add(ClassifierEntry.buildMatchEntry(nodeId, connector, matches, nsp, nsi)); - } - - @Override - public void renderEgress(InterfaceKey interfaceKey, String destinationIp) { - entries.add(ClassifierEntry.buildEgressEntry(interfaceKey, destinationIp)); - } - - @Override - public void suppressIngress(InterfaceKey interfaceKey) { - entries.remove(ClassifierEntry.buildIngressEntry(new InterfaceKey(interfaceKey))); - } - - @Override - public void suppressNode(NodeId nodeId) { - entries.remove(ClassifierEntry.buildNodeEntry(nodeId)); - } - - @Override - public void suppressPath(NodeId nodeId, Long nsp, short nsi, short nsl, String firstHopIp) { - entries.remove(ClassifierEntry.buildPathEntry(nodeId, nsp, nsi, nsl, firstHopIp)); - } - - @Override - public void suppressMatch(NodeId nodeId, String connector, Matches matches, Long nsp, Short nsi) { - entries.remove(ClassifierEntry.buildMatchEntry(nodeId, connector, matches, nsp, nsi)); - } - - @Override - public void suppressEgress(InterfaceKey interfaceKey, String destinationIp) { - entries.remove(ClassifierEntry.buildEgressEntry(interfaceKey, destinationIp)); - } - }; - } - -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatches.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatches.java deleted file mode 100644 index 5f31b3f887..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatches.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright © 2016 Red Hat, 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.netvirt.sfc.classifier.utils; - -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.stream.Collectors; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.genius.mdsalutil.packet.IPProtocols; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEthBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.grouping.ExtensionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfTcpDstKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfTcpSrcKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfUdpDstKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfUdpSrcKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.dst.grouping.NxmOfTcpDstBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.src.grouping.NxmOfTcpSrcBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.dst.grouping.NxmOfUdpDstBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.src.grouping.NxmOfUdpSrcBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AclMatches { - private static final Logger LOG = LoggerFactory.getLogger(AclMatches.class); - private MatchBuilder matchBuilder; - private List portMatches; - private final Matches matches; - private boolean ipv4EtherTypeSet; - private boolean ipv6EtherTypeSet; - - public AclMatches(Matches matches) { - this.matches = matches; - this.ipv4EtherTypeSet = false; - this.ipv6EtherTypeSet = false; - } - - /** - * Convert the ACL into an OpenFlow {@link MatchBuilder}. - * @return {@link MatchBuilder} - */ - public List buildMatch() { - matchBuilder = new MatchBuilder(); - portMatches = new ArrayList<>(); - List newMatches = new ArrayList<>(); - if (matches.getAceType() instanceof AceEth) { - addEthMatch(); - } else if (matches.getAceType() instanceof AceIp) { - addIpMatch(); - } - if (portMatches.isEmpty()) { - newMatches.add(this.matchBuilder); - } else { - for (GeneralAugMatchNodesNodeTableFlow portMatch : portMatches) { - newMatches.add(new MatchBuilder(matchBuilder.build()) - .addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, portMatch)); - } - } - LOG.debug("returned matches: {}", newMatches); - return newMatches; - } - - private void addEthMatch() { - AceEth aceEth = (AceEth) matches.getAceType(); - - if (aceEth.getSourceMacAddress() != null) { - EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder(); - EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder(); - ethSourceBuilder.setAddress(new MacAddress(aceEth.getSourceMacAddress())); - ethernetMatch.setEthernetSource(ethSourceBuilder.build()); - - matchBuilder.setEthernetMatch(mergeEthernetMatch(matchBuilder, ethernetMatch)); - } - - if (aceEth.getDestinationMacAddress() != null) { - EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder(); - EthernetDestinationBuilder ethDestBuilder = new EthernetDestinationBuilder(); - ethDestBuilder.setAddress(new MacAddress(aceEth.getDestinationMacAddress())); - ethernetMatch.setEthernetDestination(ethDestBuilder.build()); - - matchBuilder.setEthernetMatch(mergeEthernetMatch(matchBuilder, ethernetMatch)); - } - } - - private void addIpMatch() { - AceIp aceIp = (AceIp)matches.getAceType(); - - if (aceIp.getDscp() != null) { - addDscpMatch(aceIp); - } - - if (aceIp.getProtocol() != null) { - addIpProtocolMatch(aceIp); - } - - if (aceIp.getAceIpVersion() instanceof AceIpv4) { - addIpV4Match(aceIp); - } - - if (aceIp.getAceIpVersion() instanceof AceIpv6) { - addIpV6Match(aceIp); - } - } - - private void addDscpMatch(AceIp aceIp) { - setIpv4EtherType(); - - IpMatchBuilder ipMatch = new IpMatchBuilder(); - Dscp dscp = new Dscp(aceIp.getDscp()); - ipMatch.setIpDscp(dscp); - - matchBuilder.setIpMatch(mergeIpMatch(matchBuilder, ipMatch)); - } - - private void addIpProtocolMatch(AceIp aceIp) { - // Match on IP - setIpv4EtherType(); - IpMatchBuilder ipMatch = new IpMatchBuilder(); - ipMatch.setIpProtocol(aceIp.getProtocol()); - matchBuilder.setIpMatch(mergeIpMatch(matchBuilder, ipMatch)); - - Integer srcPort = null; - if (aceIp.getSourcePortRange() != null && aceIp.getSourcePortRange().getLowerPort() != null) { - srcPort = aceIp.getSourcePortRange().getLowerPort().getValue().toJava(); - } - - Integer srcPortMax = srcPort; - if (aceIp.getSourcePortRange() != null && aceIp.getSourcePortRange().getUpperPort() != null) { - srcPortMax = aceIp.getSourcePortRange().getUpperPort().getValue().toJava(); - } - - Integer dstPort = null; - if (aceIp.getDestinationPortRange() != null && aceIp.getDestinationPortRange().getLowerPort() != null) { - dstPort = aceIp.getDestinationPortRange().getLowerPort().getValue().toJava(); - } - - Integer dstPortMax = dstPort; - if (aceIp.getDestinationPortRange() != null && aceIp.getDestinationPortRange().getUpperPort() != null) { - dstPortMax = aceIp.getDestinationPortRange().getUpperPort().getValue().toJava(); - } - - // Match on a TCP/UDP src/dst port - if (srcPort != null || dstPort != null) { - Map srcPortMaskMap = srcPort == null ? Collections.singletonMap(0, 0) : - getLayer4MaskForRange(srcPort, srcPortMax); - Map dstPortMaskMap = dstPort == null ? Collections.singletonMap(0, 0) : - getLayer4MaskForRange(dstPort, dstPortMax); - Set>> srcDstMatches = Sets - .cartesianProduct(srcPortMaskMap.entrySet(), dstPortMaskMap.entrySet()); - if (aceIp.getProtocol().shortValue() == IPProtocols.TCP.shortValue()) { - portMatches = srcDstMatches.stream().map(srcDstPairList -> buildTcpMatch(srcDstPairList - .get(0), srcDstPairList.get(1))).collect(Collectors.toList()); - } else if (aceIp.getProtocol().shortValue() == IPProtocols.UDP.shortValue()) { - portMatches = srcDstMatches.stream().map(srcDstPairList -> buildUdpMatch(srcDstPairList - .get(0), srcDstPairList.get(1))).collect(Collectors.toList()); - } - } - } - - private static GeneralAugMatchNodesNodeTableFlow buildTcpMatch(Map.Entry srcEntry, - Map.Entry dstEntry) { - List srcDstExtList = new ArrayList<>(); - - if (srcEntry.getValue() != 0) { - NxmOfTcpSrcBuilder tcpSrc = new NxmOfTcpSrcBuilder(); - tcpSrc.setMask(srcEntry.getValue()); - tcpSrc.setPort(new PortNumber(srcEntry.getKey())); - NxAugMatchNodesNodeTableFlow nxAugMatchTcpSrc = - new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfTcpSrc(tcpSrc.build()).build(); - srcDstExtList.add(new ExtensionListBuilder().setExtensionKey(NxmOfTcpSrcKey.class) - .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, - nxAugMatchTcpSrc).build()).build()); - } - - if (dstEntry.getValue() != 0) { - NxmOfTcpDstBuilder tcpDst = new NxmOfTcpDstBuilder(); - tcpDst.setMask(dstEntry.getValue()); - tcpDst.setPort(new PortNumber(dstEntry.getKey())); - NxAugMatchNodesNodeTableFlow nxAugMatchTcpDst = - new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfTcpDst(tcpDst.build()).build(); - srcDstExtList.add(new ExtensionListBuilder().setExtensionKey(NxmOfTcpDstKey.class) - .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, - nxAugMatchTcpDst).build()).build()); - } - - GeneralAugMatchNodesNodeTableFlow genAugMatch = - new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(srcDstExtList).build(); - - return genAugMatch; - } - - private static GeneralAugMatchNodesNodeTableFlow buildUdpMatch(Map.Entry srcEntry, - Map.Entry dstEntry) { - List srcDstExtList = new ArrayList<>(); - - if (srcEntry.getValue() != 0) { - NxmOfUdpSrcBuilder udpSrc = new NxmOfUdpSrcBuilder(); - udpSrc.setMask(srcEntry.getValue()); - udpSrc.setPort(new PortNumber(srcEntry.getKey())); - NxAugMatchNodesNodeTableFlow nxAugMatchUdpSrc = - new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfUdpSrc(udpSrc.build()).build(); - srcDstExtList.add(new ExtensionListBuilder().setExtensionKey(NxmOfUdpSrcKey.class) - .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, - nxAugMatchUdpSrc).build()).build()); - } - - if (dstEntry.getValue() != 0) { - NxmOfUdpDstBuilder udpDst = new NxmOfUdpDstBuilder(); - udpDst.setMask(dstEntry.getValue()); - udpDst.setPort(new PortNumber(dstEntry.getKey())); - NxAugMatchNodesNodeTableFlow nxAugMatchUdpDst = - new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfUdpDst(udpDst.build()).build(); - srcDstExtList.add(new ExtensionListBuilder().setExtensionKey(NxmOfUdpDstKey.class) - .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, - nxAugMatchUdpDst).build()).build()); - } - - GeneralAugMatchNodesNodeTableFlow genAugMatch = - new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(srcDstExtList).build(); - - return genAugMatch; - } - - public static Map getLayer4MaskForRange(int portMin, int portMax) { - final int[] offset = { 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 }; - final int[] mask = { 0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0, - 0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF }; - int noOfPorts = portMax - portMin + 1; - Map portMap = new HashMap<>(); - if (noOfPorts == 1) { - portMap.put(portMin, mask[15]); - return portMap; - } else if (noOfPorts == 65535) { - portMap.put(portMin, 0x0000); - return portMap; - } - if (noOfPorts < 0) { // TODO: replace with infrautils.counter in case of high repetitive usage - LOG.warn("Cannot convert port range into a set of masked port ranges - Illegal port range {}-{}", portMin, - portMax); - return portMap; - } - String binaryNoOfPorts = Integer.toBinaryString(noOfPorts); - if (binaryNoOfPorts.length() > 16) { // TODO: replace with infrautils.counter in case of high repetitive usage - LOG.warn("Cannot convert port range into a set of masked port ranges - Illegal port range {}-{}", portMin, - portMax); - return portMap; - } - int medianOffset = 16 - binaryNoOfPorts.length(); - int medianLength = offset[medianOffset]; - int median = 0; - for (int tempMedian = 0;tempMedian < portMax;) { - tempMedian = medianLength + tempMedian; - if (portMin < tempMedian) { - median = tempMedian; - break; - } - } - int tempMedian = 0; - int currentMedain = median; - for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) { - tempMedian = currentMedain - offset[tempMedianOffset]; - for (;portMin <= tempMedian;) { - portMap.put(tempMedian, mask[tempMedianOffset]); - currentMedain = tempMedian; - tempMedian = tempMedian - offset[tempMedianOffset]; - } - } - currentMedain = median; - for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) { - tempMedian = currentMedain + offset[tempMedianOffset]; - for (;portMax >= tempMedian - 1;) { - portMap.put(currentMedain, mask[tempMedianOffset]); - currentMedain = tempMedian; - tempMedian = tempMedian + offset[tempMedianOffset]; - } - } - return portMap; - } - - private void addIpV4Match(AceIp aceIp) { - setIpv4EtherType(); - - AceIpv4 aceIpv4 = (AceIpv4)aceIp.getAceIpVersion(); - if (aceIpv4.getDestinationIpv4Network() != null) { - Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder(); - ipv4match.setIpv4Destination(aceIpv4.getDestinationIpv4Network()); - matchBuilder.setLayer3Match(mergeIpv4Match(matchBuilder, ipv4match)); - } - - if (aceIpv4.getSourceIpv4Network() != null) { - Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder(); - ipv4match.setIpv4Source(aceIpv4.getSourceIpv4Network()); - matchBuilder.setLayer3Match(mergeIpv4Match(matchBuilder, ipv4match)); - } - } - - private void addIpV6Match(AceIp aceIp) { - setIpv6EtherType(); - - AceIpv6 aceIpv6 = (AceIpv6)aceIp.getAceIpVersion(); - if (aceIpv6.getSourceIpv6Network() != null) { - Ipv6MatchBuilder ipv6match = new Ipv6MatchBuilder(); - ipv6match.setIpv6Source(aceIpv6.getSourceIpv6Network()); - matchBuilder.setLayer3Match(mergeIpv6Match(matchBuilder, ipv6match)); - } - - if (aceIpv6.getDestinationIpv6Network() != null) { - Ipv6MatchBuilder ipv6match = new Ipv6MatchBuilder(); - ipv6match.setIpv6Destination(aceIpv6.getDestinationIpv6Network()); - matchBuilder.setLayer3Match(mergeIpv6Match(matchBuilder, ipv6match)); - } - } - - // If we call multiple Layer3 match methods, the MatchBuilder - // Ipv4Match object gets overwritten each time, when we actually - // want to set additional fields on the existing Ipv4Match object - private static Ipv4Match mergeIpv4Match(MatchBuilder match, Ipv4MatchBuilder ipMatchBuilder) { - Ipv4Match ipv4Match = (Ipv4Match) match.getLayer3Match(); - if (ipv4Match == null) { - return ipMatchBuilder.build(); - } - - if (ipv4Match.getIpv4Destination() != null) { - ipMatchBuilder.setIpv4Destination(ipv4Match.getIpv4Destination()); - } - - if (ipv4Match.getIpv4Source() != null) { - ipMatchBuilder.setIpv4Source(ipv4Match.getIpv4Source()); - } - - return ipMatchBuilder.build(); - } - - private void setIpv6EtherType() { - if (this.ipv6EtherTypeSet) { - // No need to set it twice - return; - } - - setEtherType(NwConstants.ETHTYPE_IPV6); - this.ipv6EtherTypeSet = true; - } - - private void setIpv4EtherType() { - if (this.ipv4EtherTypeSet) { - // No need to set it twice - return; - } - - setEtherType(NwConstants.ETHTYPE_IPV4); - this.ipv4EtherTypeSet = true; - } - - private void setEtherType(long etherType) { - EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder(); - ethTypeBuilder.setType(new EtherType(etherType)); - EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder(); - ethernetMatch.setEthernetType(ethTypeBuilder.build()); - matchBuilder.setEthernetMatch(mergeEthernetMatch(matchBuilder, ethernetMatch)); - } - - // If we call multiple Layer3 match methods, the MatchBuilder - // Ipv6Match object gets overwritten each time, when we actually - // want to set additional fields on the existing Ipv6Match object - private static Ipv6Match mergeIpv6Match(MatchBuilder match, Ipv6MatchBuilder ipMatchBuilder) { - Ipv6Match ipv6Match = (Ipv6Match) match.getLayer3Match(); - if (ipv6Match == null) { - return ipMatchBuilder.build(); - } - - if (ipv6Match.getIpv6Destination() != null) { - ipMatchBuilder.setIpv6Destination(ipv6Match.getIpv6Destination()); - } - - if (ipv6Match.getIpv6Source() != null) { - ipMatchBuilder.setIpv6Source(ipv6Match.getIpv6Source()); - } - - return ipMatchBuilder.build(); - } - - // If we call multiple IpMatch match methods, the MatchBuilder - // IpMatch object gets overwritten each time, when we actually - // want to set additional fields on the existing IpMatch object - private static IpMatch mergeIpMatch(MatchBuilder match, IpMatchBuilder ipMatchBuilder) { - IpMatch ipMatch = match.getIpMatch(); - if (ipMatch == null) { - return ipMatchBuilder.build(); - } - - if (ipMatch.getIpDscp() != null) { - ipMatchBuilder.setIpDscp(ipMatch.getIpDscp()); - } - - if (ipMatch.getIpEcn() != null) { - ipMatchBuilder.setIpEcn(ipMatch.getIpEcn()); - } - - if (ipMatch.getIpProto() != null) { - ipMatchBuilder.setIpProto(ipMatch.getIpProto()); - } - - if (ipMatch.getIpProtocol() != null) { - ipMatchBuilder.setIpProtocol(ipMatch.getIpProtocol()); - } - - return ipMatchBuilder.build(); - } - - // If we call multiple ethernet match methods, the MatchBuilder - // EthernetMatch object gets overwritten each time, when we actually - // want to set additional fields on the existing EthernetMatch object - private static EthernetMatch mergeEthernetMatch(MatchBuilder match, EthernetMatchBuilder ethMatchBuilder) { - EthernetMatch ethMatch = match.getEthernetMatch(); - if (ethMatch == null) { - return ethMatchBuilder.build(); - } - - if (ethMatch.getEthernetDestination() != null) { - ethMatchBuilder.setEthernetDestination(ethMatch.getEthernetDestination()); - } - - if (ethMatch.getEthernetSource() != null) { - ethMatchBuilder.setEthernetSource(ethMatch.getEthernetSource()); - } - - if (ethMatch.getEthernetType() != null) { - ethMatchBuilder.setEthernetType(ethMatch.getEthernetType()); - } - - return ethMatchBuilder.build(); - } - - public static Matches invertMatches(Matches matches) { - LOG.trace("Invert matches: {}", matches); - MatchesBuilder matchesBuilder = new MatchesBuilder(matches); - - if (matches.getAceType() instanceof AceIp) { - AceIp aceIp = (AceIp) matches.getAceType(); - AceIpBuilder aceIpBuilder = new AceIpBuilder(aceIp); - aceIpBuilder.setDestinationPortRange(null); - aceIpBuilder.setSourcePortRange(null); - SourcePortRange sourcePortRange = aceIp.getSourcePortRange(); - DestinationPortRange destinationPortRange = aceIp.getDestinationPortRange(); - - if (sourcePortRange != null) { - DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder(); - destinationPortRangeBuilder.setLowerPort(sourcePortRange.getLowerPort()); - destinationPortRangeBuilder.setUpperPort(sourcePortRange.getUpperPort()); - aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build()); - } - - if (destinationPortRange != null) { - SourcePortRangeBuilder sourcePortRangeBuilder = new SourcePortRangeBuilder(); - sourcePortRangeBuilder.setLowerPort(destinationPortRange.getLowerPort()); - sourcePortRangeBuilder.setUpperPort(destinationPortRange.getUpperPort()); - aceIpBuilder.setSourcePortRange(sourcePortRangeBuilder.build()); - } - - if (aceIp.getAceIpVersion() instanceof AceIpv4) { - AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion(); - Ipv4Prefix destinationIpv4Network = aceIpv4.getDestinationIpv4Network(); - Ipv4Prefix sourceIpv4Network = aceIpv4.getSourceIpv4Network(); - - AceIpv4Builder aceIpv4Builder = new AceIpv4Builder(aceIpv4); - aceIpv4Builder.setDestinationIpv4Network(sourceIpv4Network); - aceIpv4Builder.setSourceIpv4Network(destinationIpv4Network); - aceIpBuilder.setAceIpVersion(aceIpv4Builder.build()); - - } else if (aceIp.getAceIpVersion() instanceof AceIpv6) { - AceIpv6 aceIpv6 = (AceIpv6) aceIp.getAceIpVersion(); - Ipv6Prefix destinationIpv6Network = aceIpv6.getDestinationIpv6Network(); - Ipv6Prefix sourceIpv6Network = aceIpv6.getSourceIpv6Network(); - - AceIpv6Builder aceIpv6Builder = new AceIpv6Builder(aceIpv6); - aceIpv6Builder.setDestinationIpv6Network(sourceIpv6Network); - aceIpv6Builder.setSourceIpv6Network(destinationIpv6Network); - aceIpBuilder.setAceIpVersion(aceIpv6Builder.build()); - } - - matchesBuilder.setAceType(aceIpBuilder.build()); - - } else if (matches.getAceType() instanceof AceEth) { - AceEth aceEth = (AceEth) matches.getAceType(); - MacAddress destinationMacAddress = aceEth.getDestinationMacAddress(); - MacAddress destinationMacAddressMask = aceEth.getDestinationMacAddressMask(); - MacAddress sourceMacAddress = aceEth.getSourceMacAddress(); - MacAddress sourceMacAddressMask = aceEth.getSourceMacAddressMask(); - - AceEthBuilder aceEthBuilder = new AceEthBuilder(aceEth); - aceEthBuilder.setDestinationMacAddress(sourceMacAddress); - aceEthBuilder.setDestinationMacAddressMask(sourceMacAddressMask); - aceEthBuilder.setSourceMacAddress(destinationMacAddress); - aceEthBuilder.setSourceMacAddressMask(destinationMacAddressMask); - matchesBuilder.setAceType(aceEthBuilder.build()); - } - - Matches invertedMatches = matchesBuilder.build(); - LOG.trace("Inverted matches: {}", invertedMatches); - return invertedMatches; - } - -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutor.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutor.java deleted file mode 100644 index de225827c1..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.utils; - -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicReference; - -/** - * An executor that only executes the last submitted task. Ongoing tasks wont - * be cancelled. - */ -public class LastTaskExecutor implements Executor { - - private final Executor executor; - private final AtomicReference lastTask = new AtomicReference<>(); - - public LastTaskExecutor(Executor executor) { - this.executor = executor; - } - - @Override - public void execute(final Runnable newTask) { - if (newTask == null) { - throw new NullPointerException(); - } - - lastTask.set(newTask); - executor.execute(() -> { - final Runnable runTask = lastTask.getAndSet(null); - if (runTask != null) { - runTask.run(); - } - }); - } -} diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/OpenFlow13Utils.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/OpenFlow13Utils.java deleted file mode 100644 index 1cff916111..0000000000 --- a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/OpenFlow13Utils.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.utils; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.PacketTypeMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.PacketTypeMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.ExtensionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.grouping.ExtensionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.DstChoice; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc4CaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNsiCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNspCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegMoveNodesNodeGroupBucketsBucketActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionDecapNodesNodeTableFlowApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionEncapNodesNodeTableFlowApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.write.actions._case.write.actions.action.action.NxActionResubmitNodesNodeTableFlowWriteActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.decap.grouping.NxDecap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.decap.grouping.NxDecapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.encap.grouping.NxEncap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.encap.grouping.NxEncapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoadBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.Dst; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.DstBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMove; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMoveBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.nx.reg.move.SrcBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.resubmit.grouping.NxResubmitBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.SrcChoice; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc4CaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNsiKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNspKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg2Key; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxTunIdKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxTunIpv4DstKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsi.grouping.NxmNxNsiBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsp.grouping.NxmNxNspBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.reg.grouping.NxmNxReg; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.reg.grouping.NxmNxRegBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.tun.id.grouping.NxmNxTunIdBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.tun.ipv4.dst.grouping.NxmNxTunIpv4DstBuilder; -import org.opendaylight.yangtools.yang.common.Empty; - -public final class OpenFlow13Utils { - public static final long ETHERTYPE_NSH = 0x894f; - public static final long PACKET_TYPE_NSH = 0x1894f; - public static final long PACKET_TYPE_ETH = 0; - - private OpenFlow13Utils() { - } - - public static void addMatchTunId(MatchBuilder match, long value) { - NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder() - .setNxmNxTunId(new NxmNxTunIdBuilder().setValue(BigInteger.valueOf(value)).build()).build(); - addExtension(match, NxmNxTunIdKey.class, am); - } - - public static void addMatchTunDstIp(MatchBuilder match, Ipv4Address ipv4Address) { - NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder() - .setNxmNxTunIpv4Dst(new NxmNxTunIpv4DstBuilder().setIpv4Address(ipv4Address).build()).build(); - addExtension(match, NxmNxTunIpv4DstKey.class, am); - } - - public static void addMatchEthNsh(MatchBuilder match) { - EtherType etherType = new EtherType(ETHERTYPE_NSH); - EthernetType ethernetType = new EthernetTypeBuilder().setType(etherType).build(); - EthernetMatch ethernetMatch = new EthernetMatchBuilder().setEthernetType(ethernetType).build(); - match.setEthernetMatch(ethernetMatch); - } - - public static void addMatchPacketTypeNsh(MatchBuilder match) { - PacketTypeMatch packetTypeMatch = new PacketTypeMatchBuilder().setPacketType(PACKET_TYPE_NSH).build(); - match.setPacketTypeMatch(packetTypeMatch); - } - - public static void addMatchInPort(MatchBuilder match, NodeId nodeId, long inPort) { - match.setInPort(new NodeConnectorId(nodeId.getValue() + ":" + inPort)); - } - - public static void addMatchNsp(MatchBuilder match, long nsp) { - NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder() - .setNxmNxNsp(new NxmNxNspBuilder().setValue(nsp).build()).build(); - addExtension(match, NxmNxNspKey.class, am); - } - - public static void addMatchNsi(MatchBuilder match, short nsi) { - NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder() - .setNxmNxNsi(new NxmNxNsiBuilder().setNsi(nsi).build()).build(); - addExtension(match, NxmNxNsiKey.class, am); - } - - public static void addMatchReg2(MatchBuilder match, long value) { - NxmNxReg nxmNxReg = new NxmNxRegBuilder().setReg(NxmNxReg2.class).setValue(value).build(); - NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxReg(nxmNxReg).build(); - addExtension(match, NxmNxReg2Key.class, am); - } - - private static void addExtension(MatchBuilder match, Class extensionKey, - NxAugMatchNodesNodeTableFlow am) { - GeneralAugMatchNodesNodeTableFlow existingAugmentations = match - .augmentation(GeneralAugMatchNodesNodeTableFlow.class); - List extensions = null; - if (existingAugmentations != null) { - extensions = existingAugmentations.getExtensionList(); - } - if (extensions == null) { - extensions = new ArrayList<>(); - } - - extensions.add(new ExtensionListBuilder().setExtensionKey(extensionKey) - .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build()) - .build()); - - GeneralAugMatchNodesNodeTableFlow generalAugMatchNodesNode = new GeneralAugMatchNodesNodeTableFlowBuilder() - .setExtensionList(extensions).build(); - match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, generalAugMatchNodesNode); - } - - public static Action createActionResubmitTable(final short toTable, int order) { - return createActionBuilder(order) - .setAction(new NxActionResubmitNodesNodeTableFlowWriteActionsCaseBuilder() - .setNxResubmit(new NxResubmitBuilder() - .setTable(toTable) - .build()) - .build()) - .build(); - } - - public static Action createActionNxLoadTunIpv4Dst(long value, int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxLoadRegAction(new DstNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Empty.getInstance()).build(), - BigInteger.valueOf(value), 0,31, false)); - - return ab.build(); - } - - public static Action createActionNxLoadTunId(long value, int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxLoadRegAction(new DstNxTunIdCaseBuilder().setNxTunId(Empty.getInstance()).build(), - BigInteger.valueOf(value), 0,31, false)); - - return ab.build(); - } - - public static Action createActionNxEncapNsh(int order) { - return createActionNxEncap(order, PACKET_TYPE_NSH); - } - - public static Action createActionNxEncapEthernet(int order) { - return createActionNxEncap(order, PACKET_TYPE_ETH); - } - - private static Action createActionNxEncap(int order, long packetType) { - NxEncap nxEncap = new NxEncapBuilder().setPacketType(packetType).build(); - ActionBuilder ab = createActionBuilder(order); - ab.setAction(new NxActionEncapNodesNodeTableFlowApplyActionsCaseBuilder().setNxEncap(nxEncap).build()); - return ab.build(); - } - - public static Action createActionNxDecap(int order) { - NxDecap nxDecap = new NxDecapBuilder().build(); - ActionBuilder ab = createActionBuilder(order); - ab.setAction(new NxActionDecapNodesNodeTableFlowApplyActionsCaseBuilder().setNxDecap(nxDecap).build()); - return ab.build(); - } - - public static Action createActionNxMoveTunIdToNsc2Register(int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxMoveRegAction(new SrcNxTunIdCaseBuilder().setNxTunId(Empty.getInstance()).build(), 0, 31, - new DstNxNshc2CaseBuilder().setNxNshc2Dst(Empty.getInstance()).build(), 0, 31, - false)); - - return ab.build(); - } - - public static Action createActionNxMoveReg0ToNsc1Register(int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxMoveRegAction( - new SrcNxRegCaseBuilder().setNxReg(NxmNxReg0.class).build(), 0, 31, - new DstNxNshc1CaseBuilder().setNxNshc1Dst(Empty.getInstance()).build(), 0,31, - false)); - - return ab.build(); - } - - public static Action createActionNxMoveReg6ToNsc4Register(int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(NxmNxReg6.class).build(), 0, 31, - new DstNxNshc4CaseBuilder().setNxNshc4Dst(Empty.getInstance()).build(), 0, 31, - false)); - - return ab.build(); - } - - public static Action createActionNxMoveNsc4ToReg6Register(int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxMoveRegAction(new SrcNxNshc4CaseBuilder().setNxNshc4Dst(Empty.getInstance()).build(), 0, 31, - new DstNxRegCaseBuilder().setNxReg(NxmNxReg6.class).build(), 0, 31, - false)); - - return ab.build(); - } - - public static Action createActionNxLoadNspToReg2High(long value, int order) { - ActionBuilder ab = createActionBuilder(order); - DstNxRegCase dstNxRegCase = new DstNxRegCaseBuilder().setNxReg(NxmNxReg2.class).build(); - ab.setAction( - // Load NSP to the 3 most significant bytes - nxLoadRegAction(dstNxRegCase, BigInteger.valueOf(value), 8, 31, false)); - return ab.build(); - } - - public static Action createActionNxMoveReg2HighToNsp(int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxMoveRegAction( - // Move NSP from the 3 most significant bytes - new SrcNxRegCaseBuilder().setNxReg(NxmNxReg2.class).build(), 8, 31, - new DstNxNspCaseBuilder().setNxNspDst(Empty.getInstance()).build(), 0, 23, - false)); - - return ab.build(); - } - - public static Action createActionNxLoadNsiToReg2Low(long value, int order) { - ActionBuilder ab = createActionBuilder(order); - DstNxRegCase dstNxRegCase = new DstNxRegCaseBuilder().setNxReg(NxmNxReg2.class).build(); - ab.setAction( - // Load NSI to the least significant byte - nxLoadRegAction(dstNxRegCase, BigInteger.valueOf(value), 0, 7, false)); - return ab.build(); - } - - public static Action createActionNxMoveReg2LowToNsi(int order) { - ActionBuilder ab = createActionBuilder(order); - ab.setAction(nxMoveRegAction( - // Move NSI from the least significant byte - new SrcNxRegCaseBuilder().setNxReg(NxmNxReg2.class).build(), 0, 7, - new DstNxNsiCaseBuilder().setNxNsiDst(Empty.getInstance()).build(), 0, 7, - false)); - - return ab.build(); - } - - public static Action createActionNxLoadReg2(long value, int order) { - ActionBuilder ab = createActionBuilder(order); - DstNxRegCase dstNxRegCase = new DstNxRegCaseBuilder().setNxReg(NxmNxReg2.class).build(); - ab.setAction( - nxLoadRegAction(dstNxRegCase, BigInteger.valueOf(value), 0, 31, false)); - return ab.build(); - } - - - private static org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nxLoadRegAction( - DstChoice dstChoice, BigInteger value, int startOffset, int endOffset, boolean groupBucket) { - Dst dst = new DstBuilder().setDstChoice(dstChoice).setStart(startOffset).setEnd(endOffset).build(); - NxRegLoad regLoad = new NxRegLoadBuilder().setDst(dst).setValue(value).build(); - - if (groupBucket) { - return new NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder().setNxRegLoad(regLoad).build(); - } else { - return new NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder().setNxRegLoad(regLoad).build(); - } - } - - public static org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nxMoveRegAction( - SrcChoice srcChoice, int srcStartOffset, int srcEndOffset, - DstChoice dstChoice, int dstStartOffset, int dstEndOffset, - boolean groupBucket) { - - NxRegMove nxRegMove = new NxRegMoveBuilder() - .setSrc(new SrcBuilder().setSrcChoice(srcChoice).setStart(srcStartOffset).setEnd(srcEndOffset).build()) - .setDst(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira - .action.rev140714.nx.action.reg.move.grouping.nx.reg.move.DstBuilder() - .setDstChoice(dstChoice).setStart(dstStartOffset).setEnd(dstEndOffset).build()) - .build(); - - if (groupBucket) { - return new NxActionRegMoveNodesNodeGroupBucketsBucketActionsCaseBuilder().setNxRegMove(nxRegMove).build(); - } else { - return new NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder().setNxRegMove(nxRegMove).build(); - } - } - - public static Action createActionOutPort(final String portUri, final int order) { - OutputActionBuilder output = new OutputActionBuilder(); - Uri value = new Uri(portUri); - output.setOutputNodeConnector(value); - ActionBuilder ab = createActionBuilder(order); - ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build()); - - return ab.build(); - } - - public static ActionBuilder createActionBuilder(int order) { - ActionBuilder ab = new ActionBuilder(); - ab.setOrder(order); - ab.withKey(new ActionKey(order)); - - return ab; - } - - public static InstructionsBuilder wrapActionsIntoApplyActionsInstruction(List theActions) { - // Create an Apply Action - ApplyActionsBuilder aab = new ApplyActionsBuilder(); - aab.setAction(theActions); - - // Wrap our Apply Action in an Instruction - InstructionBuilder ib = new InstructionBuilder(); - ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build()); - ib.setOrder(0); - ib.withKey(new InstructionKey(0)); - - // Put our Instruction in a list of Instructions - List instructions = new ArrayList<>(); - instructions.add(ib.build()); - return new InstructionsBuilder().setInstruction(instructions); - } - - public static FlowBuilder createFlowBuilder(final short table, final int priority, final BigInteger cookieValue, - final String flowName, final String flowIdStr, MatchBuilder match, - InstructionsBuilder isb) { - FlowBuilder flow = new FlowBuilder(); - flow.setId(new FlowId(flowIdStr)); - flow.withKey(new FlowKey(new FlowId(flowIdStr))); - flow.setTableId(table); - flow.setFlowName(flowName); - flow.setCookie(new FlowCookie(cookieValue)); - flow.setCookieMask(new FlowCookie(cookieValue)); - flow.setContainerName(null); - flow.setStrict(false); - flow.setMatch(match.build()); - flow.setInstructions(isb.build()); - flow.setPriority(priority); - flow.setHardTimeout(0); - flow.setIdleTimeout(0); - flow.setFlags(new FlowModFlags(false, false, false, false, false)); - if (null == flow.isBarrier()) { - flow.setBarrier(Boolean.FALSE); - } - - return flow; - } - - public static InstructionsBuilder appendGotoTableInstruction(InstructionsBuilder isb, short nextTableId) { - if (isb.getInstruction() == null) { - isb.setInstruction(new ArrayList<>()); - } - isb.getInstruction().add(createGotoTableInstruction(nextTableId, isb.getInstruction().size())); - return isb; - } - - public static Instruction createGotoTableInstruction(short nextTableId, int order) { - GoToTableBuilder gotoIngress = createActionGotoTable(nextTableId); - - return new InstructionBuilder().withKey(new InstructionKey(order)).setOrder(order) - .setInstruction(new GoToTableCaseBuilder().setGoToTable(gotoIngress.build()).build()).build(); - } - - public static GoToTableBuilder createActionGotoTable(final short toTable) { - GoToTableBuilder gotoTb = new GoToTableBuilder(); - gotoTb.setTableId(toTable); - - return gotoTb; - } - - public static NxRegLoad createNxLoadReg0(long value) { - Dst dst = new DstBuilder() - .setDstChoice(new DstNxRegCaseBuilder().setNxReg(NxmNxReg0.class).build()) - .setStart(0) - .setEnd(31) - .build(); - return new NxRegLoadBuilder() - .setDst(dst) - .setValue(BigInteger.valueOf(value)) - .build(); - } - - public static Action createAction( - org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action, int order) { - return new ActionBuilder() - .setOrder(order) - .withKey(new ActionKey(order)) - .setAction(action) - .build(); - } -} diff --git a/sfc/classifier/impl/src/main/resources/OSGI-INF/blueprint/sfc-classifier.xml b/sfc/classifier/impl/src/main/resources/OSGI-INF/blueprint/sfc-classifier.xml deleted file mode 100644 index 9c350acc2b..0000000000 --- a/sfc/classifier/impl/src/main/resources/OSGI-INF/blueprint/sfc-classifier.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTest.java deleted file mode 100644 index dc52042a03..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.Optional; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.opendaylight.controller.md.sal.binding.test.ConstantSchemaAbstractDataBrokerTest; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class GeniusProviderTest extends ConstantSchemaAbstractDataBrokerTest { - private GeniusProvider geniusProvider; - - @Before - public void setUp() throws Exception { - geniusProvider = new GeniusProvider(getDataBroker(), TestOdlInterfaceRpcService.newInstance(), - TestInterfaceManager.newInstance()); - } - - @Test - @Ignore("Broken in Neon (invalid number of elements)") - public void bindPortOnIngressClassifier() { - // Bind the Ingress service - geniusProvider.bindPortOnIngressClassifier(GeniusProviderTestParams.INTERFACE_NAME); - - // Now make sure its in the data store - InstanceIdentifier id = geniusProvider.getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, - GeniusProviderTestParams.INTERFACE_NAME, true); - Optional boundServices = getBoundServices(id); - assertTrue(boundServices.isPresent()); - - // UnBind the Ingress Service - geniusProvider.unbindPortOnIngressClassifier(GeniusProviderTestParams.INTERFACE_NAME); - - // Now make sure its NOT in the data store - assertFalse(getBoundServices(id).isPresent()); - } - - @Test - @Ignore("Broken in Neon (invalid number of elements)") - public void bindPortOnEgressClassifier() { - // Bind the Egress service - geniusProvider.bindPortOnEgressClassifier( - GeniusProviderTestParams.INTERFACE_NAME, - GeniusProviderTestParams.IPV4_ADDRESS_STR); - - // Now make sure its in the data store - InstanceIdentifier id = geniusProvider.getBindServiceId( - NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, - GeniusProviderTestParams.INTERFACE_NAME, - false); - Optional boundServices = getBoundServices(id); - assertTrue(boundServices.isPresent()); - - // UnBind the Egress Service - geniusProvider.unbindPortOnEgressClassifier(GeniusProviderTestParams.INTERFACE_NAME); - - // Now make sure its NOT in the data store - assertFalse(getBoundServices(id).isPresent()); - } - - @Test - public void getNodeIdFromLogicalInterface() { - //Optional getNodeIdFromLogicalInterface(String logicalInterface) - // Test that it correctly handles the case when the ifName doesnt exist - Optional nodeId = this.geniusProvider.getNodeIdFromLogicalInterface( - GeniusProviderTestParams.INTERFACE_NAME_NO_EXIST); - assertFalse(nodeId.isPresent()); - - // Test that it correctly handles RPC errors - nodeId = this.geniusProvider.getNodeIdFromLogicalInterface( - GeniusProviderTestParams.INTERFACE_NAME_INVALID); - assertFalse(nodeId.isPresent()); - - // Test that it correctly returns the DpnId when everything is correct - nodeId = this.geniusProvider.getNodeIdFromLogicalInterface( - GeniusProviderTestParams.INTERFACE_NAME); - assertTrue(nodeId.isPresent()); - assertEquals(nodeId.get().getValue(), GeniusProviderTestParams.NODE_ID); - } - - @Test - public void getNodeIdFromDpnId() { - // Test that it correctly handles null input - Optional nodeId = this.geniusProvider.getNodeIdFromDpnId(null); - assertFalse(nodeId.isPresent()); - - // Test that it correctly returns the nodeId when everything is correct - nodeId = this.geniusProvider.getNodeIdFromDpnId(new DpnIdType(GeniusProviderTestParams.DPN_ID)); - assertTrue(nodeId.isPresent()); - assertEquals(nodeId.get().getValue(), GeniusProviderTestParams.NODE_ID); - } - - @Test - public void getIpFromDpnId() { - // Test that it correctly handles the case when the ifName doesnt exist - Optional ipStr = this.geniusProvider.getIpFromDpnId( - new DpnIdType(GeniusProviderTestParams.DPN_ID_NO_EXIST)); - assertFalse(ipStr.isPresent()); - - // Test that it correctly handles RPC errors - ipStr = this.geniusProvider.getIpFromDpnId( - new DpnIdType(GeniusProviderTestParams.DPN_ID_INVALID)); - assertFalse(ipStr.isPresent()); - - // Test that it correctly returns the ipStr when everything is correct - ipStr = this.geniusProvider.getIpFromDpnId( - new DpnIdType(GeniusProviderTestParams.DPN_ID)); - assertTrue(ipStr.isPresent()); - assertEquals(ipStr.get(), GeniusProviderTestParams.IPV4_ADDRESS_STR); - } - - @Test - public void getDpnIdFromInterfaceName() { - // Test that it correctly handles the case when the ifName doesnt exist - Optional dpnId = this.geniusProvider.getDpnIdFromInterfaceName( - GeniusProviderTestParams.INTERFACE_NAME_NO_EXIST); - assertFalse(dpnId.isPresent()); - - // Test that it correctly handles RPC errors - dpnId = this.geniusProvider.getDpnIdFromInterfaceName( - GeniusProviderTestParams.INTERFACE_NAME_INVALID); - assertFalse(dpnId.isPresent()); - - // Test that it correctly returns the DpnId when everything is correct - dpnId = this.geniusProvider.getDpnIdFromInterfaceName( - GeniusProviderTestParams.INTERFACE_NAME); - assertTrue(dpnId.isPresent()); - assertEquals(dpnId.get().getValue().toJava(), GeniusProviderTestParams.DPN_ID); - } - - @Test - public void getNodeConnectorIdFromInterfaceName() { - // Test that it correctly handles the case when the ifName doesnt exist - Optional nodeConnStr = this.geniusProvider.getNodeConnectorIdFromInterfaceName( - GeniusProviderTestParams.INTERFACE_NAME_NO_EXIST); - assertFalse(nodeConnStr.isPresent()); - - // Test that it correctly handles RPC errors - nodeConnStr = this.geniusProvider.getNodeConnectorIdFromInterfaceName( - GeniusProviderTestParams.INTERFACE_NAME_INVALID); - assertFalse(nodeConnStr.isPresent()); - - // Test that it correctly returns the NodeConnectorId when everything is correct - nodeConnStr = this.geniusProvider.getNodeConnectorIdFromInterfaceName( - GeniusProviderTestParams.INTERFACE_NAME); - assertTrue(nodeConnStr.isPresent()); - assertEquals(nodeConnStr.get(), GeniusProviderTestParams.NODE_CONNECTOR_ID_PREFIX - + GeniusProviderTestParams.INTERFACE_NAME); - } - - @Test - public void getEgressVxlanPortForNode() { - // Test that it correctly handles the case when the dpnId doesnt exist - Optional ofPort = this.geniusProvider.getEgressVxlanPortForNode( - GeniusProviderTestParams.DPN_ID_NO_EXIST); - assertFalse(ofPort.isPresent()); - - // Test that it correctly handles when there are no tunnel ports on the bridge - ofPort = this.geniusProvider.getEgressVxlanPortForNode(GeniusProviderTestParams.DPN_ID_NO_PORTS); - assertFalse(ofPort.isPresent()); - - // Test that it correctly handles when there are no VXGPE tunnel ports on the bridge - ofPort = this.geniusProvider.getEgressVxlanPortForNode(GeniusProviderTestParams.DPN_ID_NO_VXGPE_PORTS); - assertFalse(ofPort.isPresent()); - - // Test that is correctly handles when a terminationPoint has no options - ofPort = this.geniusProvider.getEgressVxlanPortForNode(GeniusProviderTestParams.DPN_ID_NO_OPTIONS); - assertFalse(ofPort.isPresent()); - - // Test that it correctly returns the OpenFlow port when everything is correct - ofPort = this.geniusProvider.getEgressVxlanPortForNode(GeniusProviderTestParams.DPN_ID); - assertTrue(ofPort.isPresent()); - assertEquals(ofPort.get().longValue(), GeniusProviderTestParams.OF_PORT); - } - - Optional getBoundServices(InstanceIdentifier id) { - return Optional.ofNullable(MDSALUtil.read(getDataBroker(), LogicalDatastoreType.CONFIGURATION, id).orNull()); - } - -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTestParams.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTestParams.java deleted file mode 100644 index 65290979c6..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTestParams.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import java.math.BigInteger; - -public interface GeniusProviderTestParams { - String INTERFACE_NAME = "123456"; - String INTERFACE_NAME_INVALID = "000000"; - String INTERFACE_NAME_NO_EXIST = "111111"; - - BigInteger DPN_ID = new BigInteger("1234567890"); - BigInteger DPN_ID_NO_PORTS = new BigInteger("111111111"); - BigInteger DPN_ID_NO_VXGPE_PORTS = new BigInteger("222222222"); - BigInteger DPN_ID_NO_OPTIONS = new BigInteger("333333333"); - BigInteger DPN_ID_INVALID = new BigInteger("666666666"); - BigInteger DPN_ID_NO_EXIST = new BigInteger("999999999"); - - String NODE_ID = "openflow:" + DPN_ID.toString(); - String NODE_CONNECTOR_ID_PREFIX = "openflow:" + DPN_ID.toString() + ":"; - String IPV4_ADDRESS_STR = "192.168.0.1"; - long OF_PORT = 42L; -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProviderTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProviderTest.java deleted file mode 100644 index d914d455b7..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/NetvirtProviderTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.md.sal.binding.test.ConstantSchemaAbstractDataBrokerTest; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NeutronNetworkBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class NetvirtProviderTest extends ConstantSchemaAbstractDataBrokerTest { - private static final String NW_UUID_STR = "177bef73-514e-4922-990f-d7aba0f3b0f4"; - private static final String NW_UUID_NOEXIST_STR = "177bef73-5555-2222-0000-d7aba0f3b0f4"; - private static final String SUBNET_UUID_STR = "33333333-514e-4922-990f-d7aba0f3b0f4"; - private static final String PORT_UUID_STR = "44444444-5555-2222-0000-d7aba0f3b0f4"; - private static final String EMPTY_STR = ""; - - private NetvirtProvider netvirtProvider; - - @Before - public void setUp() throws Exception { - this.netvirtProvider = new NetvirtProvider(getDataBroker()); - } - - @Test - public void getLogicalInterfacesFromNeutronNetwork() { - - // Network doesnt exist - NeutronNetworkBuilder nwBuilder = new NeutronNetworkBuilder(); - nwBuilder.setNetworkUuid(NW_UUID_NOEXIST_STR); - List interfaces = netvirtProvider.getLogicalInterfacesFromNeutronNetwork(nwBuilder.build()); - assertTrue(interfaces.isEmpty()); - - // Network exists, subnet list empty - createNetworkMap(NW_UUID_STR); - nwBuilder = new NeutronNetworkBuilder(); - nwBuilder.setNetworkUuid(NW_UUID_STR); - interfaces = netvirtProvider.getLogicalInterfacesFromNeutronNetwork(nwBuilder.build()); - assertTrue(interfaces.isEmpty()); - - // Network exists, subnet does not exist - createNetworkMap(NW_UUID_STR, SUBNET_UUID_STR, false, EMPTY_STR); - nwBuilder = new NeutronNetworkBuilder(); - nwBuilder.setNetworkUuid(NW_UUID_STR); - interfaces = netvirtProvider.getLogicalInterfacesFromNeutronNetwork(nwBuilder.build()); - assertTrue(interfaces.isEmpty()); - - // Network exists, subnet exists, no ports - createNetworkMap(NW_UUID_STR, SUBNET_UUID_STR, true, EMPTY_STR); - nwBuilder = new NeutronNetworkBuilder(); - nwBuilder.setNetworkUuid(NW_UUID_STR); - interfaces = netvirtProvider.getLogicalInterfacesFromNeutronNetwork(nwBuilder.build()); - assertTrue(interfaces.isEmpty()); - - // Network exists, subnet exists, port exists - createNetworkMap(NW_UUID_STR, SUBNET_UUID_STR, true, PORT_UUID_STR); - nwBuilder = new NeutronNetworkBuilder(); - nwBuilder.setNetworkUuid(NW_UUID_STR); - interfaces = netvirtProvider.getLogicalInterfacesFromNeutronNetwork(nwBuilder.build()); - assertFalse(interfaces.isEmpty()); - } - - private NetworkMapBuilder createNetworkMap(String nwUuidStr) { - Uuid nwUuid = new Uuid(nwUuidStr); - NetworkMapBuilder nwMapBuilder = new NetworkMapBuilder(); - nwMapBuilder.setNetworkId(nwUuid); - storeNetworkMap(nwUuid, nwMapBuilder.build()); - - return nwMapBuilder; - } - - private void createNetworkMap(String nwUuidStr, String subnetUuidStr, boolean storeSubnet, String portUuidStr) { - SubnetmapBuilder subnetBuilder = new SubnetmapBuilder(); - if (!portUuidStr.isEmpty()) { - List portIdList = new ArrayList<>(); - portIdList.add(new Uuid(portUuidStr)); - subnetBuilder.setPortList(portIdList); - } - - Uuid subnetUuid = new Uuid(subnetUuidStr); - subnetBuilder.setId(subnetUuid); - List subnetIdList = new ArrayList<>(); - subnetIdList.add(subnetUuid); - - NetworkMapBuilder nwMapBuilder = createNetworkMap(nwUuidStr); - nwMapBuilder.setSubnetIdList(subnetIdList); - storeNetworkMap(new Uuid(nwUuidStr), nwMapBuilder.build()); - - // Simulates NetworkMap has subnet list, but subnets dont exist - if (storeSubnet) { - storeSubnetMap(subnetUuid, subnetBuilder.build()); - } - } - - @SuppressWarnings("deprecation") - private void storeNetworkMap(Uuid nwUuid, NetworkMap nwMap) { - InstanceIdentifier networkMapIdentifier = - InstanceIdentifier.builder(NetworkMaps.class) - .child(NetworkMap.class,new NetworkMapKey(nwUuid)).build(); - - MDSALUtil.syncWrite(getDataBroker(), LogicalDatastoreType.CONFIGURATION, networkMapIdentifier, nwMap); - } - - @SuppressWarnings("deprecation") - private void storeSubnetMap(Uuid subnetUuid, Subnetmap subnetMap) { - InstanceIdentifier subnetId = - InstanceIdentifier.builder(Subnetmaps.class) - .child(Subnetmap.class, new SubnetmapKey(subnetUuid)).build(); - - MDSALUtil.syncWrite(getDataBroker(), LogicalDatastoreType.CONFIGURATION, subnetId, subnetMap); - } -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13ProviderTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13ProviderTest.java deleted file mode 100644 index 6f5aa06b5d..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13ProviderTest.java +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.net.InetAddresses; -import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.netvirt.sfc.classifier.utils.AclMatches; -import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.grouping.Extension; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1Case; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2Case; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc4Case; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNsiCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNspCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionDecapNodesNodeTableFlowApplyActionsCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionEncapNodesNodeTableFlowApplyActionsCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegMoveNodesNodeTableFlowApplyActionsCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.write.actions._case.write.actions.action.action.NxActionResubmitNodesNodeTableFlowWriteActionsCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc1Case; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc2Case; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc4Case; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNsiCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNspCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCase; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow; -import org.opendaylight.yangtools.yang.common.Empty; - - -public class OpenFlow13ProviderTest { - - private OpenFlow13Provider openflowProvider; - private final NodeId nodeId; - private static final String NODE_ID_STR = "openflow:1234"; - private static final String SFF_IP_STR = "192.168.0.1"; - private static final Long IN_PORT = 8L; - private static final Long OUT_PORT = 12L; - private static final Long NSP = 6500L; - private static final Short NSI = (short) 255; - private static final Short EGRESS_NSI = (short) 253; - - public OpenFlow13ProviderTest() { - nodeId = new NodeId(NODE_ID_STR); - } - - @Before - public void setUp() { - openflowProvider = new OpenFlow13Provider(); - } - - @Test - public void createIngressClassifierFilterTunnelNshFlow() { - Flow flow = openflowProvider.createIngressClassifierFilterTunnelNshFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_TUN_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionResubmit(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.SFC_TRANSPORT_INGRESS_TABLE); - } - - @Test - public void createIngressClassifierFilterEthNshFlow() { - Flow flow = openflowProvider.createIngressClassifierFilterEthNshFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchEthNsh(flow.getMatch()); - checkMatchTunDstIp(flow.getMatch(), OpenFlow13Provider.NULL_IP); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionResubmit(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.LPORT_DISPATCHER_TABLE); - } - - @Test - public void createIngressClassifierFilterNshFlow() { - Flow flow = openflowProvider.createIngressClassifierFilterNshFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - checkMatchTunDstIp(flow.getMatch(), OpenFlow13Provider.NULL_IP); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionResubmit(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.LPORT_DISPATCHER_TABLE); - } - - @Test - public void createIngressClassifierFilterChainEgressFlow() { - Flow flow = openflowProvider.createIngressClassifierFilterChainEgressFlow(nodeId, NSP, EGRESS_NSI); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME - + nodeId.getValue() + "_" + NSP); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - checkMatchNsp(flow.getMatch(), NSP); - checkMatchNsi(flow.getMatch(), EGRESS_NSI); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - Instruction curInstruction = flow.getInstructions().getInstruction().get(0).getInstruction(); - List actionList = checkApplyActionSize(curInstruction, 3); - checkActionMoveNsc4(actionList.get(0), true); - checkActionMoveReg(actionList.get(0), NxmNxReg6.class, 0, 31, false); - checkActionDecap(actionList.get(1)); - checkActionResubmit(curInstruction, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE); - } - - @Test - public void createIngressClassifierFilterNoNshFlow() { - Flow flow = openflowProvider.createIngressClassifierFilterNoNshFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchEmpty(flow.getMatch()); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionGotoTable(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE); - } - - @Test - public void createIngressClassifierAclFlow() { - // Create an empty AclMatch to pass in - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(new AceIpBuilder().build()); - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - - List matchBuilds = aclMatches.buildMatch(); - - for (MatchBuilder matchBuilder : matchBuilds) { - Flow flow = openflowProvider.createIngressClassifierAclFlow( - nodeId, matchBuilder, IN_PORT, NSP, NSI); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_ACL_MATCH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue() - + matchBuilder.build().toString()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_ACL_COOKIE); - - // Only checking the inport match, since the rest is tested in AclMatchesTest - checkMatchInport(flow.getMatch(), nodeId.getValue() + ":" + IN_PORT); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - Instruction curInstruction = flow.getInstructions().getInstruction().get(0).getInstruction(); - List actionList = checkApplyActionSize(curInstruction, 3); - - checkActionLoadReg(actionList.get(0), NxmNxReg2.class, 8, 31, NSP); - checkActionLoadReg(actionList.get(1), NxmNxReg2.class, 0, 7, NSI); - checkActionResubmit(curInstruction, NwConstants.LPORT_DISPATCHER_TABLE); - } - } - - @Test - public void createIngressClassifierAclNoMatchFlow() { - Flow flow = openflowProvider.createIngressClassifierAclNoMatchFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.INGRESS_CLASSIFIER_ACL_COOKIE); - - checkMatchEmpty(flow.getMatch()); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionResubmit(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.LPORT_DISPATCHER_TABLE); - } - - @Test - public void createEgressClassifierFilterNshFlow() { - Flow flow = openflowProvider.createEgressClassifierFilterNshFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchEmpty(flow.getMatch()); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionGotoTable(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE); - } - - @Test - public void createEgressClassifierFilterNoNshFlow() { - Flow flow = openflowProvider.createEgressClassifierFilterNoNshFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_COOKIE); - - checkMatchReg(flow.getMatch(), NxmNxReg2.class, 0); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionResubmit(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.EGRESS_LPORT_DISPATCHER_TABLE); - } - - @Test - public void createEgressClassifierNextHopFlow() { - Flow flow = openflowProvider.createEgressClassifierNextHopFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.EGRESS_CLASSIFIER_NEXTHOP_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.EGRESS_CLASSIFIER_NEXTHOP_COOKIE); - - checkMatchEmpty(flow.getMatch()); - - assertEquals(2, flow.getInstructions().getInstruction().size()); - Instruction curInstruction = flow.getInstructions().getInstruction().get(0).getInstruction(); - List actionList = checkApplyActionSize(curInstruction, 8); - - checkActionEncap(actionList.get(0), OpenFlow13Utils.PACKET_TYPE_NSH); - checkActionMoveReg(actionList.get(1), NxmNxReg2.class, 8,31, true); - checkActionMoveNsp(actionList.get(1), false); - checkActionMoveReg(actionList.get(2), NxmNxReg2.class, 0,7, true); - checkActionMoveNsi(actionList.get(2), false); - checkActionLoadReg(actionList.get(3), NxmNxReg2.class, 0 , 31, 0); - checkActionMoveReg(actionList.get(4), NxmNxReg0.class, 0, 31, true); - checkActionMoveNsc1(actionList.get(4), false); - checkActionMoveTunId(actionList.get(5), true); - checkActionMoveNsc2(actionList.get(5), false); - checkActionMoveReg(actionList.get(6), NxmNxReg6.class, 0, 31, true); - checkActionMoveNsc4(actionList.get(6), false); - checkActionLoadTunId(actionList.get(7), OpenFlow13Provider.SFC_TUNNEL_ID); - - curInstruction = flow.getInstructions().getInstruction().get(1).getInstruction(); - checkActionGotoTable(curInstruction, NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE); - } - - @Test - public void createEgressClassifierTransportEgressLocalFlow() { - Flow flow = openflowProvider.createEgressClassifierTransportEgressLocalFlow(nodeId, NSP); - - assertEquals(flow.getTableId().shortValue(), NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.EGRESS_CLASSIFIER_EGRESS_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + NSP); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - checkMatchNsp(flow.getMatch(), NSP); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionResubmit(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.SFC_TRANSPORT_INGRESS_TABLE); - } - - @Test - public void createEgressClassifierTransportEgressRemoteNshFlow() { - Flow flow = openflowProvider.createEgressClassifierTransportEgressRemoteNshFlow( - nodeId, NSP, OUT_PORT, SFF_IP_STR); - - assertEquals(flow.getTableId().shortValue(), NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.EGRESS_CLASSIFIER_EGRESS_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + NSP); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - checkMatchNsp(flow.getMatch(), NSP); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - List actionList = checkApplyActionSize( - flow.getInstructions().getInstruction().get(0).getInstruction(), 2); - - checkActionLoadTunIpv4(actionList.get(0), SFF_IP_STR); - checkActionOutport(actionList.get(1), "output:" + OUT_PORT); - } - - @Test - public void createEgressClassifierTransportEgressRemoteEthNshFlow() { - Flow flow = openflowProvider.createEgressClassifierTransportEgressRemoteEthNshFlow( - nodeId, NSP, OUT_PORT, SFF_IP_STR); - - assertEquals(flow.getTableId().shortValue(), NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE); - assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.EGRESS_CLASSIFIER_EGRESS_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + NSP); - assertEquals(flow.getCookie().getValue().toJava(), OpenFlow13Provider.EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - checkMatchNsp(flow.getMatch(), NSP); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - List actionList = checkApplyActionSize( - flow.getInstructions().getInstruction().get(0).getInstruction(), 3); - - checkActionEncap(actionList.get(0), OpenFlow13Utils.PACKET_TYPE_ETH); - checkActionLoadTunIpv4(actionList.get(1), SFF_IP_STR); - checkActionOutport(actionList.get(2), "output:" + OUT_PORT); - } - - @Test - public void createIngressClassifierTunnelEthNshTrafficCaptureFlow() { - Flow flow = openflowProvider.createIngressClassifierTunnelEthNshTrafficCaptureFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INTERNAL_TUNNEL_TABLE); - assertEquals(flow.getPriority().intValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), - OpenFlow13Provider.INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE); - - checkMatchEthNsh(flow.getMatch()); - checkMatchTunId(flow.getMatch(), OpenFlow13Provider.SFC_TUNNEL_ID); - - assertEquals(2, flow.getInstructions().getInstruction().size()); - List actionList = checkApplyActionSize( - flow.getInstructions().getInstruction().get(0).getInstruction(), 1); - checkActionDecap(actionList.get(0)); - checkActionGotoTable(flow.getInstructions().getInstruction().get(1).getInstruction(), - NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - } - - @Test - public void createIngressClassifierTunnelNshTrafficCaptureFlow() { - Flow flow = openflowProvider.createIngressClassifierTunnelNshTrafficCaptureFlow(nodeId); - - assertEquals(flow.getTableId().shortValue(), NwConstants.INTERNAL_TUNNEL_TABLE); - assertEquals(flow.getPriority().intValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY); - assertEquals(flow.getId().getValue(), - OpenFlow13Provider.INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME + nodeId.getValue()); - assertEquals(flow.getCookie().getValue().toJava(), - OpenFlow13Provider.INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE); - - checkMatchPacketType(flow.getMatch(), OpenFlow13Utils.PACKET_TYPE_NSH); - checkMatchTunId(flow.getMatch(), OpenFlow13Provider.SFC_TUNNEL_ID); - - assertEquals(1, flow.getInstructions().getInstruction().size()); - checkActionGotoTable(flow.getInstructions().getInstruction().get(0).getInstruction(), - NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE); - } - - // - // Internal util methods to check Flow Matches - // - - private void checkMatchEmpty(Match match) { - assertNull(match.getPacketTypeMatch()); - assertNull(match.getEthernetMatch()); - assertNull(match.getIpMatch()); - assertNull(match.getLayer3Match()); - assertNull(match.getLayer4Match()); - assertNull(match.augmentation(GeneralAugMatchNodesNodeTableFlow.class)); - } - - private void checkMatchPacketType(Match match, long packetType) { - assertEquals(packetType, match.getPacketTypeMatch().getPacketType().longValue()); - } - - private void checkMatchTunId(Match match, long value) { - GeneralAugMatchNodesNodeTableFlow genAug = - match.augmentation(GeneralAugMatchNodesNodeTableFlow.class); - - assertNotNull(genAug); - - List extensions = genAug.getExtensionList(); - for (ExtensionList extensionList : extensions) { - Extension extension = extensionList.getExtension(); - NxAugMatchNodesNodeTableFlow nxAugMatch = extension.augmentation(NxAugMatchNodesNodeTableFlow.class); - - if (nxAugMatch.getNxmNxTunId() != null) { - assertEquals(nxAugMatch.getNxmNxTunId().getValue().longValue(), value); - } - } - } - - private void checkMatchTunDstIp(Match match, Ipv4Address value) { - GeneralAugMatchNodesNodeTableFlow genAug = - match.augmentation(GeneralAugMatchNodesNodeTableFlow.class); - - assertNotNull(genAug); - - List extensions = genAug.getExtensionList(); - for (ExtensionList extensionList : extensions) { - Extension extension = extensionList.getExtension(); - NxAugMatchNodesNodeTableFlow nxAugMatch = extension.augmentation(NxAugMatchNodesNodeTableFlow.class); - - if (nxAugMatch.getNxmNxTunIpv4Dst() != null) { - assertEquals(nxAugMatch.getNxmNxTunIpv4Dst().getIpv4Address(), value); - } - } - } - - private void checkMatchEthNsh(Match match) { - assertEquals(match.getEthernetMatch().getEthernetType().getType().getValue().longValue(), - OpenFlow13Utils.ETHERTYPE_NSH); - } - - private void checkMatchInport(Match match, String inportStr) { - assertEquals(inportStr, match.getInPort().getValue()); - } - - private void checkMatchNsp(Match match, long nsp) { - GeneralAugMatchNodesNodeTableFlow genAug = - match.augmentation(GeneralAugMatchNodesNodeTableFlow.class); - - assertNotNull(genAug); - - List extensions = genAug.getExtensionList(); - for (ExtensionList extensionList : extensions) { - Extension extension = extensionList.getExtension(); - NxAugMatchNodesNodeTableFlow nxAugMatch = extension.augmentation(NxAugMatchNodesNodeTableFlow.class); - - if (nxAugMatch.getNxmNxNsp() != null) { - assertEquals(nxAugMatch.getNxmNxNsp().getValue().longValue(), nsp); - } - } - } - - private void checkMatchNsi(Match match, short nsi) { - GeneralAugMatchNodesNodeTableFlow genAug = - match.augmentation(GeneralAugMatchNodesNodeTableFlow.class); - - assertNotNull(genAug); - - List extensions = genAug.getExtensionList(); - for (ExtensionList extensionList : extensions) { - Extension extension = extensionList.getExtension(); - NxAugMatchNodesNodeTableFlow nxAugMatch = extension.augmentation(NxAugMatchNodesNodeTableFlow.class); - - if (nxAugMatch.getNxmNxNsi() != null) { - assertEquals(nxAugMatch.getNxmNxNsi().getNsi().shortValue(), nsi); - } - } - } - - private void checkMatchReg(Match match, Class reg, long value) { - GeneralAugMatchNodesNodeTableFlow genAug = - match.augmentation(GeneralAugMatchNodesNodeTableFlow.class); - - assertNotNull(genAug); - - List extensions = genAug.getExtensionList(); - for (ExtensionList extensionList : extensions) { - Extension extension = extensionList.getExtension(); - NxAugMatchNodesNodeTableFlow nxAugMatch = extension.augmentation(NxAugMatchNodesNodeTableFlow.class); - - if (nxAugMatch.getNxmNxReg() != null) { - assertEquals(nxAugMatch.getNxmNxReg().getReg(), reg); - assertEquals(nxAugMatch.getNxmNxReg().getValue().longValue(), value); - assertNull(nxAugMatch.getNxmNxReg().getMask()); - } - } - } - - // - // Internal util methods to check Flow Actions - // - - private void checkActionResubmit(Instruction curInstruction, short nextTableId) { - assertTrue(curInstruction instanceof ApplyActionsCase); - boolean resubmitActionFound = false; - for (Action action : ((ApplyActionsCase) curInstruction).getApplyActions().getAction()) { - if (action.getAction() instanceof NxActionResubmitNodesNodeTableFlowWriteActionsCase) { - NxActionResubmitNodesNodeTableFlowWriteActionsCase resubmitAction = - (NxActionResubmitNodesNodeTableFlowWriteActionsCase) action.getAction(); - assertEquals(resubmitAction.getNxResubmit().getTable().shortValue(), nextTableId); - resubmitActionFound = true; - } - } - - assertTrue(resubmitActionFound); - } - - private void checkActionGotoTable(Instruction curInstruction, short nextTableId) { - if (curInstruction instanceof GoToTableCase) { - GoToTableCase goToTablecase = (GoToTableCase) curInstruction; - assertEquals(goToTablecase.getGoToTable().getTableId().shortValue(), nextTableId); - } else { - fail(); - } - } - - private List checkApplyActionSize(Instruction curInstruction, int numActions) { - assertTrue(curInstruction instanceof ApplyActionsCase); - ApplyActionsCase action = (ApplyActionsCase) curInstruction; - assertEquals(numActions, action.getApplyActions().getAction().size()); - - return action.getApplyActions().getAction(); - } - - private void checkActionLoadTunIpv4(Action action, String ip) { - long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(ip)) & 0xffffffffL; - NxActionRegLoadNodesNodeTableFlowApplyActionsCase regLoad = - (NxActionRegLoadNodesNodeTableFlowApplyActionsCase) action.getAction(); - DstNxTunIpv4DstCase tunDstTypeCase = (DstNxTunIpv4DstCase) regLoad.getNxRegLoad().getDst().getDstChoice(); - assertEquals(Empty.getInstance(), tunDstTypeCase.getNxTunIpv4Dst()); - assertEquals(regLoad.getNxRegLoad().getValue().longValue(), ipl); - } - - private void checkActionLoadTunId(Action action, long tunId) { - NxActionRegLoadNodesNodeTableFlowApplyActionsCase regLoad = - (NxActionRegLoadNodesNodeTableFlowApplyActionsCase) action.getAction(); - DstNxTunIdCase mdTypeCase = (DstNxTunIdCase) regLoad.getNxRegLoad().getDst().getDstChoice(); - assertEquals(Empty.getInstance(), mdTypeCase.getNxTunId()); - assertEquals(regLoad.getNxRegLoad().getValue().longValue(), tunId); - } - - private void checkActionOutport(Action action, String outport) { - OutputActionCase output = (OutputActionCase) action.getAction(); - assertEquals(output.getOutputAction().getOutputNodeConnector().getValue(), outport); - } - - private void checkActionMoveNsp(Action action, boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - assertEquals(Empty.getInstance(), ((SrcNxNspCase) regMove.getNxRegMove() - .getSrc().getSrcChoice()).getNxNspDst()); - } else { - assertEquals(Empty.getInstance(), ((DstNxNspCase) regMove.getNxRegMove() - .getDst().getDstChoice()).getNxNspDst()); - } - } - - private void checkActionMoveNsi(Action action, boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - assertEquals(Empty.getInstance(), ((SrcNxNsiCase) regMove.getNxRegMove() - .getSrc().getSrcChoice()).getNxNsiDst()); - } else { - assertEquals(Empty.getInstance(), ((DstNxNsiCase) regMove.getNxRegMove() - .getDst().getDstChoice()).getNxNsiDst()); - } - } - - private void checkActionMoveNsc1(Action action, boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - SrcNxNshc1Case src = (SrcNxNshc1Case) regMove.getNxRegMove().getSrc().getSrcChoice(); - assertEquals(Empty.getInstance(), src.getNxNshc1Dst()); - } else { - DstNxNshc1Case dst = (DstNxNshc1Case) regMove.getNxRegMove().getDst().getDstChoice(); - assertEquals(Empty.getInstance(), dst.getNxNshc1Dst()); - } - } - - private void checkActionMoveNsc2(Action action, boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - SrcNxNshc2Case src = (SrcNxNshc2Case) regMove.getNxRegMove().getSrc().getSrcChoice(); - assertEquals(Empty.getInstance(), src.getNxNshc2Dst()); - } else { - DstNxNshc2Case dst = (DstNxNshc2Case) regMove.getNxRegMove().getDst().getDstChoice(); - assertEquals(Empty.getInstance(), dst.getNxNshc2Dst()); - } - } - - private void checkActionMoveNsc4(Action action, boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - SrcNxNshc4Case src = (SrcNxNshc4Case) regMove.getNxRegMove().getSrc().getSrcChoice(); - assertEquals(Empty.getInstance(), src.getNxNshc4Dst()); - } else { - DstNxNshc4Case dst = (DstNxNshc4Case) regMove.getNxRegMove().getDst().getDstChoice(); - assertEquals(Empty.getInstance(), dst.getNxNshc4Dst()); - } - } - - private void checkActionMoveTunId(Action action, boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - SrcNxTunIdCase src = (SrcNxTunIdCase) regMove.getNxRegMove().getSrc().getSrcChoice(); - assertEquals(Empty.getInstance(), src.getNxTunId()); - } else { - DstNxTunIdCase dst = (DstNxTunIdCase) regMove.getNxRegMove().getDst().getDstChoice(); - assertEquals(Empty.getInstance(), dst.getNxTunId()); - } - } - - private void checkActionLoadReg(Action action, Class reg, - int startOffset, - int endOffset, - long value) { - NxActionRegLoadNodesNodeTableFlowApplyActionsCase regLoad = - (NxActionRegLoadNodesNodeTableFlowApplyActionsCase) action.getAction(); - assertEquals(reg, ((DstNxRegCase) regLoad.getNxRegLoad().getDst().getDstChoice()).getNxReg()); - assertEquals(startOffset, regLoad.getNxRegLoad().getDst().getStart().intValue()); - assertEquals(endOffset, regLoad.getNxRegLoad().getDst().getEnd().intValue()); - assertEquals(value, regLoad.getNxRegLoad().getValue().longValue()); - } - - private void checkActionMoveReg(Action action, Class reg, - int startOffset, - int endOffset, - boolean checkSrc) { - NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove = - (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction(); - if (checkSrc) { - assertEquals(reg, ((SrcNxRegCase) regMove.getNxRegMove().getSrc().getSrcChoice()).getNxReg()); - assertEquals(startOffset, regMove.getNxRegMove().getSrc().getStart().intValue()); - assertEquals(endOffset, regMove.getNxRegMove().getSrc().getEnd().intValue()); - } else { - assertEquals(reg, ((DstNxRegCase) regMove.getNxRegMove().getDst().getDstChoice()).getNxReg()); - assertEquals(startOffset, regMove.getNxRegMove().getDst().getStart().intValue()); - assertEquals(endOffset, regMove.getNxRegMove().getDst().getEnd().intValue()); - } - } - - private void checkActionEncap(Action action, long packetType) { - NxActionEncapNodesNodeTableFlowApplyActionsCase encap = - (NxActionEncapNodesNodeTableFlowApplyActionsCase) action.getAction(); - assertEquals(packetType, encap.getNxEncap().getPacketType().longValue()); - } - - private void checkActionDecap(Action action) { - NxActionDecapNodesNodeTableFlowApplyActionsCase decap = - (NxActionDecapNodesNodeTableFlowApplyActionsCase) action.getAction(); - assertNotNull(decap.getNxDecap()); - } - -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProviderTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProviderTest.java deleted file mode 100644 index 120136e5a2..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProviderTest.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.md.sal.binding.test.ConstantSchemaAbstractDataBrokerTest; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffDataPlaneLocatorName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHopBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarders; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocatorKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.ServiceFunctionDictionaryBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.data.plane.locator.locator.type.LogicalInterfaceBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class SfcProviderTest extends ConstantSchemaAbstractDataBrokerTest { - private static final String RSP_NAME = "RSP1"; - private static final String RSP_NAME_NOEXIST = "RSP_NOEXIST"; - private static final String SFC_NAME = "SFC1"; - private static final String SF_NAME = "SF1"; - private static final String SFF_NAME = "SFF1"; - private static final String SFF_DPL_NAME = "SFF_DPL"; - private static final String LOGICAL_IF_NAME = "eccb57ae-5a2e-467f-823e-45d7bb2a6a9a"; - private static final Long PATH_ID = Long.valueOf(1); - - private SfcProvider sfcProvider; - - @Before - public void setUp() throws Exception { - sfcProvider = new SfcProvider(getDataBroker()); - } - - @Test - public void getRenderedServicePath() { - RspName rspName = new RspName(RSP_NAME); - RenderedServicePathBuilder rspBuilder = createRsp(rspName); - storeRsp(rspName, rspBuilder.build()); - - Optional rspOptional = this.sfcProvider.getRenderedServicePath(RSP_NAME); - assertTrue(rspOptional.isPresent()); - } - - @Test - public void getRenderedServicePathNonExistantRsp() { - Optional rspOptional = this.sfcProvider.getRenderedServicePath(RSP_NAME_NOEXIST); - assertFalse(rspOptional.isPresent()); - } - - @Test - public void getRenderedServicePathFromSfc() { - // This method isnt implemented yet, so it should return empty - Optional rspOptional = this.sfcProvider.getRenderedServicePathFromSfc(SFC_NAME); - assertFalse(rspOptional.isPresent()); - } - - @Test - public void getFirstHopSfInterfaceFromRsp() { - RspName rspName = new RspName(RSP_NAME); - - // Check RSP with no hops - RenderedServicePathBuilder rspBuilder = createRsp(rspName); - Optional ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with no SF name - rspBuilder = createRsp(rspName, true, false, false, false, false, false, false, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with SF name, but no SFF name - rspBuilder = createRsp(rspName, true, true, false, false, false, false,false, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with SF name, but SFF doesnt exist - rspBuilder = createRsp(rspName, true, true, true, false, false, false,false, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with SF and SFF, but SFF has no dictionary - rspBuilder = createRsp(rspName, true, true, true, false, false, true, false, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with SF and SFF, but SFF has no dictionary entry for SF - rspBuilder = createRsp(rspName, true, true, true, true, false, true, false, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with SF, SFF name, SFF exists, but has no DPL - rspBuilder = createRsp(rspName, true, true, true, true, true, true, false, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP with Sfm SFF name, SFF exists, has DPL, but not of type LogicalInterfaceLocator - rspBuilder = createRsp(rspName, true, true, true, true, true, true, true, false); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertFalse(ifName.isPresent()); - - // Check RSP when its all created correctly - rspBuilder = createRsp(rspName, true, true, true, true, true, true, true, true); - ifName = this.sfcProvider.getFirstHopIngressInterfaceFromRsp(rspBuilder.build()); - assertTrue(ifName.isPresent()); - assertEquals(ifName.get(), LOGICAL_IF_NAME); - } - - private RenderedServicePathBuilder createRsp(RspName rspName) { - return new RenderedServicePathBuilder() - .setName(rspName) - .setServiceChainName(SfcName.getDefaultInstance(SFC_NAME)) - .setPathId(PATH_ID) - .setReversePath(false); - } - - private RenderedServicePathBuilder createRsp(RspName rspName, boolean hasHops, boolean hasSfName, - boolean hasSffName, boolean hasDict, boolean hasSfDict, - boolean createSff, boolean createSffDpl, - boolean createLogicalSfDpl) { - RenderedServicePathBuilder rspBuilder = createRsp(rspName); - SffName sffName = new SffName(SFF_NAME); - SfName sfName = new SfName(SF_NAME); - - RenderedServicePathHopBuilder rspHopBuilder = new RenderedServicePathHopBuilder(); - if (hasSfName) { - rspHopBuilder.setServiceFunctionName(sfName); - } - - if (hasSffName) { - rspHopBuilder.setServiceFunctionForwarder(sffName); - } - - if (hasHops) { - List hops = new ArrayList<>(); - hops.add(rspHopBuilder.build()); - rspBuilder.setRenderedServicePathHop(hops); - } - - ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder(); - ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder = new ServiceFunctionDictionaryBuilder(); - serviceFunctionDictionaryBuilder.setName(sfName); - - if (hasSfDict) { - SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder = new SffSfDataPlaneLocatorBuilder(); - sffSfDataPlaneLocatorBuilder.setSffDplName(new SffDataPlaneLocatorName(SFF_DPL_NAME)); - serviceFunctionDictionaryBuilder.setSffSfDataPlaneLocator(sffSfDataPlaneLocatorBuilder.build()); - } - - if (hasDict) { - sffBuilder.setServiceFunctionDictionary( - Collections.singletonList(serviceFunctionDictionaryBuilder.build())); - } - - SffDataPlaneLocatorBuilder sffDplBuilder = new SffDataPlaneLocatorBuilder(); - DataPlaneLocatorBuilder dataPlaneLocatorBuilder = new DataPlaneLocatorBuilder(); - if (createLogicalSfDpl) { - LogicalInterfaceBuilder liBuilder = new LogicalInterfaceBuilder(); - liBuilder.setInterfaceName(LOGICAL_IF_NAME); - dataPlaneLocatorBuilder.setLocatorType(liBuilder.build()); - sffDplBuilder.setDataPlaneLocator(dataPlaneLocatorBuilder.build()); - } - - if (createSffDpl) { - List sffDpls = new ArrayList<>(); - sffDplBuilder.withKey(new SffDataPlaneLocatorKey(new SffDataPlaneLocatorName(SFF_DPL_NAME))); - sffDplBuilder.setName(new SffDataPlaneLocatorName(SFF_DPL_NAME)); - sffDpls.add(sffDplBuilder.build()); - sffBuilder.setSffDataPlaneLocator(sffDpls); - } - - if (createSff) { - sffBuilder.setName(sffName); - storeSff(sffName, sffBuilder.build()); - } - - return rspBuilder; - } - - @SuppressWarnings("deprecation") - private void storeRsp(RspName rspName, RenderedServicePath rsp) { - InstanceIdentifier rspIid = InstanceIdentifier.builder(RenderedServicePaths.class) - .child(RenderedServicePath.class, new RenderedServicePathKey(rspName)).build(); - - MDSALUtil.syncWrite(getDataBroker(), LogicalDatastoreType.OPERATIONAL, rspIid, rsp); - } - - @SuppressWarnings("deprecation") - private void storeSff(SffName sffName, ServiceFunctionForwarder sff) { - InstanceIdentifier sffIid; - sffIid = InstanceIdentifier.builder(ServiceFunctionForwarders.class) - .child(ServiceFunctionForwarder.class, new ServiceFunctionForwarderKey(sffName)) - .build(); - - MDSALUtil.syncWrite(getDataBroker(), LogicalDatastoreType.CONFIGURATION, sffIid, sff); - } -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestInterfaceManager.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestInterfaceManager.java deleted file mode 100644 index b0b31bf2b0..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestInterfaceManager.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import static org.opendaylight.yangtools.testutils.mockito.MoreAnswers.realOrException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.mockito.Mockito; -import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey; -import org.opendaylight.yangtools.yang.common.Uint64; - -public abstract class TestInterfaceManager implements IInterfaceManager { - public static TestInterfaceManager newInstance() { - return Mockito.mock(TestInterfaceManager.class, realOrException()); - } - - @Override - public List getTunnelPortsOnBridge(Uint64 dpnId) { - if (GeniusProviderTestParams.DPN_ID_NO_EXIST.equals(dpnId.toJava())) { - // Unfortunately, the getTunnelPortsOnBridge() method may return null - return null; - } - - if (GeniusProviderTestParams.DPN_ID_NO_PORTS.equals(dpnId.toJava())) { - return Collections.emptyList(); - } - - OvsdbTerminationPointAugmentationBuilder tpAug = new OvsdbTerminationPointAugmentationBuilder(); - tpAug.setOfport(GeniusProviderTestParams.OF_PORT); - - if (GeniusProviderTestParams.DPN_ID_NO_VXGPE_PORTS.equals(dpnId.toJava())) { - // Tunnel Termination Point that is NOT of type VXGPE - tpAug.setInterfaceType(InterfaceTypeGre.class); - } else { - // Tunnel Termination Point that IS of type VXGPE - tpAug.setInterfaceType(InterfaceTypeVxlan.class); - } - - List opsList = new ArrayList<>(); - if (!GeniusProviderTestParams.DPN_ID_NO_OPTIONS.equals(dpnId.toJava())) { - OptionsBuilder opsBuilder = new OptionsBuilder(); - opsBuilder.withKey(new OptionsKey(GeniusProvider.OPTION_KEY_REMOTE_IP)); - opsBuilder.setValue(GeniusProvider.OPTION_VALUE_FLOW); - opsList.add(opsBuilder.build()); - } - tpAug.setOptions(opsList); - - List tpAugList = new ArrayList<>(); - tpAugList.add(tpAug.build()); - - return tpAugList; - } -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestOdlInterfaceRpcService.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestOdlInterfaceRpcService.java deleted file mode 100644 index 9672724f78..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/TestOdlInterfaceRpcService.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers; - -import static org.opendaylight.yangtools.testutils.mockito.MoreAnswers.realOrException; - -import com.google.common.util.concurrent.ListenableFuture; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import org.mockito.Mockito; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnOutputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceOutputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; - -public abstract class TestOdlInterfaceRpcService implements OdlInterfaceRpcService { - public static TestOdlInterfaceRpcService newInstance() { - return Mockito.mock(TestOdlInterfaceRpcService.class, realOrException()); - } - - @Override - public ListenableFuture> getEndpointIpForDpn(GetEndpointIpForDpnInput input) { - BigInteger dpnId = input.getDpid().toJava(); - - // if the dpnId is DPN_ID_NO_EXIST, then an empty response will be returned - GetEndpointIpForDpnOutputBuilder builder = new GetEndpointIpForDpnOutputBuilder(); - if (GeniusProviderTestParams.DPN_ID.equals(dpnId)) { - List localIpList = new ArrayList<>(); - localIpList.add(new IpAddress(new Ipv4Address(GeniusProviderTestParams.IPV4_ADDRESS_STR))); - builder.setLocalIps(localIpList); - } else if (dpnId == GeniusProviderTestParams.DPN_ID_INVALID) { - return RpcResultBuilder.failed() - .withError(ErrorType.APPLICATION, "Invalid data.").buildFuture(); - } - - return RpcResultBuilder.success(builder.build()).buildFuture(); - } - - @Override - public ListenableFuture> getDpidFromInterface( - GetDpidFromInterfaceInput input) { - String ifName = input.getIntfName(); - - // if the ifName is INTERFACE_NAME_NO_EXIST, then an empty response will be returned - GetDpidFromInterfaceOutputBuilder builder = new GetDpidFromInterfaceOutputBuilder(); - if (ifName == GeniusProviderTestParams.INTERFACE_NAME) { - builder.setDpid(GeniusProviderTestParams.DPN_ID); - } else if (ifName == GeniusProviderTestParams.INTERFACE_NAME_INVALID) { - return RpcResultBuilder.failed() - .withError(ErrorType.APPLICATION, "Invalid data.").buildFuture(); - } - - return RpcResultBuilder.success(builder.build()).buildFuture(); - } - - @Override - public ListenableFuture> - getNodeconnectorIdFromInterface(GetNodeconnectorIdFromInterfaceInput input) { - String ifName = input.getIntfName(); - - // if the ifName is INTERFACE_NAME_NO_EXIST, then an empty response will be returned - GetNodeconnectorIdFromInterfaceOutputBuilder builder = new GetNodeconnectorIdFromInterfaceOutputBuilder(); - if (ifName == GeniusProviderTestParams.INTERFACE_NAME) { - builder.setNodeconnectorId(new NodeConnectorId( - GeniusProviderTestParams.NODE_CONNECTOR_ID_PREFIX - + GeniusProviderTestParams.INTERFACE_NAME)); - } else if (ifName == GeniusProviderTestParams.INTERFACE_NAME_INVALID) { - return RpcResultBuilder.failed() - .withError(ErrorType.APPLICATION, "Invalid data.").buildFuture(); - } - - return RpcResultBuilder.success(builder.build()).buildFuture(); - } - -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntryTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntryTest.java deleted file mode 100644 index 507f109145..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntryTest.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.AceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEthBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; - -@RunWith(MockitoJUnitRunner.class) -public class ClassifierEntryTest { - - @Mock - private ClassifierEntryRenderer renderer; - - @Test - public void equalsContract() throws Exception { - new EqualsTester() - .addEqualityGroup(buildIngressEntry(), buildIngressEntry()) - .addEqualityGroup(buildNodeEntry(), buildNodeEntry()) - .addEqualityGroup(buildMatchEntry(), buildMatchEntry()) - .addEqualityGroup(buildPathEntry(), buildPathEntry()) - .addEqualityGroup(buildEgressEntry(), buildEgressEntry()) - .testEquals(); - } - - private ClassifierEntry buildIngressEntry() { - return ClassifierEntry.buildIngressEntry(new InterfaceKey("input")); - } - - private ClassifierEntry buildEgressEntry() { - return ClassifierEntry.buildEgressEntry(new InterfaceKey("output"), "127.0.0.1"); - } - - private ClassifierEntry buildNodeEntry() { - return ClassifierEntry.buildNodeEntry(new NodeId("node")); - } - - private ClassifierEntry buildPathEntry() { - return ClassifierEntry.buildPathEntry(new NodeId("node"), 100L, (short) 254, (short) 253, "127.0.0.10"); - } - - private ClassifierEntry buildMatchEntry() { - AceType aceType = new AceEthBuilder() - .setDestinationMacAddress(new MacAddress("12:34:56:78:90:AB")) - .build(); - Matches matches = new MatchesBuilder().setAceType(aceType).build(); - return ClassifierEntry.buildMatchEntry( - new NodeId("node"), - "connector", - matches, - 100L, - (short) 254); - } - - @Test - public void renderIngressEntry() throws Exception { - InterfaceKey interfaceKey = new InterfaceKey("interface"); - ClassifierEntry entry = ClassifierEntry.buildIngressEntry(interfaceKey); - entry.render(renderer); - verify(renderer).renderIngress(interfaceKey); - verifyNoMoreInteractions(renderer); - } - - @Test - public void renderEgressEntry() throws Exception { - InterfaceKey interfaceKey = new InterfaceKey("interface"); - ClassifierEntry entry = ClassifierEntry.buildEgressEntry(interfaceKey, "127.0.0.1"); - entry.render(renderer); - verify(renderer).renderEgress(interfaceKey, "127.0.0.1"); - verifyNoMoreInteractions(renderer); - } - - @Test - public void renderNodeEntry() throws Exception { - NodeId nodeId = new NodeId("node"); - ClassifierEntry entry = ClassifierEntry.buildNodeEntry(nodeId); - entry.render(renderer); - verify(renderer).renderNode(nodeId); - verifyNoMoreInteractions(renderer); - } - - @Test - public void renderPathEntry() throws Exception { - NodeId nodeId = new NodeId("node"); - Long nsp = 2L; - short nsi = (short) 254; - short nsl = (short) 252; - String firstHopIp = "127.0.0.1"; - ClassifierEntry entry = ClassifierEntry.buildPathEntry(nodeId, nsp, nsi, nsl, firstHopIp); - entry.render(renderer); - verify(renderer).renderPath(nodeId, nsp, nsi, nsl, firstHopIp); - verifyNoMoreInteractions(renderer); - } - - @Test - public void renderMatchEntry() throws Exception { - NodeId nodeId = new NodeId("node"); - String connector = "openflow:0123456789:1"; - Long nsp = 2L; - Short nsi = (short) 254; - Matches matches = new MatchesBuilder().build(); - ClassifierEntry entry = ClassifierEntry.buildMatchEntry(nodeId, connector, matches, nsp, nsi); - entry.render(renderer); - verify(renderer).renderMatch(nodeId, connector, matches, nsp, nsi); - verifyNoMoreInteractions(renderer); - } - - @Test - public void suppressIngressEntry() throws Exception { - InterfaceKey interfaceKey = new InterfaceKey("interface"); - ClassifierEntry entry = ClassifierEntry.buildIngressEntry(interfaceKey); - entry.suppress(renderer); - verify(renderer).suppressIngress(interfaceKey); - verifyNoMoreInteractions(renderer); - } - - @Test - public void suppressEgressEntry() throws Exception { - InterfaceKey interfaceKey = new InterfaceKey("interface"); - ClassifierEntry entry = ClassifierEntry.buildEgressEntry(interfaceKey, "127.0.0.1"); - entry.suppress(renderer); - verify(renderer).suppressEgress(interfaceKey, "127.0.0.1"); - verifyNoMoreInteractions(renderer); - } - - @Test - public void suppressNodeEntry() throws Exception { - NodeId nodeId = new NodeId("node"); - ClassifierEntry entry = ClassifierEntry.buildNodeEntry(nodeId); - entry.suppress(renderer); - verify(renderer).suppressNode(nodeId); - verifyNoMoreInteractions(renderer); - } - - @Test - public void suppressPathEntry() throws Exception { - NodeId nodeId = new NodeId("node"); - Long nsp = 2L; - short nsi = (short) 254; - short nsl = (short) 252; - String firstHopIp = "127.0.0.1"; - ClassifierEntry entry = ClassifierEntry.buildPathEntry(nodeId, nsp, nsi, nsl, firstHopIp); - entry.suppress(renderer); - verify(renderer).suppressPath(nodeId, nsp, nsi, nsl, firstHopIp); - verifyNoMoreInteractions(renderer); - } - - @Test - public void suppressMatchEntry() throws Exception { - NodeId nodeId = new NodeId("node"); - String connector = "openflow:0123456789:1"; - Long nsp = 2L; - Short nsi = (short) 254; - Matches matches = new MatchesBuilder().build(); - ClassifierEntry entry = ClassifierEntry.buildMatchEntry(nodeId, connector, matches, nsp, nsi); - entry.suppress(renderer); - verify(renderer).suppressMatch(nodeId, connector, matches, nsp, nsi); - verifyNoMoreInteractions(renderer); - } - -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdateTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdateTest.java deleted file mode 100644 index 38ee40d89b..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ClassifierUpdateTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.service.domain.impl; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.internal.util.collections.Sets; -import org.mockito.junit.MockitoJUnitRunner; -import org.opendaylight.netvirt.sfc.classifier.service.domain.ClassifierEntry; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer; -import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; - -@RunWith(MockitoJUnitRunner.class) -public class ClassifierUpdateTest { - - @Mock - private ClassifierEntryRenderer rendererA; - - @Mock - private ClassifierEntryRenderer rendererB; - - @Mock - private ClassifierState configurationState; - - @Mock - private ClassifierState operationalState; - - private ClassifierUpdate classifierUpdate; - - @Before - public void setup() { - classifierUpdate = new ClassifierUpdate( - configurationState, - operationalState, - Arrays.asList(rendererA, rendererB)); - } - - @Test - public void update() throws Exception { - ClassifierEntry configOnly = ClassifierEntry.buildIngressEntry(new InterfaceKey("configOnly")); - ClassifierEntry operOnly = ClassifierEntry.buildIngressEntry(new InterfaceKey("operOnly")); - ClassifierEntry configAndOper = ClassifierEntry.buildIngressEntry(new InterfaceKey("configAndOper")); - when(configurationState.getAllEntries()).thenReturn(Sets.newSet(configOnly, configAndOper)); - when(operationalState.getAllEntries()).thenReturn(Sets.newSet(configAndOper, operOnly)); - classifierUpdate.run(); - verify(rendererA).renderIngress(new InterfaceKey("configOnly")); - verify(rendererB).renderIngress(new InterfaceKey("configOnly")); - verify(rendererA).suppressIngress(new InterfaceKey("operOnly")); - verify(rendererB).suppressIngress(new InterfaceKey("operOnly")); - verifyNoMoreInteractions(rendererA); - verifyNoMoreInteractions(rendererB); - } - -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatchesTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatchesTest.java deleted file mode 100644 index d63e6bd20b..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatchesTest.java +++ /dev/null @@ -1,879 +0,0 @@ -/* - * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.utils; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.junit.Test; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.genius.mdsalutil.packet.IPProtocols; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEthBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.dst.grouping.NxmOfTcpDst; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.src.grouping.NxmOfTcpSrc; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.dst.grouping.NxmOfUdpDst; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.src.grouping.NxmOfUdpSrc; -import org.opendaylight.yangtools.yang.common.Uint32; -import org.opendaylight.yangtools.yang.common.Uint8; - -public class AclMatchesTest { - - private static final String MAC_SRC_STR = "11:22:33:44:55:66"; - private static final String MAC_DST_STR = "66:55:44:33:22:11"; - private static final String IPV4_DST_STR = "10.1.2.0/24"; - private static final String IPV4_SRC_STR = "10.1.2.3/32"; - private static final String IPV6_DST_STR = "2001:DB8:AC10:FE01::/64"; - private static final String IPV6_SRC_STR = "2001:db8:85a3:7334::/64"; - private static final int TCP_SRC_LOWER_PORT = 80; - private static final int TCP_SRC_UPPER_PORT = 82; - private static final int TCP_DST_LOWER_PORT = 800; - private static final int TCP_DST_UPPER_PORT = 800; - private static final int UDP_SRC_LOWER_PORT = 90; - private static final int UDP_SRC_UPPER_PORT = 90; - private static final int UDP_DST_LOWER_PORT = 900; - private static final int UDP_DST_UPPER_PORT = 902; - private static final short DSCP_VALUE = (short) 42; - - - @Test - public void buildEthMatchTest() { - AceEthBuilder aceEthBuilder = new AceEthBuilder(); - aceEthBuilder.setDestinationMacAddress(new MacAddress(MAC_DST_STR)); - aceEthBuilder.setSourceMacAddress(new MacAddress(MAC_SRC_STR)); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceEthBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // The ethernet match should be there with src/dst values - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetSource().getAddress().getValue(), MAC_SRC_STR); - assertEquals(ethMatch.getEthernetDestination().getAddress().getValue(), MAC_DST_STR); - - // The rest should be null - assertNull(matchBuilder.getIpMatch()); - assertNull(matchBuilder.getLayer3Match()); - assertNull(matchBuilder.getLayer4Match()); - } - } - - @Test - public void buildIpv4MatchTest() { - AceIpv4Builder aceIpv4 = new AceIpv4Builder(); - aceIpv4.setDestinationIpv4Network(new Ipv4Prefix(IPV4_DST_STR)); - aceIpv4.setSourceIpv4Network(new Ipv4Prefix(IPV4_SRC_STR)); - - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(aceIpv4.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // The layer3 match should be there with src/dst values - Ipv4Match l3 = (Ipv4Match) matchBuilder.getLayer3Match(); - assertNotNull(l3); - assertEquals(l3.getIpv4Destination().getValue().toString(), IPV4_DST_STR); - assertEquals(l3.getIpv4Source().getValue().toString(), IPV4_SRC_STR); - - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // The rest should be null - assertNull(matchBuilder.getIpMatch()); - assertNull(matchBuilder.getLayer4Match()); - } - assertEquals(1, matchBuilds.size()); - } - - @Test - public void buildIpv4SrcLwrTcpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.TCP.shortValue()); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(TCP_SRC_LOWER_PORT)); - aceIpBuilder.setSourcePortRange(srcPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set srcTcpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its TCP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.TCP.shortValue())); - - NxmOfTcpSrc tcpSrc = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfTcpSrc(); - - - if (tcpSrc != null) { - srcTcpMatches.add(tcpSrc.getPort().getValue().toJava()); - srcTcpMatches.add(tcpSrc.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(1, matchBuilds.size()); - assertEquals(2, srcTcpMatches.size()); - assertTrue(srcTcpMatches.contains(TCP_SRC_LOWER_PORT)); - assertTrue(srcTcpMatches.contains(65535)); - } - - @Test - public void buildIpv4SrcTcpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.TCP.shortValue()); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(TCP_SRC_LOWER_PORT)); - srcPortRange.setUpperPort(new PortNumber(TCP_SRC_UPPER_PORT)); - aceIpBuilder.setSourcePortRange(srcPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set srcTcpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its TCP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.TCP.shortValue())); - - NxmOfTcpSrc tcpSrc = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfTcpSrc(); - - - if (tcpSrc != null) { - srcTcpMatches.add(tcpSrc.getPort().getValue().toJava()); - srcTcpMatches.add(tcpSrc.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(2, matchBuilds.size()); - assertEquals(4, srcTcpMatches.size()); - assertTrue(srcTcpMatches.contains(TCP_SRC_LOWER_PORT)); - assertTrue(srcTcpMatches.contains(TCP_SRC_UPPER_PORT)); - assertTrue(srcTcpMatches.contains(65535)); - assertTrue(srcTcpMatches.contains(65534)); - } - - @Test - public void buildIpv4DstLwrTcpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.TCP.shortValue()); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(TCP_DST_LOWER_PORT)); - aceIpBuilder.setDestinationPortRange(dstPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set dstTcpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its TCP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.TCP.shortValue())); - - NxmOfTcpDst tcpDst = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfTcpDst(); - - if (tcpDst != null) { - dstTcpMatches.add(tcpDst.getPort().getValue().toJava()); - dstTcpMatches.add(tcpDst.getMask().toJava()); - } - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(1, matchBuilds.size()); - assertEquals(2, dstTcpMatches.size()); - assertTrue(dstTcpMatches.contains(TCP_DST_LOWER_PORT)); - assertTrue(dstTcpMatches.contains(65535)); - } - - @Test - public void buildIpv4DstTcpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.TCP.shortValue()); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(TCP_DST_LOWER_PORT)); - dstPortRange.setUpperPort(new PortNumber(TCP_DST_UPPER_PORT)); - aceIpBuilder.setDestinationPortRange(dstPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set dstTcpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its TCP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.TCP.shortValue())); - - NxmOfTcpDst tcpDst = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfTcpDst(); - - if (tcpDst != null) { - dstTcpMatches.add(tcpDst.getPort().getValue().toJava()); - dstTcpMatches.add(tcpDst.getMask().toJava()); - } - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(1, matchBuilds.size()); - assertEquals(2, dstTcpMatches.size()); - assertTrue(dstTcpMatches.contains(TCP_DST_LOWER_PORT)); - assertTrue(dstTcpMatches.contains(TCP_DST_UPPER_PORT)); - assertTrue(dstTcpMatches.contains(65535)); - } - - @Test - public void buildIpv4TcpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.TCP.shortValue()); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(TCP_SRC_LOWER_PORT)); - srcPortRange.setUpperPort(new PortNumber(TCP_SRC_UPPER_PORT)); - aceIpBuilder.setSourcePortRange(srcPortRange.build()); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(TCP_DST_LOWER_PORT)); - dstPortRange.setUpperPort(new PortNumber(TCP_DST_UPPER_PORT)); - aceIpBuilder.setDestinationPortRange(dstPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set dstTcpMatches = new HashSet<>(); - Set srcTcpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its TCP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.TCP.shortValue())); - - NxmOfTcpSrc tcpSrc = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfTcpSrc(); - - NxmOfTcpDst tcpDst = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(1) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfTcpDst(); - - if (tcpSrc != null) { - srcTcpMatches.add(tcpSrc.getPort().getValue().toJava()); - srcTcpMatches.add(tcpSrc.getMask().toJava()); - } - - if (tcpDst != null) { - dstTcpMatches.add(tcpDst.getPort().getValue().toJava()); - dstTcpMatches.add(tcpDst.getMask().toJava()); - } - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(2, matchBuilds.size()); - assertEquals(4, srcTcpMatches.size()); - assertEquals(2, dstTcpMatches.size()); - - assertTrue(srcTcpMatches.contains(TCP_SRC_LOWER_PORT)); - assertTrue(srcTcpMatches.contains(TCP_SRC_UPPER_PORT)); - assertTrue(srcTcpMatches.contains(65535)); - assertTrue(srcTcpMatches.contains(65534)); - - assertTrue(dstTcpMatches.contains(TCP_DST_LOWER_PORT)); - assertTrue(dstTcpMatches.contains(TCP_DST_UPPER_PORT)); - assertTrue(dstTcpMatches.contains(65535)); - } - - @Test - public void buildIpv4SrcLwrUdpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.UDP.shortValue()); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(UDP_SRC_LOWER_PORT)); - aceIpBuilder.setSourcePortRange(srcPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set srcUdpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its UDP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.UDP.shortValue())); - - NxmOfUdpSrc udpSrc = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfUdpSrc(); - - if (udpSrc != null) { - srcUdpMatches.add(udpSrc.getPort().getValue().toJava()); - srcUdpMatches.add(udpSrc.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(1, matchBuilds.size()); - assertEquals(2, srcUdpMatches.size()); - assertTrue(srcUdpMatches.contains(UDP_SRC_LOWER_PORT)); - assertTrue(srcUdpMatches.contains(65535)); - } - - @Test - public void buildIpv4SrcUdpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.UDP.shortValue()); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(UDP_SRC_LOWER_PORT)); - srcPortRange.setUpperPort(new PortNumber(UDP_SRC_UPPER_PORT)); - aceIpBuilder.setSourcePortRange(srcPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set srcUdpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its UDP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.UDP.shortValue())); - - NxmOfUdpSrc udpSrc = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfUdpSrc(); - - if (udpSrc != null) { - srcUdpMatches.add(udpSrc.getPort().getValue().toJava()); - srcUdpMatches.add(udpSrc.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(1, matchBuilds.size()); - assertEquals(2, srcUdpMatches.size()); - assertTrue(srcUdpMatches.contains(UDP_SRC_LOWER_PORT)); - assertTrue(srcUdpMatches.contains(UDP_SRC_UPPER_PORT)); - assertTrue(srcUdpMatches.contains(65535)); - } - - @Test - public void buildIpv4DstLwrUdpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.UDP.shortValue()); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(UDP_DST_LOWER_PORT)); - aceIpBuilder.setDestinationPortRange(dstPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set dstUdpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its UDP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.UDP.shortValue())); - - NxmOfUdpDst udpDst = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfUdpDst(); - - if (udpDst != null) { - dstUdpMatches.add(udpDst.getPort().getValue().toJava()); - dstUdpMatches.add(udpDst.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(1, matchBuilds.size()); - assertEquals(2, dstUdpMatches.size()); - assertTrue(dstUdpMatches.contains(UDP_DST_LOWER_PORT)); - assertTrue(dstUdpMatches.contains(65535)); - } - - @Test - public void buildIpv4DstUdpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.UDP.shortValue()); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(UDP_DST_LOWER_PORT)); - dstPortRange.setUpperPort(new PortNumber(UDP_DST_UPPER_PORT)); - aceIpBuilder.setDestinationPortRange(dstPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set dstUdpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its UDP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.UDP.shortValue())); - - NxmOfUdpDst udpDst = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfUdpDst(); - - if (udpDst != null) { - dstUdpMatches.add(udpDst.getPort().getValue().toJava()); - dstUdpMatches.add(udpDst.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(2, matchBuilds.size()); - assertEquals(4, dstUdpMatches.size()); - assertTrue(dstUdpMatches.contains(UDP_DST_LOWER_PORT)); - assertTrue(dstUdpMatches.contains(UDP_DST_UPPER_PORT)); - assertTrue(dstUdpMatches.contains(65534)); - assertTrue(dstUdpMatches.contains(65535)); - } - - @Test - public void buildIpv4UdpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setProtocol(IPProtocols.UDP.shortValue()); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(UDP_SRC_LOWER_PORT)); - srcPortRange.setUpperPort(new PortNumber(UDP_SRC_UPPER_PORT)); - aceIpBuilder.setSourcePortRange(srcPortRange.build()); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(UDP_DST_LOWER_PORT)); - dstPortRange.setUpperPort(new PortNumber(UDP_DST_UPPER_PORT)); - aceIpBuilder.setDestinationPortRange(dstPortRange.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - Set srcUdpMatches = new HashSet<>(); - Set dstUdpMatches = new HashSet<>(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Make sure its UDP - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpProtocol(), Uint8.valueOf(IPProtocols.UDP.shortValue())); - - NxmOfUdpSrc udpSrc = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(0) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfUdpSrc(); - - NxmOfUdpDst udpDst = matchBuilder - .augmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList().get(1) - .getExtension().augmentation(NxAugMatchNodesNodeTableFlow.class).getNxmOfUdpDst(); - - if (udpSrc != null) { - srcUdpMatches.add(udpSrc.getPort().getValue().toJava()); - srcUdpMatches.add(udpSrc.getMask().toJava()); - } - - if (udpDst != null) { - dstUdpMatches.add(udpDst.getPort().getValue().toJava()); - dstUdpMatches.add(udpDst.getMask().toJava()); - } - - // The layer3 match should be null - assertNull(matchBuilder.getLayer3Match()); - } - assertEquals(2, matchBuilds.size()); - assertEquals(2, srcUdpMatches.size()); - assertEquals(4, dstUdpMatches.size()); - - assertTrue(srcUdpMatches.contains(UDP_SRC_LOWER_PORT)); - assertTrue(srcUdpMatches.contains(UDP_SRC_UPPER_PORT)); - assertTrue(srcUdpMatches.contains(65535)); - - assertTrue(dstUdpMatches.contains(UDP_DST_LOWER_PORT)); - assertTrue(dstUdpMatches.contains(UDP_DST_UPPER_PORT)); - assertTrue(dstUdpMatches.contains(65534)); - assertTrue(dstUdpMatches.contains(65535)); - } - - @Test - public void buildIpv4DscpMatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(new AceIpv4Builder().build()); - aceIpBuilder.setDscp(new Dscp(DSCP_VALUE)); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // There should be an IPv4 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV4)); - - // Check the DSCP value - IpMatch ipMatch = matchBuilder.getIpMatch(); - assertNotNull(ipMatch); - assertEquals(ipMatch.getIpDscp().getValue(), Uint8.valueOf(DSCP_VALUE)); - - // The rest should be null - assertNull(matchBuilder.getLayer3Match()); - assertNull(matchBuilder.getLayer4Match()); - } - } - - @Test - public void buildIpv6MatchTest() { - AceIpv6Builder aceIpv6 = new AceIpv6Builder(); - aceIpv6.setDestinationIpv6Network(new Ipv6Prefix(IPV6_DST_STR)); - aceIpv6.setSourceIpv6Network(new Ipv6Prefix(IPV6_SRC_STR)); - - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(aceIpv6.build()); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - - // Create the aclMatches that is the object to be tested - AclMatches aclMatches = new AclMatches(matchesBuilder.build()); - List matchBuilds = aclMatches.buildMatch(); - - for (MatchBuilder matchBuilder : matchBuilds) { - // The layer3 match should be there with src/dst values - Ipv6Match l3 = (Ipv6Match) matchBuilder.getLayer3Match(); - assertNotNull(l3); - assertEquals(l3.getIpv6Destination().getValue().toString(), IPV6_DST_STR); - assertEquals(l3.getIpv6Source().getValue().toString(), IPV6_SRC_STR); - - // There should be an IPv6 etherType set - EthernetMatch ethMatch = matchBuilder.getEthernetMatch(); - assertNotNull(ethMatch); - assertEquals(ethMatch.getEthernetType().getType().getValue(), Uint32.valueOf(NwConstants.ETHTYPE_IPV6)); - - // The rest should be null - assertNull(matchBuilder.getIpMatch()); - assertNull(matchBuilder.getLayer4Match()); - } - } - - @Test - public void invertEthMatchTest() { - AceEthBuilder aceEthBuilder = new AceEthBuilder(); - aceEthBuilder.setDestinationMacAddress(new MacAddress(MAC_DST_STR)); - aceEthBuilder.setSourceMacAddress(new MacAddress(MAC_SRC_STR)); - AceEth aceEth = aceEthBuilder.build(); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceEth); - Matches matches = matchesBuilder.build(); - - Matches invertedMatches = AclMatches.invertMatches(matches); - - assertNotEquals(matches, invertedMatches); - - AceEth invertedAceEth = (AceEth) invertedMatches.getAceType(); - assertEquals(invertedAceEth.getDestinationMacAddress(), aceEth.getSourceMacAddress()); - assertEquals(invertedAceEth.getSourceMacAddress(), aceEth.getDestinationMacAddress()); - } - - @Test - public void invertIpv4MatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setProtocol(IPProtocols.UDP.shortValue()); - aceIpBuilder.setDscp(new Dscp(DSCP_VALUE)); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(UDP_DST_LOWER_PORT)); - dstPortRange.setUpperPort(new PortNumber(UDP_DST_UPPER_PORT)); - DestinationPortRange destinationPortRange = dstPortRange.build(); - aceIpBuilder.setDestinationPortRange(destinationPortRange); - - AceIpv4Builder aceIpv4Builder = new AceIpv4Builder(); - aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(IPV4_DST_STR)); - aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(IPV4_SRC_STR)); - AceIpv4 aceIpv4 = aceIpv4Builder.build(); - aceIpBuilder.setAceIpVersion(aceIpv4); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - AceIp aceIp = aceIpBuilder.build(); - matchesBuilder.setAceType(aceIp); - - Matches matches = matchesBuilder.build(); - - Matches invertedMatches = AclMatches.invertMatches(matches); - - assertNotEquals(matches, invertedMatches); - - AceIp invertedAceIp = (AceIp) invertedMatches.getAceType(); - assertEquals(invertedAceIp.getDscp(), aceIp.getDscp()); - assertEquals(invertedAceIp.getProtocol(), aceIp.getProtocol()); - - DestinationPortRange invertedDestinationPortRange = invertedAceIp.getDestinationPortRange(); - assertNull(invertedDestinationPortRange); - - SourcePortRange invertedSourcePortRange = invertedAceIp.getSourcePortRange(); - assertEquals(invertedSourcePortRange.getLowerPort(), destinationPortRange.getLowerPort()); - assertEquals(invertedSourcePortRange.getUpperPort(), destinationPortRange.getUpperPort()); - - AceIpv4 invertedAceIpv4 = (AceIpv4) invertedAceIp.getAceIpVersion(); - assertEquals(invertedAceIpv4.getDestinationIpv4Network(), aceIpv4.getSourceIpv4Network()); - assertEquals(invertedAceIpv4.getSourceIpv4Network(), aceIpv4.getDestinationIpv4Network()); - } - - @Test - public void invertIpv6MatchTest() { - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setProtocol(IPProtocols.TCP.shortValue()); - aceIpBuilder.setDscp(new Dscp(DSCP_VALUE)); - - SourcePortRangeBuilder srcPortRange = new SourcePortRangeBuilder(); - srcPortRange.setLowerPort(new PortNumber(TCP_SRC_LOWER_PORT)); - srcPortRange.setUpperPort(new PortNumber(TCP_SRC_UPPER_PORT)); - SourcePortRange sourcePortRange = srcPortRange.build(); - aceIpBuilder.setSourcePortRange(sourcePortRange); - - DestinationPortRangeBuilder dstPortRange = new DestinationPortRangeBuilder(); - dstPortRange.setLowerPort(new PortNumber(TCP_DST_LOWER_PORT)); - dstPortRange.setUpperPort(new PortNumber(TCP_DST_UPPER_PORT)); - DestinationPortRange destinationPortRange = dstPortRange.build(); - aceIpBuilder.setDestinationPortRange(destinationPortRange); - - AceIpv6Builder aceIpv6Builder = new AceIpv6Builder(); - aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(IPV6_DST_STR)); - aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(IPV6_SRC_STR)); - AceIpv6 aceIpv6 = aceIpv6Builder.build(); - aceIpBuilder.setAceIpVersion(aceIpv6); - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - AceIp aceIp = aceIpBuilder.build(); - matchesBuilder.setAceType(aceIp); - - Matches matches = matchesBuilder.build(); - - Matches invertedMatches = AclMatches.invertMatches(matches); - - assertNotEquals(matches, invertedMatches); - - AceIp invertedAceIp = (AceIp) invertedMatches.getAceType(); - assertEquals(invertedAceIp.getDscp(), aceIp.getDscp()); - assertEquals(invertedAceIp.getProtocol(), aceIp.getProtocol()); - - DestinationPortRange invertedDestinationPortRange = invertedAceIp.getDestinationPortRange(); - assertEquals(invertedDestinationPortRange.getLowerPort(), sourcePortRange.getLowerPort()); - assertEquals(invertedDestinationPortRange.getUpperPort(), sourcePortRange.getUpperPort()); - - SourcePortRange invertedSourcePortRange = invertedAceIp.getSourcePortRange(); - assertEquals(invertedSourcePortRange.getLowerPort(), destinationPortRange.getLowerPort()); - assertEquals(invertedSourcePortRange.getUpperPort(), destinationPortRange.getUpperPort()); - - AceIpv6 invertedAceIpv6 = (AceIpv6) invertedAceIp.getAceIpVersion(); - assertEquals(invertedAceIpv6.getDestinationIpv6Network(), aceIpv6.getSourceIpv6Network()); - assertEquals(invertedAceIpv6.getSourceIpv6Network(), aceIpv6.getDestinationIpv6Network()); - } - - @Test - public void testgetLayer4MaskForRange_SinglePort() { - Map layer4MaskForRange = AclMatches.getLayer4MaskForRange(1111, 1111); - assertEquals("port L4 mask missing", 1, layer4MaskForRange.size()); - } - - @Test - public void testgetLayer4MaskForRange_MultiplePorts() { - Map layer4MaskForRange = AclMatches.getLayer4MaskForRange(1024, 2048); - assertEquals("port L4 mask missing", 2, layer4MaskForRange.size()); - } - - @Test - public void testgetLayer4MaskForRange_IllegalPortRange_ExceedMin() { - Map layer4MaskForRange = AclMatches.getLayer4MaskForRange(0, 1); - - assertEquals("port L4 mask missing", 1, layer4MaskForRange.size()); - } - - @Test - public void testgetLayer4MaskForRange_IllegalPortRange_ExceedMax() { - Map layer4MaskForRange = AclMatches.getLayer4MaskForRange(1, 65536); - assertEquals("Illegal ports range", 0, layer4MaskForRange.size()); - } - - @Test - public void testgetLayer4MaskForRange_IllegalPortRange_MinGreaterThanMax() { - Map layer4MaskForRange = AclMatches.getLayer4MaskForRange(8192, 4096); - assertEquals("Illegal ports range", 0, layer4MaskForRange.size()); - } -} diff --git a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutorTest.java b/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutorTest.java deleted file mode 100644 index 5cfe7de299..0000000000 --- a/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/utils/LastTaskExecutorTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2017 Ericsson 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.netvirt.sfc.classifier.utils; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.atMost; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.concurrent.Executor; -import java.util.concurrent.RejectedExecutionException; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class LastTaskExecutorTest { - - @Mock - private Executor executor; - - @Mock - private Runnable runnable; - - @Captor - private ArgumentCaptor runnableArgumentCaptor; - - private LastTaskExecutor lastTaskExecutor; - - @Before - public void setup() { - lastTaskExecutor = new LastTaskExecutor(executor); - } - - @Test - public void executeTwoConsecutive() throws Exception { - lastTaskExecutor.execute(runnable); - lastTaskExecutor.execute(runnable); - verify(executor, atMost(2)).execute(runnableArgumentCaptor.capture()); - runnableArgumentCaptor.getAllValues().forEach(Runnable::run); - verify(runnable).run(); - } - - @Test - public void executeTwoInterleaved() throws Exception { - lastTaskExecutor.execute(runnable); - verify(executor).execute(runnableArgumentCaptor.capture()); - runnableArgumentCaptor.getValue().run(); - lastTaskExecutor.execute(runnable); - verify(executor,times(2)).execute(runnableArgumentCaptor.capture()); - runnableArgumentCaptor.getValue().run(); - verify(runnable, times(2)).run(); - } - - @Test(expected = NullPointerException.class) - public void executeNull() throws Exception { - lastTaskExecutor.execute(null); - } - - @Test(expected = RejectedExecutionException.class) - public void executeRejected() throws Exception { - doThrow(new RejectedExecutionException()).when(executor).execute(any()); - lastTaskExecutor.execute(runnable); - } - - @Test - public void executeAfterRejected() throws Exception { - doThrow(new RejectedExecutionException()).doNothing().when(executor).execute(any()); - try { - lastTaskExecutor.execute(runnable); - } catch (RejectedExecutionException e) { - // noop - } - lastTaskExecutor.execute(runnable); - verify(executor, times(2)).execute(any()); - } -} diff --git a/sfc/classifier/pom.xml b/sfc/classifier/pom.xml deleted file mode 100644 index f1fe957791..0000000000 --- a/sfc/classifier/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - org.opendaylight.odlparent - odlparent-lite - 6.0.1 - - - - org.opendaylight.netvirt - sfc.classifier - 0.10.0-SNAPSHOT - ODL :: netvirt :: ${project.artifactId} - pom - 4.0.0 - - - api - impl - - - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-install-plugin - - true - - - - - diff --git a/sfc/pom.xml b/sfc/pom.xml deleted file mode 100644 index 76ba0d8f7d..0000000000 --- a/sfc/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - org.opendaylight.odlparent - odlparent-lite - 6.0.1 - - - - org.opendaylight.netvirt - sfc - 0.10.0-SNAPSHOT - ODL :: netvirt :: ${project.artifactId} - pom - 4.0.0 - - - classifier - translator - - - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-install-plugin - - true - - - - - - diff --git a/sfc/translator/pom.xml b/sfc/translator/pom.xml deleted file mode 100644 index 150843bf3a..0000000000 --- a/sfc/translator/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - -4.0.0 - - - org.opendaylight.netvirt - binding-parent - 0.10.0-SNAPSHOT - ../../commons/binding-parent - - - sfc.translator - ODL :: netvirt :: ${project.artifactId} - bundle - - - 0.11.0-SNAPSHOT - - - - - org.opendaylight.infrautils - inject - ${infrautils.version} - - - org.opendaylight.mdsal.model - ietf-access-control-list - - - ${project.groupId} - sfc.classifier-api - ${project.version} - - - org.opendaylight.neutron - model - ${neutron.version} - - - org.opendaylight.sfc - sfc-model - ${sfc.version} - - - org.opendaylight.sfc - sfc-provider - ${sfc.version} - - - org.opendaylight.genius - mdsalutil-api - ${genius.version} - - - - - - - org.apache.aries.blueprint - blueprint-maven-plugin - - - - - diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/DelegatingDataTreeListener.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/DelegatingDataTreeListener.java deleted file mode 100644 index 5d40e675b1..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/DelegatingDataTreeListener.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.Collection; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; -import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Data-tree listener which delegates data processing to a {@link INeutronSfcDataProcessor}. - */ -public abstract class DelegatingDataTreeListener implements AutoCloseable, - DataTreeChangeListener, - INeutronSfcDataProcessor { - private static final Logger LOG = LoggerFactory.getLogger(DelegatingDataTreeListener.class); - private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder() - .setNameFormat("NeutronSfcListener-%d").build(); - private final ExecutorService executorService = Executors.newFixedThreadPool(1, THREAD_FACTORY); - private final INeutronSfcDataProcessor dataProcessor; - @Nullable - private ListenerRegistration> listenerRegistration; - - public DelegatingDataTreeListener(DataBroker db, DataTreeIdentifier treeId) { - this.dataProcessor = Preconditions.checkNotNull(this, "Data processor can not be null!"); - registerListener(Preconditions.checkNotNull(db, "Data broker can not be null!"), - Preconditions.checkNotNull(treeId, "Tree identifier can not be null!")); - } - - // TODO Clean up the exception handling - @SuppressWarnings("checkstyle:IllegalCatch") - private void registerListener(final DataBroker db, DataTreeIdentifier treeId) { - try { - LOG.info("Registering Data Change Listener for {}", getClass().getSimpleName()); - listenerRegistration = db.registerDataTreeChangeListener(treeId, this); - } catch (final Exception e) { - LOG.warn("{} DataChange listener registration fail!", getClass().getSimpleName(), e); - throw new IllegalStateException("DataTreeListener startup fail! System needs restart.", e); - } - } - - private void processChanges(Collection> changes) { - LOG.info("onDataTreeChanged: Received Data Tree Changed {}", changes); - for (DataTreeModification change : changes) { - final InstanceIdentifier key = change.getRootPath().getRootIdentifier(); - final DataObjectModification mod = change.getRootNode(); - LOG.info("onDataTreeChanged: Received Data Tree Changed Update of Type={} for Key={}", - mod.getModificationType(), key); - switch (mod.getModificationType()) { - case DELETE: - dataProcessor.remove(mod.getDataBefore()); - break; - case SUBTREE_MODIFIED: - dataProcessor.update(mod.getDataBefore(), mod.getDataAfter()); - break; - case WRITE: - if (mod.getDataBefore() == null) { - dataProcessor.add(mod.getDataAfter()); - } else { - dataProcessor.update(mod.getDataBefore(), mod.getDataAfter()); - } - break; - default: - throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType()); - } - } - } - - @Override - public void onDataTreeChanged(@NonNull final Collection> changes) { - Preconditions.checkNotNull(changes, "Changes may not be null!"); - executorService.execute(() -> processChanges(changes)); - } - - @Override - public void close() { - if (listenerRegistration != null) { - listenerRegistration.close(); - listenerRegistration = null; - } - executorService.shutdownNow(); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/INeutronSfcDataProcessor.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/INeutronSfcDataProcessor.java deleted file mode 100644 index 605a19fecc..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/INeutronSfcDataProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator; - -import org.opendaylight.yangtools.yang.binding.DataObject; - -/** - * Neutron SFC yang model processor. - */ -public interface INeutronSfcDataProcessor { - - /** - * Method removes DataObject which is identified by InstanceIdentifier. - * - * @param del - DataObject for removing - */ - void remove(D del); - - /** - * Method updates the original DataObject to the update DataObject. - * Both are identified by same InstanceIdentifier. - * - * @param orig - original DataObject - * @param update - changed DataObject (contain updates)*/ - void update(D orig, D update); - - /** - * Method adds the DataObject which is identified by InstanceIdentifier - * to device. - * - * @param add - new DataObject - */ - void add(D add); - -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/NeutronMdsalHelper.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/NeutronMdsalHelper.java deleted file mode 100644 index 870a7a2efc..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/NeutronMdsalHelper.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator; - -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.SfcFlowClassifiers; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.sfc.flow.classifiers.SfcFlowClassifier; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.sfc.flow.classifiers.SfcFlowClassifierKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.PortPairGroups; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.PortPairs; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroup; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroupKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPair; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPairKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility functions to read Neutron models (e.g network, subnet, port, sfc flow classifier - * port pair, port group, port chain) from md-sal data store. - */ -public class NeutronMdsalHelper { - private static final Logger LOG = LoggerFactory.getLogger(NeutronMdsalHelper.class); - private static final InstanceIdentifier FC_IID = - InstanceIdentifier.create(Neutron.class).child(SfcFlowClassifiers.class); - private static final InstanceIdentifier PORTS_IID = - InstanceIdentifier.create(Neutron.class).child(Ports.class); - private static final InstanceIdentifier PORT_PAIRS_IID = - InstanceIdentifier.create(Neutron.class).child(PortPairs.class); - private static final InstanceIdentifier PORT_PAIR_GROUPS_IID = - InstanceIdentifier.create(Neutron.class).child(PortPairGroups.class); - - private final DataBroker dataBroker; - - public NeutronMdsalHelper(DataBroker dataBroker) { - this.dataBroker = dataBroker; - } - - @Nullable - public Port getNeutronPort(Uuid portId) { - return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, getNeutronPortPath(portId)).orNull(); - } - - @Nullable - public PortPair getNeutronPortPair(Uuid portPairId) { - return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, getNeutronPortPairPath(portPairId)).orNull(); - } - - @Nullable - public PortPairGroup getNeutronPortPairGroup(Uuid portPairGroupId) { - return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, getNeutronPortPairGroupPath(portPairGroupId)).orNull(); - } - - @Nullable - public SfcFlowClassifier getNeutronFlowClassifier(Uuid flowClassifierId) { - return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, getNeutronSfcFlowClassifierPath(flowClassifierId)).orNull(); - } - - private InstanceIdentifier getNeutronPortPath(Uuid portId) { - return PORTS_IID.builder().child(Port.class, new PortKey(portId)).build(); - } - - private InstanceIdentifier getNeutronPortPairPath(Uuid portPairId) { - return PORT_PAIRS_IID.builder().child(PortPair.class, new PortPairKey(portPairId)).build(); - } - - private InstanceIdentifier getNeutronPortPairGroupPath(Uuid portPairGroupId) { - return PORT_PAIR_GROUPS_IID.builder().child(PortPairGroup.class, new PortPairGroupKey(portPairGroupId)).build(); - } - - private InstanceIdentifier getNeutronSfcFlowClassifierPath(Uuid portId) { - return FC_IID.builder().child(SfcFlowClassifier.class, new SfcFlowClassifierKey(portId)).build(); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/OpenStackSFCTranslatorProvider.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/OpenStackSFCTranslatorProvider.java deleted file mode 100644 index c97b542052..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/OpenStackSFCTranslatorProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator; - -import javax.inject.Inject; -import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.infrautils.inject.AbstractLifecycle; -import org.opendaylight.netvirt.sfc.translator.flowclassifier.NeutronFlowClassifierListener; -import org.opendaylight.netvirt.sfc.translator.portchain.NeutronPortChainListener; -import org.opendaylight.netvirt.sfc.translator.portchain.NeutronPortPairGroupListener; -import org.opendaylight.netvirt.sfc.translator.portchain.NeutronPortPairListener; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePathService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class OpenStackSFCTranslatorProvider extends AbstractLifecycle { - - private static final Logger LOG = LoggerFactory.getLogger(OpenStackSFCTranslatorProvider.class); - private final DataBroker dataBroker; - private final RenderedServicePathService rspService; - private NeutronFlowClassifierListener neutronFlowClassifierListener; - private NeutronPortPairListener neutronPortPairListener; - private NeutronPortPairGroupListener neutronPortPairGroupListener; - private NeutronPortChainListener neutronPortChainListener; - - @Inject - public OpenStackSFCTranslatorProvider(final DataBroker dataBroker, final RenderedServicePathService rspService) { - LOG.info("OpenStackSFCTranslatorProvider2 constructor"); - this.dataBroker = dataBroker; - this.rspService = rspService; - } - - @Override - protected void start() { - LOG.info("{} start", getClass().getSimpleName()); - neutronFlowClassifierListener = new NeutronFlowClassifierListener(dataBroker); - neutronPortPairListener = new NeutronPortPairListener(dataBroker); - neutronPortPairGroupListener = new NeutronPortPairGroupListener(dataBroker); - neutronPortChainListener = new NeutronPortChainListener(dataBroker, rspService); - if (this.rspService == null) { - LOG.warn("RenderedServicePath Service is not available. Translation layer might not work as expected."); - } - } - - @Override - protected void stop() { - neutronFlowClassifierListener.close(); - neutronPortPairListener.close(); - neutronPortPairGroupListener.close(); - neutronPortChainListener.close(); - LOG.info("{} close", getClass().getSimpleName()); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcMdsalHelper.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcMdsalHelper.java deleted file mode 100644 index f3b1fd0c58..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcMdsalHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator; - -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChains; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarders; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility methods to read OpenDaylight SFC models. - */ -public class SfcMdsalHelper { - private static final Logger LOG = LoggerFactory.getLogger(SfcMdsalHelper.class); - private static final InstanceIdentifier ACCESS_LIST_IID = InstanceIdentifier.create(AccessLists.class); - private static final InstanceIdentifier SF_IID = - InstanceIdentifier.create(ServiceFunctions.class); - private static final InstanceIdentifier SFF_IID = - InstanceIdentifier.create(ServiceFunctionForwarders.class); - private static final InstanceIdentifier SFC_IID = - InstanceIdentifier.create(ServiceFunctionChains.class); - private static final InstanceIdentifier SFP_IID - = InstanceIdentifier.create(ServiceFunctionPaths.class); - public static final String NETVIRT_LOGICAL_SFF_NAME = "Netvirt-Logical-SFF"; - - private final DataBroker dataBroker; - - public SfcMdsalHelper(DataBroker dataBroker) { - this.dataBroker = dataBroker; - } - - //ACL Flow Classifier data store utility methods - public void addAclFlowClassifier(Acl aclFlowClassifier) { - InstanceIdentifier aclIid = getAclPath(aclFlowClassifier.key()); - LOG.info("Write ACL FlowClassifier {} to config data store at {}",aclFlowClassifier, aclIid); - try { - SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, aclIid, - aclFlowClassifier); - } catch (TransactionCommitFailedException e) { - LOG.error("Error writing {} to {}", aclFlowClassifier, aclIid, e); - } - } - - public void updateAclFlowClassifier(Acl aclFlowClassifier) { - InstanceIdentifier aclIid = getAclPath(aclFlowClassifier.key()); - LOG.info("Update ACL FlowClassifier {} in config data store at {}",aclFlowClassifier, aclIid); - try { - SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, aclIid, - aclFlowClassifier); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to merge {}", aclIid, e); - } - } - - public void removeAclFlowClassifier(Acl aclFlowClassifier) { - InstanceIdentifier aclIid = getAclPath(aclFlowClassifier.key()); - LOG.info("Remove ACL FlowClassifier {} from config data store at {}",aclFlowClassifier, aclIid); - try { - SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, aclIid); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to delete {}", aclIid, e); - } - } - - //Service Function - @Nullable - public ServiceFunction readServiceFunction(ServiceFunctionKey sfKey) { - InstanceIdentifier sfIid = getSFPath(sfKey); - LOG.info("Read Service Function {} from config data store at {}",sfKey, sfIid); - return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, sfIid).orNull(); - } - - public void addServiceFunction(ServiceFunction sf) { - InstanceIdentifier sfIid = getSFPath(sf.key()); - LOG.info("Write Service Function {} to config data store at {}",sf, sfIid); - try { - SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, sfIid, sf); - } catch (TransactionCommitFailedException e) { - LOG.error("Error writing {} to {}", sf, sfIid, e); - } - } - - public void updateServiceFunction(ServiceFunction sf) { - InstanceIdentifier sfIid = getSFPath(sf.key()); - LOG.info("Update Service Function {} in config data store at {}",sf, sfIid); - try { - SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, sfIid, sf); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to merge {}", sfIid, e); - } - } - - public void removeServiceFunction(ServiceFunctionKey sfKey) { - InstanceIdentifier sfIid = getSFPath(sfKey); - LOG.info("Remove Service Function {} from config data store at {}",sfKey, sfIid); - try { - SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, sfIid); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to delete {}", sfIid, e); - } - } - - //Service Function Forwarder - @Nullable - public ServiceFunctionForwarder readServiceFunctionForwarder(ServiceFunctionForwarderKey sffKey) { - InstanceIdentifier sffIid = getSFFPath(sffKey); - LOG.info("Read Service Function Forwarder from config data store at {}", sffIid); - return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, sffIid).orNull(); - } - - public void addServiceFunctionForwarder(ServiceFunctionForwarder sff) { - InstanceIdentifier sffIid = getSFFPath(sff.key()); - LOG.info("Write Service Function Forwarder {} to config data store at {}",sff, sffIid); - try { - SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, sffIid, sff); - } catch (TransactionCommitFailedException e) { - LOG.error("Error writing {} to {}", sff, sffIid, e); - } - } - - public void updateServiceFunctionForwarder(ServiceFunctionForwarder sff) { - InstanceIdentifier sffIid = getSFFPath(sff.key()); - LOG.info("Update Service Function Forwarder {} to config data store at {}",sff, sffIid); - try { - SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, sffIid, sff); - } catch (TransactionCommitFailedException e) { - LOG.error("Error writing {} to {}", sff, sffIid, e); - } - } - - public void deleteServiceFunctionForwarder(ServiceFunctionForwarderKey sffKey) { - InstanceIdentifier sffIid = getSFFPath(sffKey); - LOG.info("Delete Service Function Forwarder from config data store at {}", sffIid); - try { - SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, sffIid); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to delete {}", sffIid, e); - } - } - - public void addServiceFunctionChain(ServiceFunctionChain sfc) { - InstanceIdentifier sfcIid = getSFCPath(sfc.key()); - LOG.info("Write Service Function Chain {} to config data store at {}",sfc, sfcIid); - try { - SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, sfcIid, sfc); - } catch (TransactionCommitFailedException e) { - LOG.error("Error writing {} to {}", sfc, sfcIid, e); - } - } - - public void deleteServiceFunctionChain(ServiceFunctionChainKey sfcKey) { - InstanceIdentifier sfcIid = getSFCPath(sfcKey); - LOG.info("Remove Service Function Chain {} from config data store at {}",sfcKey, sfcIid); - try { - SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, sfcIid); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to delete {}", sfcIid, e); - } - } - - public void addServiceFunctionPath(ServiceFunctionPath sfp) { - InstanceIdentifier sfpIid = getSFPPath(sfp.key()); - LOG.info("Write Service Function Path {} to config data store at {}",sfp, sfpIid); - try { - SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, sfpIid, sfp); - } catch (TransactionCommitFailedException e) { - LOG.error("Error writing {} to {}", sfp, sfpIid, e); - } - } - - public void deleteServiceFunctionPath(ServiceFunctionPathKey sfpKey) { - InstanceIdentifier sfpIid = getSFPPath(sfpKey); - LOG.info("Delete Service Function Path from config data store at {}", sfpIid); - try { - SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, sfpIid); - } catch (TransactionCommitFailedException e) { - LOG.warn("Failed to delete {}", sfpIid, e); - } - } - - private static InstanceIdentifier getAclPath(AclKey aclKey) { - return ACCESS_LIST_IID.builder().child(Acl.class, aclKey).build(); - } - - private static InstanceIdentifier getSFPath(ServiceFunctionKey key) { - return SF_IID.builder().child(ServiceFunction.class, key).build(); - } - - private static InstanceIdentifier getSFFPath(ServiceFunctionForwarderKey key) { - return SFF_IID.builder().child(ServiceFunctionForwarder.class, key).build(); - } - - private static InstanceIdentifier getSFCPath(ServiceFunctionChainKey key) { - return SFC_IID.builder().child(ServiceFunctionChain.class, key).build(); - } - - private static InstanceIdentifier getSFPPath(ServiceFunctionPathKey key) { - return SFP_IID.builder().child(ServiceFunctionPath.class, key).build(); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/FlowClassifierTranslator.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/FlowClassifierTranslator.java deleted file mode 100644 index a9b511f0c9..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/FlowClassifierTranslator.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.flowclassifier; - -import java.util.ArrayList; -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv4Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv6Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntriesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.ActionsBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NeutronPorts; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NeutronPortsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.RedirectToSfc; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.RedirectToSfcBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.sfc.flow.classifiers.SfcFlowClassifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class will convert OpenStack Flow Classifier API yang models to - * OpenDaylight ACL yang models. - */ -public final class FlowClassifierTranslator { - private static final Logger LOG = LoggerFactory.getLogger(FlowClassifierTranslator.class); - private static final Short PROTO_TCP = 6; - private static final Short PROTO_UDP = 17; - private static final String RULE = "_rule"; - - private FlowClassifierTranslator() { - - } - - public static Acl buildAcl(SfcFlowClassifier flowClassifier) { - return buildAcl(flowClassifier, null); - } - - public static Acl buildAcl(SfcFlowClassifier flowClassifier, @Nullable String sfpName) { - LOG.info("OpenStack Networking SFC pushed Flow classifier : {}", flowClassifier); - AclBuilder aclBuilder = new AclBuilder(); - AceBuilder aceBuilder = new AceBuilder(); - - ActionsBuilder actionsBuilder = new ActionsBuilder(); - RedirectToSfcBuilder redirectToSfcBuilder = new RedirectToSfcBuilder(); - NeutronPortsBuilder neutronPortsBuilder = new NeutronPortsBuilder(); - - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - DestinationPortRangeBuilder destinationPortRange = new DestinationPortRangeBuilder(); - SourcePortRangeBuilder sourcePortRangeBuilder = new SourcePortRangeBuilder(); - - if (flowClassifier.getUuid() != null) { - if (flowClassifier.getName() != null) { - aclBuilder.setAclName(flowClassifier.getUuid().getValue() + "_" + flowClassifier.getName()); - } else { - aclBuilder.setAclName(flowClassifier.getUuid().getValue()); - } - - } - if (flowClassifier.getEthertype() != null) { - IpPrefix sourceIp = null; - IpPrefix destinationIp = null; - if (flowClassifier.getSourceIpPrefix() != null) { - sourceIp = flowClassifier.getSourceIpPrefix(); - } - if (flowClassifier.getDestinationIpPrefix() != null) { - destinationIp = flowClassifier.getDestinationIpPrefix(); - } - if (flowClassifier.getEthertype() == EthertypeV4.class) { - AceIpv4Builder aceIpv4Builder = new AceIpv4Builder(); - if (sourceIp != null && sourceIp.getIpv4Prefix() != null) { - aceIpv4Builder.setSourceIpv4Network(sourceIp.getIpv4Prefix()); - } - if (destinationIp != null && destinationIp.getIpv4Prefix() != null) { - aceIpv4Builder.setDestinationIpv4Network(destinationIp.getIpv4Prefix()); - } - aceIpBuilder.setAceIpVersion(aceIpv4Builder.build()); - aclBuilder.setAclType(Ipv4Acl.class); - } - if (flowClassifier.getEthertype() == EthertypeV6.class) { - AceIpv6Builder aceIpv6Builder = new AceIpv6Builder(); - if (sourceIp != null && sourceIp.getIpv6Prefix() != null) { - aceIpv6Builder.setSourceIpv6Network(sourceIp.getIpv6Prefix()); - } - if (destinationIp != null && destinationIp.getIpv6Prefix() != null) { - aceIpv6Builder.setDestinationIpv6Network(destinationIp.getIpv6Prefix()); - } - aceIpBuilder.setAceIpVersion(aceIpv6Builder.build()); - aclBuilder.setAclType(Ipv6Acl.class); - } - } - if (flowClassifier.getProtocol() != null) { - if (flowClassifier.getProtocol() == ProtocolTcp.class) { - aceIpBuilder.setProtocol(PROTO_TCP); - } - if (flowClassifier.getProtocol() == ProtocolUdp.class) { - aceIpBuilder.setProtocol(PROTO_UDP); - } - } - if (flowClassifier.getSourcePortRangeMin() != null) { - sourcePortRangeBuilder.setLowerPort(new PortNumber(flowClassifier.getSourcePortRangeMin())); - // set source port range only if lower port is specified as it is a mandatory parameter in acl model - aceIpBuilder.setSourcePortRange(sourcePortRangeBuilder.build()); - } - if (flowClassifier.getSourcePortRangeMax() != null) { - sourcePortRangeBuilder.setUpperPort(new PortNumber(flowClassifier.getSourcePortRangeMax())); - aceIpBuilder.setSourcePortRange(sourcePortRangeBuilder.build()); - } - if (flowClassifier.getDestinationPortRangeMin() != null) { - destinationPortRange.setLowerPort(new PortNumber(flowClassifier.getDestinationPortRangeMin())); - // set destination port range only if lower port is specified as it is a mandatory parameter in acl model - aceIpBuilder.setDestinationPortRange(destinationPortRange.build()); - } - if (flowClassifier.getDestinationPortRangeMax() != null) { - destinationPortRange.setUpperPort(new PortNumber(flowClassifier.getDestinationPortRangeMax())); - aceIpBuilder.setDestinationPortRange(destinationPortRange.build()); - } - if (flowClassifier.getLogicalSourcePort() != null) { - neutronPortsBuilder.setSourcePortUuid(flowClassifier.getLogicalSourcePort().getValue()); - } - if (flowClassifier.getLogicalDestinationPort() != null) { - neutronPortsBuilder.setDestinationPortUuid(flowClassifier.getLogicalDestinationPort().getValue()); - } - - // currently not supported. -// if (flowClassifier.getL7Parameter() != null) { -// } - - MatchesBuilder matchesBuilder = new MatchesBuilder(); - matchesBuilder.setAceType(aceIpBuilder.build()); - matchesBuilder.addAugmentation(NeutronPorts.class, neutronPortsBuilder.build()); - - //Set redirect-to-rsp action if rsp name is provided - if (sfpName != null) { - redirectToSfcBuilder.setSfpName(sfpName); - actionsBuilder.addAugmentation(RedirectToSfc.class, redirectToSfcBuilder.build()); - aceBuilder.setActions(actionsBuilder.build()); - } - aceBuilder.setMatches(matchesBuilder.build()); - - //OpenStack networking-sfc don't pass action information - //with flow classifier. It need to be determined using the - //Port Chain data and then flow calssifier need to be updated - //with the actions. - - aceBuilder.setRuleName(aclBuilder.getAclName() + RULE); - aceBuilder.withKey(new AceKey(aceBuilder.getRuleName())); - - ArrayList aceList = new ArrayList<>(); - aceList.add(aceBuilder.build()); - AccessListEntriesBuilder accessListEntriesBuilder = new AccessListEntriesBuilder(); - accessListEntriesBuilder.setAce(aceList); - - aclBuilder.setAccessListEntries(accessListEntriesBuilder.build()); - aclBuilder.withKey(new AclKey(aclBuilder.getAclName(),aclBuilder.getAclType())); - - LOG.info("Translated ACL Flow classfier : {}", aclBuilder.toString()); - - return aclBuilder.build(); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/NeutronFlowClassifierListener.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/NeutronFlowClassifierListener.java deleted file mode 100644 index 40b36860c8..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/NeutronFlowClassifierListener.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.flowclassifier; - -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.netvirt.sfc.translator.DelegatingDataTreeListener; -import org.opendaylight.netvirt.sfc.translator.SfcMdsalHelper; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.SfcFlowClassifiers; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.sfc.flow.classifiers.SfcFlowClassifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * OpenDaylight Neutron Flow Classifier yang models data change listener. - */ -public class NeutronFlowClassifierListener extends DelegatingDataTreeListener { - - private static final InstanceIdentifier FLOW_CLASSIFIERS_IID = - InstanceIdentifier.create(Neutron.class).child(SfcFlowClassifiers.class).child(SfcFlowClassifier.class); - - private final SfcMdsalHelper sfcMdsalHelper; - - public NeutronFlowClassifierListener(DataBroker db) { - super(db, new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, FLOW_CLASSIFIERS_IID)); - sfcMdsalHelper = new SfcMdsalHelper(db); - - } - - /** - * Method removes Acl respective to SfcFlowClassifier which is identified by InstanceIdentifier. - * - * @param deletedSfcFlowClassifier - SfcFlowClassifier for removing - */ - @Override - public void remove(SfcFlowClassifier deletedSfcFlowClassifier) { - Acl aclFlowClassifier = FlowClassifierTranslator.buildAcl(deletedSfcFlowClassifier); - sfcMdsalHelper.removeAclFlowClassifier(aclFlowClassifier); - } - - /** - * Method updates the original SfcFlowClassifier to the update SfcFlowClassifier. - * Both are identified by same InstanceIdentifier. - * - * @param origSfcFlowClassifier - original SfcFlowClassifier - * @param updatedSfcFlowClassifier - changed SfcFlowClassifier (contain updates) - */ - @Override - public void update(SfcFlowClassifier origSfcFlowClassifier, SfcFlowClassifier updatedSfcFlowClassifier) { - - Acl aclFlowClassifier = FlowClassifierTranslator.buildAcl(updatedSfcFlowClassifier); - sfcMdsalHelper.updateAclFlowClassifier(aclFlowClassifier); - } - - /** - * Method adds the SfcFlowClassifier which is identified by InstanceIdentifier - * to device. - * - * @param sfcFlowClassifier - new SfcFlowClassifier - */ - @Override - public void add(SfcFlowClassifier sfcFlowClassifier) { - // Respective ACL classifier will be written in data store, once the chain is created. - } - -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortChainListener.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortChainListener.java deleted file mode 100644 index 03f6648e9e..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortChainListener.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.portchain; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.netvirt.sfc.translator.DelegatingDataTreeListener; -import org.opendaylight.netvirt.sfc.translator.NeutronMdsalHelper; -import org.opendaylight.netvirt.sfc.translator.SfcMdsalHelper; -import org.opendaylight.netvirt.sfc.translator.flowclassifier.FlowClassifierTranslator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePathService; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.sfc.flow.classifiers.SfcFlowClassifier; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.PortChains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.chains.PortChain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroup; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPair; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * OpenDaylight Neutron Port Chain yang models data change listener. - */ -public class NeutronPortChainListener extends DelegatingDataTreeListener { - private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChainListener.class); - - private static final InstanceIdentifier PORT_CHAIN_IID = - InstanceIdentifier.create(Neutron.class).child(PortChains.class).child(PortChain.class); - private final SfcMdsalHelper sfcMdsalHelper; - private final NeutronMdsalHelper neutronMdsalHelper; - private final RenderedServicePathService rspService; - - public NeutronPortChainListener(DataBroker db, RenderedServicePathService rspService) { - super(db,new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, PORT_CHAIN_IID)); - this.sfcMdsalHelper = new SfcMdsalHelper(db); - this.neutronMdsalHelper = new NeutronMdsalHelper(db); - this.rspService = rspService; - } - - /** - * Method removes PortChain which is identified by InstanceIdentifier. - * - * @param deletedPortChain - PortChain for removing - */ - @Override - public void remove(PortChain deletedPortChain) { - sfcMdsalHelper.deleteServiceFunctionPath(PortChainTranslator.getSFPKey(deletedPortChain)); - sfcMdsalHelper.deleteServiceFunctionChain(PortChainTranslator.getSFCKey(deletedPortChain)); - } - - /** - * Method updates the original PortChain to the update PortChain. - * Both are identified by same InstanceIdentifier. - * - * @param origPortChain - original PortChain - * @param updatePortChain - changed PortChain (contain updates) - */ - @Override - public void update(PortChain origPortChain, PortChain updatePortChain) { - List oldFcList = origPortChain.getFlowClassifiers(); - oldFcList = oldFcList != null ? new ArrayList<>(oldFcList) : new ArrayList<>(); - List newFcList = updatePortChain.getFlowClassifiers(); - if (oldFcList != null && newFcList != null) { - oldFcList.removeAll(newFcList); - if (!oldFcList.isEmpty()) { - LOG.debug("Removing old list {}", oldFcList); - processFlowClassifiers(origPortChain, oldFcList, null, false); - } - } - processPortChain(updatePortChain); - } - - /** - * Method adds the PortChain which is identified by InstanceIdentifier - * to device. - * - * @param newPortChain - new PortChain - */ - @Override - public void add(final PortChain newPortChain) { - processPortChain(newPortChain); - } - - private void processPortChain(PortChain newPortChain) { - - //List of Port Pair Group attached to the Port Chain - List portPairGroupList = new ArrayList<>(); - //Port Pair Group and associated Port Pair - Map> groupPortPairsList = new HashMap<>(); - - List portChainServiceFunctionList = new ArrayList<>(); - - //Read chain related port pair group from neutron data store - List newPortPairGroups = newPortChain.getPortPairGroups(); - if (newPortPairGroups != null) { - for (Uuid ppgUuid : newPortPairGroups) { - PortPairGroup ppg = neutronMdsalHelper.getNeutronPortPairGroup(ppgUuid); - if (ppg != null) { - List portPairList = new ArrayList<>(); - portPairGroupList.add(ppg); - @org.eclipse.jdt.annotation.Nullable List ppgPortPairs = ppg.getPortPairs(); - if (ppgPortPairs != null) { - for (Uuid ppUuid : ppgPortPairs) { - PortPair pp = neutronMdsalHelper.getNeutronPortPair(ppUuid); - if (pp == null) { - LOG.error("Port pair {} does not exist in the neutron data store", ppUuid); - return; - } - portPairList.add(pp); - } - } - groupPortPairsList.put(ppgUuid, portPairList); - } - } - } - - //For each port pair group - for (PortPairGroup ppg : portPairGroupList) { - - List portPairList = groupPortPairsList.get(ppg.getUuid()); - - //Generate all the SF and write it to SFC data store - for (PortPair portPair : portPairList) { - //Build the service function for the given port pair. - ServiceFunction serviceFunction = PortPairTranslator.buildServiceFunction(portPair, ppg); - portChainServiceFunctionList.add(serviceFunction); - - //Write the Service Function to SFC data store. - LOG.info("Add Service Function {} for Port Pair {}", serviceFunction, portPair); - sfcMdsalHelper.addServiceFunction(serviceFunction); - } - - //Build the SFF Builder from port pair group - ServiceFunctionForwarder serviceFunctionForwarder = PortPairGroupTranslator - .buildServiceFunctionForwarder(ppg, portPairList); - // Send SFF create request - LOG.info("Update Service Function Forwarder with {} for Port Pair Group {}", serviceFunctionForwarder, ppg); - sfcMdsalHelper.updateServiceFunctionForwarder(serviceFunctionForwarder); - } - - //Build Service Function Chain Builder - ServiceFunctionChain sfc = - PortChainTranslator.buildServiceFunctionChain(newPortChain, portChainServiceFunctionList); - - //Write SFC to data store - if (sfc == null) { - LOG.warn("Service Function Chain building failed for Port Chain {}", newPortChain); - return; - } - - LOG.info("Add service function chain {}", sfc); - sfcMdsalHelper.addServiceFunctionChain(sfc); - - // Build Service Function Path Builder - ServiceFunctionPath sfp = PortChainTranslator.buildServiceFunctionPath(sfc); - - // Write SFP to data store - LOG.info("Add service function path {}", sfp); - sfcMdsalHelper.addServiceFunctionPath(sfp); - - // The RSP will automatically be created from the SFP added above. - - // Add ACLs from flow classifiers - List newFlowClassifiers = newPortChain.getFlowClassifiers(); - processFlowClassifiers(newPortChain, newFlowClassifiers != null ? newFlowClassifiers : Collections.emptyList(), - sfp.getName().getValue(), true); - } - - private void processFlowClassifiers(PortChain pc, @NonNull List flowClassifiers, @Nullable String sfpName, - boolean added) { - for (Uuid uuid : flowClassifiers) { - SfcFlowClassifier fc = neutronMdsalHelper.getNeutronFlowClassifier(uuid); - if (fc != null) { - Acl acl = FlowClassifierTranslator.buildAcl(fc, sfpName); - if (acl != null) { - if (added) { - sfcMdsalHelper.addAclFlowClassifier(acl); - } else { - sfcMdsalHelper.removeAclFlowClassifier(acl); - } - } else { - LOG.warn("Acl building failed for flow classifier {}. Traffic might not be redirected to RSP", fc); - } - - } else { - LOG.error("Neutron Flow Classifier {} attached to Port Chain {} is not present in the neutron data " - + "store", uuid, pc); - } - } - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairGroupListener.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairGroupListener.java deleted file mode 100644 index 6af1d94928..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairGroupListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.portchain; - -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.netvirt.sfc.translator.DelegatingDataTreeListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.PortPairGroups; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroup; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * OpenDaylight Neutron Port Pair Group yang models data change listener. - */ -public class NeutronPortPairGroupListener extends DelegatingDataTreeListener { - private static final InstanceIdentifier PORT_PAIR_GROUP_IID = - InstanceIdentifier.create(Neutron.class).child(PortPairGroups.class).child(PortPairGroup.class); - - public NeutronPortPairGroupListener(DataBroker db) { - super(db,new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, PORT_PAIR_GROUP_IID)); - } - - /** - * Method removes PortPairGroup which is identified by InstanceIdentifier. - * - * @param deletedPortPairGroup - PortPairGroup for removing - */ - @Override - public void remove(PortPairGroup deletedPortPairGroup) { - //NO-OP - } - - /** - * Method updates the original PortPairGroup to the update PortPairGroup. - * Both are identified by same InstanceIdentifier. - * - * @param origPortPairGroup - original PortPairGroup - * @param updatePortPairGroup - changed PortPairGroup (contain updates) - */ - @Override - public void update(PortPairGroup origPortPairGroup, PortPairGroup updatePortPairGroup) { - //NO-OP - } - - /** - * Method adds the PortPairGroup which is identified by InstanceIdentifier - * to device. - * - * @param newPortPairGroup - new PortPairGroup - */ - @Override - public void add(PortPairGroup newPortPairGroup) { - //NO-OP - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairListener.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairListener.java deleted file mode 100644 index f5b79a7b46..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortPairListener.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.portchain; - -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.netvirt.sfc.translator.DelegatingDataTreeListener; -import org.opendaylight.netvirt.sfc.translator.SfcMdsalHelper; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.PortPairs; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPair; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * OpenDaylight Neutron Port Pair yang models data change listener. - */ -public class NeutronPortPairListener extends DelegatingDataTreeListener { - private static final Logger LOG = LoggerFactory.getLogger(NeutronPortPairListener.class); - - private static final InstanceIdentifier PORT_PAIR_IID = - InstanceIdentifier.create(Neutron.class).child(PortPairs.class).child(PortPair.class); - - private final SfcMdsalHelper sfcMdsalHelper; - - public NeutronPortPairListener(DataBroker db) { - super(db,new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, PORT_PAIR_IID)); - sfcMdsalHelper = new SfcMdsalHelper(db); - } - - /** - * Method removes PortPair which is identified by InstanceIdentifier. - * - * @param deletedPortPair - PortPair for removing - */ - @Override - public void remove(PortPair deletedPortPair) { - LOG.info("Received remove port pair event {}", deletedPortPair); - - ServiceFunctionKey sfKey = PortPairTranslator.getSFKey(deletedPortPair); - LOG.info("Removing service function {}", sfKey); - sfcMdsalHelper.removeServiceFunction(sfKey); - - ServiceFunctionForwarder sff; - ServiceFunctionForwarder updatedSff; - SffName sffName = new SffName(SfcMdsalHelper.NETVIRT_LOGICAL_SFF_NAME); - sff = sfcMdsalHelper.readServiceFunctionForwarder(new ServiceFunctionForwarderKey(sffName)); - updatedSff = PortPairGroupTranslator.removePortPairFromServiceFunctionForwarder(sff, deletedPortPair); - LOG.info("Updating service function forwarder as {}", updatedSff); - sfcMdsalHelper.addServiceFunctionForwarder(updatedSff); - } - - /** - * Method updates the original PortPair to the update PortPair. - * Both are identified by same InstanceIdentifier. - * - * @param origPortPair - original PortPair - * @param updatePortPair - changed PortPair (contain updates) - */ - @Override - public void update(PortPair origPortPair, PortPair updatePortPair) { - //NO-OP - } - - /** - * Method adds the PortPair which is identified by InstanceIdentifier - * to device. - * - * @param newPortPair - new PortPair - */ - @Override - public void add(PortPair newPortPair) { - //NO-OP - // Port Pair data written in neutron data store will be used - // When user will create port chain. - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortChainTranslator.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortChainTranslator.java deleted file mode 100644 index 1b9e19e03f..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortChainTranslator.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.portchain; - -import com.google.common.base.Preconditions; -import java.util.ArrayList; -import java.util.List; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfpName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunction; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunctionBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunctionKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.port.chain.attributes.ChainParameters; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.chains.PortChain; - -/** - * Class will convert OpenStack Port Chain API yang models present in neutron northbound project to OpenDaylight SFC - * yang models. - */ -public final class PortChainTranslator { - - private static final String SYMMETRIC_PARAM = "symmetric"; - private static final String SFP_NAME_PREFIX = "Path-"; - - private PortChainTranslator() { - } - - public static ServiceFunctionChain buildServiceFunctionChain( - PortChain portChain, List sfList) { - ServiceFunctionChainBuilder sfcBuilder = new ServiceFunctionChainBuilder(); - sfcBuilder.setName(new SfcName(portChain.getName())); - sfcBuilder.withKey(new ServiceFunctionChainKey(sfcBuilder.getName())); - - //By default set it to false. If user specify it in chain parameters, it will be overridden - sfcBuilder.setSymmetric(false); - - //Set service functions - List sfcSfList = new ArrayList<>(); - for (ServiceFunction sf : sfList) { - SfcServiceFunctionBuilder sfcSfBuilder = new SfcServiceFunctionBuilder(); - sfcSfBuilder.setName(sf.getName().getValue()); - sfcSfBuilder.setType(sf.getType()); - sfcSfBuilder.withKey(new SfcServiceFunctionKey(sfcSfBuilder.getName())); - - //NOTE: no explicit order is set. - sfcSfList.add(sfcSfBuilder.build()); - } - List cpList = portChain.getChainParameters(); - if (cpList != null && !cpList.isEmpty()) { - for (ChainParameters cp : cpList) { - if (SYMMETRIC_PARAM.equals(cp.getChainParameter())) { - //Override the symmetric default value. - sfcBuilder.setSymmetric(Boolean.valueOf(cp.getChainParameterValue())); - break; - } - } - } - sfcBuilder.setSfcServiceFunction(sfcSfList); - return sfcBuilder.build(); - } - - public static ServiceFunctionPath buildServiceFunctionPath(ServiceFunctionChain sfc) { - Preconditions.checkNotNull(sfc, "Service Function Chain must not be null"); - ServiceFunctionPathBuilder sfpBuilder = new ServiceFunctionPathBuilder(); - - //Set the name - sfpBuilder.setName(new SfpName(SFP_NAME_PREFIX + sfc.getName().getValue())); - - sfpBuilder.setSymmetric(sfc.isSymmetric()); - //Set related SFC name - sfpBuilder.setServiceChainName(sfc.getName()); - return sfpBuilder.build(); - } - - public static ServiceFunctionChainKey getSFCKey(PortChain portChain) { - return new ServiceFunctionChainKey(new SfcName(portChain.getName())); - } - - public static ServiceFunctionPathKey getSFPKey(PortChain portChain) { - return new ServiceFunctionPathKey(new SfpName(SFP_NAME_PREFIX + portChain.getName())); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairGroupTranslator.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairGroupTranslator.java deleted file mode 100644 index c570c60213..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairGroupTranslator.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.portchain; - -import com.google.common.base.Preconditions; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.opendaylight.netvirt.sfc.translator.SfcMdsalHelper; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfDataPlaneLocatorName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffDataPlaneLocatorName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.ServiceFunctionDictionary; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.ServiceFunctionDictionaryBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Mac; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.data.plane.locator.locator.type.LogicalInterface; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.data.plane.locator.locator.type.LogicalInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroup; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class will convert OpenStack Port Pair API yang models present in - * neutron northbound project to OpenDaylight SFC yang models. - */ -public final class PortPairGroupTranslator { - private static final Logger LOG = LoggerFactory.getLogger(PortPairGroupTranslator.class); - - private static final String DPL_EGRESS_SUFFIX = "-egress"; - private static final String DPL_INGRESS_SUFFIX = "-ingress"; - - private PortPairGroupTranslator() { - - } - - public static ServiceFunctionForwarder buildServiceFunctionForwarder( - PortPairGroup portPairGroup, - List portPairs) { - Preconditions.checkNotNull(portPairGroup, "Port pair group must not be null"); - Preconditions.checkNotNull(portPairs, "Port pairs must not be null"); - Preconditions.checkElementIndex(0, portPairs.size(), "There must be at least one port pair"); - - //Currently we only support one SF per type. Mean, one port-pair per port-pair-group. - final PortPair portPair = portPairs.get(0); - - ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder(); - sffBuilder.setName(new SffName(SfcMdsalHelper.NETVIRT_LOGICAL_SFF_NAME)); - - DataPlaneLocatorBuilder forwardDplBuilder = new DataPlaneLocatorBuilder(); - forwardDplBuilder.setTransport(Mac.class); - String forwardPort = portPair.getIngress().getValue(); - LogicalInterface forwardInterface = new LogicalInterfaceBuilder().setInterfaceName(forwardPort).build(); - forwardDplBuilder.setLocatorType(forwardInterface); - SffDataPlaneLocatorBuilder sffForwardDplBuilder = new SffDataPlaneLocatorBuilder(); - sffForwardDplBuilder.setDataPlaneLocator(forwardDplBuilder.build()); - String forwardDplName = portPair.getName() + DPL_INGRESS_SUFFIX; - sffForwardDplBuilder.setName(new SffDataPlaneLocatorName(forwardDplName)); - - DataPlaneLocatorBuilder reverseDplBuilder = new DataPlaneLocatorBuilder(); - reverseDplBuilder.setTransport(Mac.class); - String reversePort = portPair.getEgress().getValue(); - LogicalInterface reverseInterface = new LogicalInterfaceBuilder().setInterfaceName(reversePort).build(); - reverseDplBuilder.setLocatorType(reverseInterface); - SffDataPlaneLocatorBuilder sffReverseDplBuilder = new SffDataPlaneLocatorBuilder(); - sffReverseDplBuilder.setDataPlaneLocator(reverseDplBuilder.build()); - String reverseDplName = portPair.getName() + DPL_EGRESS_SUFFIX; - sffReverseDplBuilder.setName(new SffDataPlaneLocatorName(reverseDplName)); - - List sffDataPlaneLocator = new ArrayList<>(); - sffDataPlaneLocator.add(sffForwardDplBuilder.build()); - sffDataPlaneLocator.add(sffReverseDplBuilder.build()); - sffBuilder.setSffDataPlaneLocator(sffDataPlaneLocator); - - SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder = new SffSfDataPlaneLocatorBuilder(); - sffSfDataPlaneLocatorBuilder.setSffForwardDplName(new SffDataPlaneLocatorName(forwardDplName)); - sffSfDataPlaneLocatorBuilder.setSfForwardDplName(new SfDataPlaneLocatorName(forwardDplName)); - sffSfDataPlaneLocatorBuilder.setSffReverseDplName(new SffDataPlaneLocatorName(reverseDplName)); - sffSfDataPlaneLocatorBuilder.setSfReverseDplName(new SfDataPlaneLocatorName(reverseDplName)); - ServiceFunctionDictionaryBuilder sfdBuilder = new ServiceFunctionDictionaryBuilder(); - sfdBuilder.setName(new SfName(portPair.getName())); - sfdBuilder.setSffSfDataPlaneLocator(sffSfDataPlaneLocatorBuilder.build()); - - List sfdList = new ArrayList<>(); - sfdList.add(sfdBuilder.build()); - sffBuilder.setServiceFunctionDictionary(sfdList); - - return sffBuilder.build(); - } - - public static ServiceFunctionForwarder removePortPairFromServiceFunctionForwarder( - ServiceFunctionForwarder serviceFunctionForwarder, - PortPair deletedPortPair) { - Preconditions.checkNotNull(deletedPortPair, "Port pair must not be null"); - - String portPairName = deletedPortPair.getName(); - ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder(serviceFunctionForwarder); - - List serviceFunctionDictionaryList = sffBuilder.getServiceFunctionDictionary(); - if (serviceFunctionDictionaryList == null) { - LOG.debug("SF dictionary is empty"); - return serviceFunctionForwarder; - } - - ServiceFunctionDictionary serviceFunctionDictionary = serviceFunctionDictionaryList.stream() - .filter(sfDictionary -> sfDictionary.getName().getValue().equals(portPairName)) - .findFirst() - .orElse(null); - - if (serviceFunctionDictionary == null) { - LOG.debug("SFF dictionary entry for port pair {} not found", portPairName); - return serviceFunctionForwarder; - } - - SffSfDataPlaneLocator sffSfDataPlaneLocator = serviceFunctionDictionary.getSffSfDataPlaneLocator(); - if (sffSfDataPlaneLocator != null) { - List locators = Arrays.asList( - sffSfDataPlaneLocator.getSffDplName(), - sffSfDataPlaneLocator.getSffForwardDplName(), - sffSfDataPlaneLocator.getSffReverseDplName()); - List sffDplList = sffBuilder.getSffDataPlaneLocator(); - if (sffDplList != null) { - sffDplList.stream() - .filter(sffDataPlaneLocator -> locators.contains(sffDataPlaneLocator.getName())) - .map(sffDplList::remove); - } - } - serviceFunctionDictionaryList.remove(serviceFunctionDictionary); - - return sffBuilder.build(); - } -} diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairTranslator.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairTranslator.java deleted file mode 100644 index b65495ae48..0000000000 --- a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortPairTranslator.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2016, 2017 Brocade Communications 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.netvirt.sfc.translator.portchain; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableBiMap; -import java.util.ArrayList; -import java.util.List; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.netvirt.sfc.translator.SfcMdsalHelper; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfDataPlaneLocatorName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SftTypeName; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.TenantId; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocator; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocatorBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionBuilder; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Mac; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.SlTransportType; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.functions.service.function.sf.data.plane.locator.locator.type.LogicalInterface; -import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.functions.service.function.sf.data.plane.locator.locator.type.LogicalInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.port.pair.attributes.ServiceFunctionParameters; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroup; -import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPair; - -/** - * Class will convert OpenStack Port Pair API yang models present in - * neutron northbound project to OpenDaylight SFC Service Function yang models. - */ -public final class PortPairTranslator { - private static final String SF_TYPE_PARAM = "type"; - private static final String DPL_TRANSPORT_PARAM = "dpl-transport"; - private static final String DPL_EGRESS_SUFFIX = "-egress"; - private static final String DPL_INGRESS_SUFFIX = "-ingress"; - - public static final ImmutableBiMap> DPL_TRANSPORT_TYPE - = new ImmutableBiMap.Builder>() - .put("mac", Mac.class).build(); - - private PortPairTranslator() { - - } - - @NonNull - public static ServiceFunction buildServiceFunction( - PortPair portPair, - PortPairGroup portPairGroup) { - Preconditions.checkNotNull(portPair, "Port pair must not be null"); - Preconditions.checkNotNull(portPairGroup, "Port pair group must not be null"); - - ServiceFunctionBuilder serviceFunctionBuilder = new ServiceFunctionBuilder(); - - //Set SF name and tenant-id - serviceFunctionBuilder.setName(new SfName(portPair.getName())); - serviceFunctionBuilder.setTenantId(new TenantId(portPair.getTenantId().getValue())); - - //Set SF Type. Setting it to PortPairGroup Type, this will be overridden if user pass - //it through service_function_params - serviceFunctionBuilder.setType(SftTypeName.getDefaultInstance(portPairGroup.getName())); - - //If user pass specific param using service_function_parameters, set/override it accordingly - Class transportTypeClass = null; - List sfParams = portPair.getServiceFunctionParameters(); - if (sfParams != null) { - for (ServiceFunctionParameters sfParam : sfParams) { - //There is by default type set to port pair group name, override it if user pass it specific type - if (sfParam.getServiceFunctionParameter().equals(SF_TYPE_PARAM)) { - serviceFunctionBuilder.setType(new SftTypeName(sfParam.getServiceFunctionParameterValue())); - } - if (sfParam.getServiceFunctionParameter().equals(DPL_TRANSPORT_PARAM)) { - transportTypeClass = DPL_TRANSPORT_TYPE.get(sfParam.getServiceFunctionParameterValue()); - } - } - } - - //Build forward DPL - SfDataPlaneLocatorBuilder sfForwardDplBuilder = new SfDataPlaneLocatorBuilder(); - sfForwardDplBuilder.setName(new SfDataPlaneLocatorName(portPair.getName() + DPL_INGRESS_SUFFIX)); - sfForwardDplBuilder.setTransport(transportTypeClass == null ? Mac.class : transportTypeClass); - sfForwardDplBuilder.setServiceFunctionForwarder(new SffName(SfcMdsalHelper.NETVIRT_LOGICAL_SFF_NAME)); - String forwardPort = portPair.getIngress().getValue(); - LogicalInterface forwardInterface = new LogicalInterfaceBuilder().setInterfaceName(forwardPort).build(); - sfForwardDplBuilder.setLocatorType(forwardInterface); - - //Build reverse DPL - SfDataPlaneLocatorBuilder sfReverseDplBuilder = new SfDataPlaneLocatorBuilder(); - sfReverseDplBuilder.setName(new SfDataPlaneLocatorName(portPair.getName() + DPL_EGRESS_SUFFIX)); - sfReverseDplBuilder.setTransport(transportTypeClass == null ? Mac.class : transportTypeClass); - sfReverseDplBuilder.setServiceFunctionForwarder(new SffName(SfcMdsalHelper.NETVIRT_LOGICAL_SFF_NAME)); - String reversePort = portPair.getEgress().getValue(); - LogicalInterface reverseInterface = new LogicalInterfaceBuilder().setInterfaceName(reversePort).build(); - sfReverseDplBuilder.setLocatorType(reverseInterface); - - //Set all data plane locator - List sfDataPlaneLocatorList = new ArrayList<>(); - sfDataPlaneLocatorList.add(sfForwardDplBuilder.build()); - sfDataPlaneLocatorList.add(sfReverseDplBuilder.build()); - serviceFunctionBuilder.setSfDataPlaneLocator(sfDataPlaneLocatorList); - - return serviceFunctionBuilder.build(); - } - - public static ServiceFunctionKey getSFKey(PortPair portPair) { - return new ServiceFunctionKey(new SfName(portPair.getName())); - } - - -} diff --git a/sfc/translator/src/main/resources/OSGI-INF/blueprint/sfc-translator.xml b/sfc/translator/src/main/resources/OSGI-INF/blueprint/sfc-translator.xml deleted file mode 100644 index a8e2eacac8..0000000000 --- a/sfc/translator/src/main/resources/OSGI-INF/blueprint/sfc-translator.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - -- 2.36.6