Imported vpnservice as a subtree
authorThanh Ha <thanh.ha@linuxfoundation.org>
Wed, 4 May 2016 18:11:49 +0000 (14:11 -0400)
committerThanh Ha <thanh.ha@linuxfoundation.org>
Wed, 4 May 2016 18:14:44 +0000 (14:14 -0400)
Change-Id: I31c80009a31b0b97c1d10246e844be69e81125f4

1100 files changed:
.gitignore [changed mode: 0644->0755]
.gitreview
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
README.Vagrant [new file with mode: 0644]
Vagrantfile [new file with mode: 0644]
commons/it/pom.xml [new file with mode: 0644]
commons/pom.xml [new file with mode: 0644]
docker-compose.yml [new file with mode: 0644]
features/pom.xml
features/src/main/features/features.xml
karaf/pom.xml [new file with mode: 0644]
netvirt-artifacts/pom.xml [new file with mode: 0644]
netvirt/api/pom.xml [new file with mode: 0644]
netvirt/api/src/main/yang/netvirt-common.yang [new file with mode: 0644]
netvirt/api/src/main/yang/netvirt-devices.yang [new file with mode: 0644]
netvirt/api/src/main/yang/netvirt-l2-networks.yang [new file with mode: 0644]
netvirt/api/src/main/yang/netvirt-ports.yang [new file with mode: 0644]
netvirt/api/src/main/yang/netvirt.yang [new file with mode: 0644]
netvirt/it/pom.xml [new file with mode: 0644]
netvirt/it/src/test/java/org/opendaylight/netvirt/netvirt/it/NetvirtIT.java [new file with mode: 0644]
netvirt/pom.xml [new file with mode: 0644]
netvirt/renderers/hwgw/pom.xml [new file with mode: 0644]
netvirt/renderers/hwgw/src/main/config/default-config.xml [new file with mode: 0644]
netvirt/renderers/hwgw/src/main/java/org/opendaylight/netvirt/netvirt/renderers/hwgw/HwgwProvider.java [new file with mode: 0644]
netvirt/renderers/hwgw/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModule.java [new file with mode: 0644]
netvirt/renderers/hwgw/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleFactory.java [new file with mode: 0644]
netvirt/renderers/hwgw/src/main/yang/hwgw.yang [new file with mode: 0644]
netvirt/renderers/hwgw/src/test/java/org/opendaylight/netvirt/netvirt/renderers/hwgw/HwgwProviderTest.java [new file with mode: 0644]
netvirt/renderers/hwgw/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleFactoryTest.java [new file with mode: 0644]
netvirt/renderers/hwgw/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleTest.java [new file with mode: 0644]
netvirt/renderers/neutron/pom.xml [new file with mode: 0644]
netvirt/renderers/neutron/src/main/config/default-config.xml [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/Constants.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/DataProcessor.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/DelegatingDataTreeListener.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/MdsalHelper.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronNetworkChangeListener.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronNetworkDataProcessor.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortChangeListener.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortDataProcessor.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronProvider.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModule.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleFactory.java [new file with mode: 0644]
netvirt/renderers/neutron/src/main/yang/netvirt-neutron.yang [new file with mode: 0644]
netvirt/renderers/neutron/src/test/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortDataProcessorTest.java [new file with mode: 0644]
netvirt/renderers/neutron/src/test/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronProviderTest.java [new file with mode: 0644]
netvirt/renderers/neutron/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleFactoryTest.java [new file with mode: 0644]
netvirt/renderers/neutron/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleTest.java [new file with mode: 0644]
netvirt/renderers/pom.xml [new file with mode: 0644]
openstack/net-virt-it/pom.xml [new file with mode: 0644]
openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java [new file with mode: 0644]
openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtITConstants.java [new file with mode: 0644]
openstack/net-virt-providers/pom.xml [new file with mode: 0644]
openstack/net-virt-providers/src/main/config/default-config.xml [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigActivator.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigInterface.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersConfigImpl.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersProvider.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13Provider.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestrator.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/Service.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ArpResponderService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ClassifierService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IcmpEchoResponderService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/InboundNatService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2ForwardingService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2RewriteService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L3ForwardingService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/LoadBalancerService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/OutboundNatService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/RoutingService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/Arp.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpFlowFactory.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpMessageAddress.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpOperation.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpResolverMetadata.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpResolverUtils.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpSender.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpUtils.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModule.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModuleFactory.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/yang/netvirt-providers-config.yang [new file with mode: 0644]
openstack/net-virt-providers/src/main/yang/netvirt-providers-impl.yang [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersProviderTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/AbstractServiceInstanceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13ProviderTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorImplTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ArpResponderServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ClassifierServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IcmpEchoResponderServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/InboundNatServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2FowardingServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2RewriteServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L3FowardingServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/LoadBalancerServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/OutboundNatServiceTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/RoutingServiceTest.java [new file with mode: 0644]
openstack/net-virt-sfc/api/pom.xml [new file with mode: 0644]
openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang [new file with mode: 0644]
openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang [new file with mode: 0644]
openstack/net-virt-sfc/api/src/main/yang/netvirt-sfc.yang [new file with mode: 0644]
openstack/net-virt-sfc/artifacts/pom.xml [new file with mode: 0644]
openstack/net-virt-sfc/features/pom.xml [new file with mode: 0644]
openstack/net-virt-sfc/features/src/main/features/features.xml [new file with mode: 0644]
openstack/net-virt-sfc/impl/pom.xml [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/config/default-config.xml [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/DelegatingDataTreeListener.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/INetvirtSfcDataProcessor.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/INetvirtSfcOF13Provider.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/ISfcClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/ISfcStandaloneClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcAclDataProcessor.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcAclListener.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcClassifierDataProcessor.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcProvider.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NshUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/RspDataProcessor.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/RspListener.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/SfcUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/NetvirtSfcStandaloneOF13Provider.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/SfcClassifier.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclMatches.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/FlowCache.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/FlowNames.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModule.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleFactory.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/yang/netvirt-sfc-impl.yang [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclMatchesTest.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleFactoryTest.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleTest.java [new file with mode: 0644]
openstack/net-virt-sfc/it/pom.xml [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/NetvirtSfcIT.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/AbstractUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/AclUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ClassifierUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/NetvirtConfigUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/NetvirtSfcUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/RenderedServicePathUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionChainUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionForwarderUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionPathUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/SfcConfigUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/karaf/pom.xml [new file with mode: 0644]
openstack/net-virt-sfc/pom.xml [new file with mode: 0644]
openstack/net-virt/pom.xml [new file with mode: 0644]
openstack/net-virt/src/main/config/default-config.xml [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/AbstractEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/AbstractHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ClusterAwareMdsalUtils.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ConfigActivator.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ConfigInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/FWaasHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/FloatingIPHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolHandler.java [new file with mode: 0755]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolMemberHandler.java [new file with mode: 0755]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/MdsalHelper.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NetvirtProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NetworkHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NeutronCacheUtils.java [new file with mode: 0755]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NeutronL3AdapterEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NodeCacheManagerEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NodeConfiguration.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NorthboundEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/RouterHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SubnetHandler.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Action.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ArpProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/BridgeConfigurationManager.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ClassifierProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ConfigurationService.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Constants.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/EgressAclProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/EventDispatcher.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/GatewayMacResolver.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/GatewayMacResolverListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/IcmpEchoProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/InboundNatProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/IngressAclProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L2ForwardingProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L2RewriteProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L3ForwardingProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerConfiguration.java [new file with mode: 0755]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerProvider.java [new file with mode: 0755]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/MultiTenantAwareRouter.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProviderManager.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NodeCacheListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NodeCacheManager.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OutboundNatProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbInventoryListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbInventoryService.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbPluginException.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbTables.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Router.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/RoutingProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityGroupCacheManger.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityServicesManager.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Southbound.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Status.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/StatusCode.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/TenantNetworkManager.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/VlanConfigurationCache.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/BridgeConfigurationManagerImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/ConfigurationServiceImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpService.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/EventDispatcherImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/HostConfigService.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3Adapter.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NodeCacheManagerImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OpenstackRouter.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbDataChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbInventoryServiceImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/ProviderNetworkManagerImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SouthboundImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/TenantNetworkManagerImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/VlanConfigurationCacheImpl.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/INeutronObject.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewall.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewallPolicy.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewallRule.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFloatingIP.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancer.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerHealthMonitor.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerPool.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerPoolMember.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancer_SessionPersistence.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronNetwork.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronNetwork_Segment.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_AllowedAddressPairs.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_ExtraDHCPOption.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_VIFDetail.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter_Interface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter_NetworkReference.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSecurityGroup.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSecurityRule.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnet.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnetIPAllocationPool.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnet_HostRoute.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/Neutron_ID.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/Neutron_IPs.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallPolicyCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallRuleCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFloatingIPCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerHealthMonitorCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerListenerCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolMemberCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronNetworkCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronPortCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronRouterCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSecurityGroupCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSecurityRuleCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSubnetCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/NeutronCRUDInterfaces.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/AbstractNeutronInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallPolicyInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallRuleInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerHealthMonitorInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerListenerInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolMemberInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronNetworkInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronRouterInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSecurityGroupInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSecurityRuleInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSubnetInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallPolicyAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallRuleAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFloatingIPAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerHealthMonitorAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerListenerAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolMemberAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronNetworkAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronPortAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronRouterAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSecurityGroupAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSecurityRuleAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSubnetAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronFloatingIPChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolMemberChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronNetworkChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronRouterChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSecurityGroupDataChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSecurityRuleDataChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSubnetChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModule.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModuleFactory.java [new file with mode: 0644]
openstack/net-virt/src/main/yang/netvirt-impl.yang [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/AbstractEventTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/AbstractHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/FWaasHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/FloatingIPHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolMemberHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NetworkHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NeutronCacheUtilsTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NodeCacheManagerEventTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NodeConfigurationTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/PortHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/RouterHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SubnetHandlerTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerConfigurationTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/BridgeConfigurationManagerImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/ConfigurationServiceImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpServiceTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/EventDispatcherImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3AdapterTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/NodeCacheManagerImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbInventoryServiceImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/ProviderNetworkManagerImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/TenantNetworkManagerImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/VlanConfigurationCacheImplTest.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterfaceTest.java [new file with mode: 0644]
openstack/pom.xml [new file with mode: 0644]
ovsdb-ui/bundle/pom.xml [new file with mode: 0644]
ovsdb-ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml [new file with mode: 0644]
ovsdb-ui/module/pom.xml [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/Graph.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/LogicalGraph.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/OvsCore.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/css/ovsdb.css [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/css/select2.min.css [new file with mode: 0755]
ovsdb-ui/module/src/main/resources/ovsdb/css/toggle-switch.css [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/lib/d3.min.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/lib/select2.full.min.js [new file with mode: 0755]
ovsdb-ui/module/src/main/resources/ovsdb/lib/sylvester.js [new file with mode: 0755]
ovsdb-ui/module/src/main/resources/ovsdb/matrix.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.constant.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.controller.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.directives.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.module.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.services.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/views/graph_header.tpl.html [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/views/index.tpl.html [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/views/root.tpl.html [new file with mode: 0644]
ovsdb-ui/pom.xml [new file with mode: 0644]
pom.xml
resources/README [new file with mode: 0644]
resources/commons/3-Node-Cluster-Setup-Environment-Variables.postman_environment [new file with mode: 0644]
resources/commons/L2Gateway.json.postman_collection [new file with mode: 0644]
resources/commons/Mininet_Demo_OVSDB_OF.json.postman_collection [new file with mode: 0644]
resources/commons/NetvirtSfc.json.postman_collection [new file with mode: 0644]
resources/commons/NetvirtSfc.v2.json.postman_collection [new file with mode: 0644]
resources/commons/Neutron-v2.0-LBaaS-API-Examples_July15.json.postman_collection.txt [new file with mode: 0644]
resources/commons/ODL-Clustering.json.postman_collection [new file with mode: 0644]
resources/commons/Ovsdb-HwvtepSouthbound-Collection.json.postman_collection [new file with mode: 0755]
resources/commons/Ovsdb-Southbound-Collection-for-3-Node-Cluster.json.postman_collection [new file with mode: 0644]
resources/commons/Ovsdb-Southbound-Collection-for-Single-Node-Cluster.json.postman_collection [new file with mode: 0644]
resources/commons/Qos-and-Queue-Collection-Environment-Variables.postman_environment [new file with mode: 0644]
resources/commons/Qos-and-Queue-Collection.json.postman_collection [new file with mode: 0644]
resources/commons/README [new file with mode: 0644]
resources/commons/Single-Node-Cluster-Setup-Environment-Variables.postman_environment [new file with mode: 0644]
resources/commons/localhost.json.postman_environment [new file with mode: 0644]
resources/commons/pplog.py [new file with mode: 0755]
resources/commons/readable_flows.py [new file with mode: 0755]
resources/commons/showOvsdbMdsal.py [new file with mode: 0755]
resources/demo/netvirtsfc-env/README.md [new file with mode: 0755]
resources/demo/netvirtsfc-env/Vagrantfile [new file with mode: 0644]
resources/demo/netvirtsfc-env/bootstrap.sh [new file with mode: 0644]
resources/demo/netvirtsfc-env/checkdemo.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/cleandemo.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/cleanodl.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/demo-asymmetric-chain/rest.py [new file with mode: 0755]
resources/demo/netvirtsfc-env/dpdumpflows.py [new file with mode: 0755]
resources/demo/netvirtsfc-env/dumpflows.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/env.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/flowcount.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/images/asymmetric-sfc-demo.png [new file with mode: 0644]
resources/demo/netvirtsfc-env/infrastructure_launch.py [new file with mode: 0755]
resources/demo/netvirtsfc-env/ovswork.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/pollflows.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/resetcontroller.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/rest-clean.py [new file with mode: 0755]
resources/demo/netvirtsfc-env/setsfc.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/startdemo.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/traceflow.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/utils/hosts [new file with mode: 0644]
resources/demo/netvirtsfc-env/utils/overlay-flows.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/utils/setuphosts.sh [new file with mode: 0755]
resources/demo/netvirtsfc-env/vmclean.sh [new file with mode: 0755]
resources/openstack/DevStack.json.postman_collection [new file with mode: 0644]
resources/openstack/Neutron-v2.0-API-Examples.json.postman_collection [new file with mode: 0644]
resources/openstack/Neutron-v2.0-LBaaS-API-Examples.json.postman_collection [new file with mode: 0644]
resources/openstack/README [new file with mode: 0644]
resources/openstack/bootvm.sh [new file with mode: 0755]
resources/openstack/dsconf.sh [new file with mode: 0755]
resources/openstack/local.conf.compute [new file with mode: 0644]
resources/openstack/local.conf.controller [new file with mode: 0644]
resources/openstack/make-vxlan-net.sh [new file with mode: 0755]
resources/openstack/odl_os_ovs.sh [new file with mode: 0755]
resources/openstack/pingvm.sh [new file with mode: 0755]
resources/openstack/sethostname.sh [new file with mode: 0755]
resources/puppet/hiera.yaml [new file with mode: 0644]
resources/puppet/hieradata/hosts.json [new file with mode: 0644]
resources/puppet/manifests/base.pp [new file with mode: 0644]
resources/puppet/manifests/devstack-compute.pp [new file with mode: 0644]
resources/puppet/manifests/devstack-control.pp [new file with mode: 0644]
resources/puppet/manifests/mininet.pp [new file with mode: 0644]
resources/puppet/scripts/bootstrap.sh [new file with mode: 0644]
resources/puppet/templates/compute.local.conf.erb [new file with mode: 0644]
resources/puppet/templates/control.local.conf.erb [new file with mode: 0644]
resources/puppet/templates/hosts.erb [new file with mode: 0644]
resources/robot/README.md [new file with mode: 0644]
resources/robot/Vagrantfile [new file with mode: 0644]
resources/robot/puppet/manifests/dependencies.pp [new file with mode: 0644]
resources/robot/puppet/manifests/ovsnode.pp [new file with mode: 0644]
resources/robot/puppet/manifests/ovsnode_build.pp [new file with mode: 0644]
resources/robot/puppet/scripts/clear_ovs.sh [new file with mode: 0755]
resources/robot/puppet/scripts/setup_defaults.sh [new file with mode: 0644]
resources/robot/scripts/clear_ovs.sh [new file with mode: 0755]
resources/robot/scripts/create_ssh_key.sh [new file with mode: 0644]
resources/robot/scripts/ovs_vm_host_timezone_map.sh [new file with mode: 0644]
resources/robot/scripts/run_robot_tests.sh [new file with mode: 0644]
resources/robot/scripts/setup_other_mininets.sh [new file with mode: 0644]
resources/robot/scripts/setup_robot_framework.sh [new file with mode: 0644]
resources/robot/scripts/special_robot_configuration.sh [new file with mode: 0644]
utils/config/pom.xml [new file with mode: 0644]
utils/config/src/main/java/org/opendaylight/netvirt/utils/config/ConfigProperties.java [new file with mode: 0644]
utils/config/src/test/java/org/opendaylight/netvirt/utils/config/ConfigPropertiesTest.java [new file with mode: 0644]
utils/mdsal-openflow/pom.xml [new file with mode: 0644]
utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/ActionUtils.java [new file with mode: 0644]
utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java [new file with mode: 0644]
utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/InstructionUtils.java [new file with mode: 0644]
utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtils.java [new file with mode: 0644]
utils/mdsal-openflow/src/test/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtilsTest.java [new file with mode: 0644]
utils/mdsal-utils/pom.xml [new file with mode: 0644]
utils/mdsal-utils/src/main/java/org/opendaylight/netvirt/utils/mdsal/utils/MdsalUtils.java [new file with mode: 0644]
utils/mdsal-utils/src/main/java/org/opendaylight/netvirt/utils/mdsal/utils/NotifyingDataChangeListener.java [new file with mode: 0644]
utils/mdsal-utils/src/test/java/org/opendaylight/netvirt/utils/mdsal/utils/MdsalUtilsTest.java [new file with mode: 0644]
utils/netvirt-it-utils/pom.xml [new file with mode: 0644]
utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/ItConstants.java [new file with mode: 0644]
utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java [new file with mode: 0644]
utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java [new file with mode: 0644]
utils/neutron-utils/pom.xml [new file with mode: 0644]
utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronModelsDataStoreHelper.java [new file with mode: 0644]
utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java [new file with mode: 0644]
utils/pom.xml [new file with mode: 0644]
utils/servicehelper/pom.xml [new file with mode: 0644]
utils/servicehelper/src/main/java/org/opendaylight/netvirt/utils/servicehelper/ServiceHelper.java [new file with mode: 0644]
utils/servicehelper/src/test/java/org/opendaylight/netvirt/utils/servicehelper/ServiceHelperTest.java [new file with mode: 0644]
vpnservice/.gitignore [new file with mode: 0644]
vpnservice/.gitreview [new file with mode: 0644]
vpnservice/alivenessmonitor/alivenessmonitor-api/pom.xml [moved from alivenessmonitor/alivenessmonitor-api/pom.xml with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-api/src/main/yang/aliveness-monitor.yang [moved from alivenessmonitor/alivenessmonitor-api/src/main/yang/aliveness-monitor.yang with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/pom.xml [moved from alivenessmonitor/alivenessmonitor-impl/pom.xml with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/config/default-config.xml [moved from alivenessmonitor/alivenessmonitor-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AbstractAlivenessProtocolHandler.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AbstractAlivenessProtocolHandler.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitor.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitor.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorConstants.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorConstants.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorProvider.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorProvider.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorUtil.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorUtil.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandler.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandler.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerARP.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerARP.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerLLDP.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerLLDP.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InterfaceStateListener.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InterfaceStateListener.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InventoryReader.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InventoryReader.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/ServiceProvider.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/ServiceProvider.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/UnsupportedConfigException.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/UnsupportedConfigException.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModule.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModule.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModuleFactory.java [moved from alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModuleFactory.java with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/main/yang/alivenessmonitor-impl.yang [moved from alivenessmonitor/alivenessmonitor-impl/src/main/yang/alivenessmonitor-impl.yang with 100% similarity]
vpnservice/alivenessmonitor/alivenessmonitor-impl/src/test/java/org/opendaylight/controller/alivenessmonitor/test/AlivenessMonitorTest.java [moved from alivenessmonitor/alivenessmonitor-impl/src/test/java/org/opendaylight/controller/alivenessmonitor/test/AlivenessMonitorTest.java with 100% similarity]
vpnservice/alivenessmonitor/pom.xml [moved from alivenessmonitor/pom.xml with 100% similarity]
vpnservice/arputil/arputil-api/pom.xml [moved from arputil/arputil-api/pom.xml with 100% similarity]
vpnservice/arputil/arputil-api/src/main/yang/odl-arputil.yang [moved from arputil/arputil-api/src/main/yang/odl-arputil.yang with 100% similarity]
vpnservice/arputil/arputil-impl/pom.xml [moved from arputil/arputil-impl/pom.xml with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/config/default-config.xml [moved from arputil/arputil-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpPacketUtil.java [moved from arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpPacketUtil.java with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilImpl.java [moved from arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilImpl.java with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilProvider.java [moved from arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilProvider.java with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModule.java [moved from arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModule.java with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModuleFactory.java [moved from arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModuleFactory.java with 100% similarity]
vpnservice/arputil/arputil-impl/src/main/yang/arputil-impl.yang [moved from arputil/arputil-impl/src/main/yang/arputil-impl.yang with 100% similarity]
vpnservice/arputil/pom.xml [moved from arputil/pom.xml with 100% similarity]
vpnservice/bgpmanager/bgpmanager-api/pom.xml [moved from bgpmanager/bgpmanager-api/pom.xml with 100% similarity]
vpnservice/bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java [moved from bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-api/src/main/yang/bgpmanager-api.yang [moved from bgpmanager/bgpmanager-api/src/main/yang/bgpmanager-api.yang with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/pom.xml [moved from bgpmanager/bgpmanager-impl/pom.xml with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/config/default-config.xml [moved from bgpmanager/bgpmanager-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/AbstractDataChangeListener.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/AbstractDataChangeListener.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpConfigurationManager.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpConfigurationManager.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpUtil.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpUtil.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/ConfigureBgpCli.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/ConfigureBgpCli.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/DisplayBgpConfigCli.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/DisplayBgpConfigCli.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/FibDSWriter.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/FibDSWriter.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/VtyshCli.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/VtyshCli.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Cache.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Cache.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/ClearBgpCli.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/ClearBgpCli.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Commands.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Commands.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Connect.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Connect.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Misc.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Misc.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Neighbor.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Neighbor.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Network.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Network.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Router.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Router.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Vrf.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/commands/Vrf.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpAlarmBroadcaster.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpAlarmBroadcaster.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpAlarmBroadcasterMBean.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpAlarmBroadcasterMBean.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpAlarmErrorCodes.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpAlarmErrorCodes.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpConstants.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpConstants.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpCounters.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpCounters.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpCountersBroadcaster.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpCountersBroadcaster.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpCountersBroadcasterMBean.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/oam/BgpCountersBroadcasterMBean.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/client/BgpRouter.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/client/BgpRouter.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/client/BgpRouterException.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/client/BgpRouterException.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/client/BgpSyncHandle.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/client/BgpSyncHandle.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/BgpConfigurator.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/BgpConfigurator.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/BgpUpdater.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/BgpUpdater.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/Routes.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/Routes.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/Update.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/Update.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/af_afi.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/af_afi.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/af_safi.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/af_safi.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/qbgpConstants.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/gen/qbgpConstants.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/idl/qbgp.thrift [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/idl/qbgp.thrift with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/server/BgpThriftService.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/thrift/server/BgpThriftService.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/bgpmanager/impl/rev150326/BgpManagerImplModule.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/bgpmanager/impl/rev150326/BgpManagerImplModule.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/bgpmanager/impl/rev150326/BgpManagerImplModuleFactory.java [moved from bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/bgpmanager/impl/rev150326/BgpManagerImplModuleFactory.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/resources/OSGI-INF/blueprint/commands.xml [moved from bgpmanager/bgpmanager-impl/src/main/resources/OSGI-INF/blueprint/commands.xml with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/main/yang/bgpmanager-impl.yang [moved from bgpmanager/bgpmanager-impl/src/main/yang/bgpmanager-impl.yang with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/test/java/org/opendaylight/vpnservice/bgpmanager/test/AbstractMockFibManager.java [moved from bgpmanager/bgpmanager-impl/src/test/java/org/opendaylight/vpnservice/bgpmanager/test/AbstractMockFibManager.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/test/java/org/opendaylight/vpnservice/bgpmanager/test/BgpManagerTest.java [moved from bgpmanager/bgpmanager-impl/src/test/java/org/opendaylight/vpnservice/bgpmanager/test/BgpManagerTest.java with 100% similarity]
vpnservice/bgpmanager/bgpmanager-impl/src/test/java/org/opendaylight/vpnservice/bgpmanager/test/MockFibManager.java [moved from bgpmanager/bgpmanager-impl/src/test/java/org/opendaylight/vpnservice/bgpmanager/test/MockFibManager.java with 100% similarity]
vpnservice/bgpmanager/pom.xml [moved from bgpmanager/pom.xml with 100% similarity]
vpnservice/commons/binding-parent/pom.xml [moved from commons/binding-parent/pom.xml with 100% similarity]
vpnservice/commons/config-parent/pom.xml [moved from commons/config-parent/pom.xml with 100% similarity]
vpnservice/commons/src/main/resources/vpns_checks.xml [moved from commons/src/main/resources/vpns_checks.xml with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/pom.xml [moved from dhcpservice/dhcpservice-api/pom.xml with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java [moved from dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPConstants.java [moved from dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPConstants.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPMConstants.java [moved from dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPMConstants.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java [moved from dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPUtils.java [moved from dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPUtils.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang [moved from dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang with 100% similarity]
vpnservice/dhcpservice/dhcpservice-api/src/main/yang/dhcpservice-api.yang [moved from dhcpservice/dhcpservice-api/src/main/yang/dhcpservice-api.yang with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/pom.xml [moved from dhcpservice/dhcpservice-impl/pom.xml with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/config/default-config.xml [moved from dhcpservice/dhcpservice-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModuleFactory.java [moved from dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModuleFactory.java with 100% similarity]
vpnservice/dhcpservice/dhcpservice-impl/src/main/yang/dhcpservice-impl.yang [moved from dhcpservice/dhcpservice-impl/src/main/yang/dhcpservice-impl.yang with 100% similarity]
vpnservice/dhcpservice/pom.xml [moved from dhcpservice/pom.xml with 100% similarity]
vpnservice/distribution/karaf/pom.xml [moved from distribution/karaf/pom.xml with 100% similarity]
vpnservice/elanmanager/elanmanager-api/pom.xml [moved from elanmanager/elanmanager-api/pom.xml with 100% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/api/IElanService.java [moved from elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/api/IElanService.java with 100% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/exceptions/MacNotFoundException.java [moved from elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/exceptions/MacNotFoundException.java with 100% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/utils/ElanL2GwCacheUtils.java [moved from elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/utils/ElanL2GwCacheUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/yang/elan-statistics.yang [moved from elanmanager/elanmanager-api/src/main/yang/elan-statistics.yang with 100% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/yang/elan.yang [moved from elanmanager/elanmanager-api/src/main/yang/elan.yang with 100% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/yang/elanmanager-api.yang [moved from elanmanager/elanmanager-api/src/main/yang/elanmanager-api.yang with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/pom.xml [moved from elanmanager/elanmanager-impl/pom.xml with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/config/default-config.xml [moved from elanmanager/elanmanager-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanAdd.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanAdd.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanDelete.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanDelete.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanGet.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanGet.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceAdd.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceAdd.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceDelete.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceDelete.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceGet.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceGet.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceUpdate.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanInterfaceUpdate.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanMacTableFlush.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanMacTableFlush.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanMacTableGet.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanMacTableGet.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanUpdate.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/ElanUpdate.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/StaticMacAdd.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/StaticMacAdd.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/StaticMacDelete.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/StaticMacDelete.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanForwardingEntriesHandler.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanForwardingEntriesHandler.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanItmEventListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanItmEventListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanNodeListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanNodeListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanSmacFlowEventListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanSmacFlowEventListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/statisitcs/ElanStatisticsImpl.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/statisitcs/ElanStatisticsImpl.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/statusanddiag/ElanStatusMonitor.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/statusanddiag/ElanStatusMonitor.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/statusanddiag/ElanStatusMonitorMBean.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/statusanddiag/ElanStatusMonitorMBean.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanCLIUtils.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanCLIUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModuleFactory.java [moved from elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModuleFactory.java with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/resources/OSGI-INF/blueprint/blueprint.xml [moved from elanmanager/elanmanager-impl/src/main/resources/OSGI-INF/blueprint/blueprint.xml with 100% similarity]
vpnservice/elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang [moved from elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang with 100% similarity]
vpnservice/elanmanager/pom.xml [moved from elanmanager/pom.xml with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/pom.xml [moved from fcapsapplication/fcapsapplication-impl/pom.xml with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/FcapsProvider.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/FcapsProvider.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/NodeEventListener.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/NodeEventListener.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/alarm/AlarmAgent.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/alarm/AlarmAgent.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/FlowCapableNodeConnectorCommitter.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/FlowCapableNodeConnectorCommitter.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/FlowNodeConnectorInventoryTranslatorImpl.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/FlowNodeConnectorInventoryTranslatorImpl.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/NodeConnectorEventListener.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/NodeConnectorEventListener.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/NodeUpdateCounter.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/NodeUpdateCounter.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/PMAgent.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/PMAgent.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/PacketInCounterHandler.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/performancecounter/PacketInCounterHandler.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/portinfo/PortNameMapping.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/portinfo/PortNameMapping.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/portinfo/PortNameMappingMBean.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/vpnservice/fcapsapp/portinfo/PortNameMappingMBean.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflowplugin/app/fcaps/app/rev151211/FcapsAppModule.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflowplugin/app/fcaps/app/rev151211/FcapsAppModule.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflowplugin/app/fcaps/app/rev151211/FcapsAppModuleFactory.java [moved from fcapsapplication/fcapsapplication-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflowplugin/app/fcaps/app/rev151211/FcapsAppModuleFactory.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/resources/initial/73-fcaps-app.xml [moved from fcapsapplication/fcapsapplication-impl/src/main/resources/initial/73-fcaps-app.xml with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-impl/src/main/yang/fcaps-app.yang [moved from fcapsapplication/fcapsapplication-impl/src/main/yang/fcaps-app.yang with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/pom.xml [moved from fcapsapplication/fcapsapplication-jmxapi/pom.xml with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/ControlPathFailureAlarm.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/ControlPathFailureAlarm.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/ControlPathFailureAlarmMBean.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/ControlPathFailureAlarmMBean.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFPorts.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFPorts.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFPortsMBean.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFPortsMBean.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFSwitchCounter.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFSwitchCounter.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFSwitchCounterMBean.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/NumberOfOFSwitchCounterMBean.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/PacketInCounter.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/PacketInCounter.java with 100% similarity]
vpnservice/fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/PacketInCounterMBean.java [moved from fcapsapplication/fcapsapplication-jmxapi/src/main/java/org/opendaylight/vpnservice/fcapsappjmx/PacketInCounterMBean.java with 100% similarity]
vpnservice/fcapsapplication/pom.xml [moved from fcapsapplication/pom.xml with 100% similarity]
vpnservice/fcapsmanager/alarmmanager/pom.xml [moved from fcapsmanager/alarmmanager/pom.xml with 100% similarity]
vpnservice/fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/Activator.java [moved from fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/Activator.java with 100% similarity]
vpnservice/fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/AlarmNotificationListeners.java [moved from fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/AlarmNotificationListeners.java with 100% similarity]
vpnservice/fcapsmanager/countermanager/pom.xml [moved from fcapsmanager/countermanager/pom.xml with 100% similarity]
vpnservice/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Activator.java [moved from fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Activator.java with 100% similarity]
vpnservice/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/PMRegistrationListener.java [moved from fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/PMRegistrationListener.java with 100% similarity]
vpnservice/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Poller.java [moved from fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Poller.java with 100% similarity]
vpnservice/fcapsmanager/fcaps-api/pom.xml [moved from fcapsmanager/fcaps-api/pom.xml with 100% similarity]
vpnservice/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/Activator.java [moved from fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/Activator.java with 100% similarity]
vpnservice/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/AlarmServiceFacade.java [moved from fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/AlarmServiceFacade.java with 100% similarity]
vpnservice/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/PMServiceFacade.java [moved from fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/PMServiceFacade.java with 100% similarity]
vpnservice/fcapsmanager/pom.xml [moved from fcapsmanager/pom.xml with 100% similarity]
vpnservice/features/pom.xml [new file with mode: 0644]
vpnservice/features/src/main/features/features.xml [new file with mode: 0644]
vpnservice/fibmanager/fibmanager-api/pom.xml [moved from fibmanager/fibmanager-api/pom.xml with 100% similarity]
vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/fibmanager/api/IFibManager.java [moved from fibmanager/fibmanager-api/src/main/java/org/opendaylight/fibmanager/api/IFibManager.java with 100% similarity]
vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang [moved from fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang with 100% similarity]
vpnservice/fibmanager/fibmanager-api/src/main/yang/fibmanager-api.yang [moved from fibmanager/fibmanager-api/src/main/yang/fibmanager-api.yang with 100% similarity]
vpnservice/fibmanager/fibmanager-api/src/main/yang/l3nexthop.yang [moved from fibmanager/fibmanager-api/src/main/yang/l3nexthop.yang with 100% similarity]
vpnservice/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang [moved from fibmanager/fibmanager-api/src/main/yang/odl-fib.yang with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/pom.xml [moved from fibmanager/fibmanager-impl/pom.xml with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/config/default-config.xml [moved from fibmanager/fibmanager-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibConstants.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibConstants.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManagerProvider.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManagerProvider.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibNodeCapableListener.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibNodeCapableListener.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibRpcServiceImpl.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibRpcServiceImpl.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibUtil.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibUtil.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModuleFactory.java [moved from fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModuleFactory.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/main/yang/fibmanager-impl.yang [moved from fibmanager/fibmanager-impl/src/main/yang/fibmanager-impl.yang with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java [moved from fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java with 100% similarity]
vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/MockDataChangedEvent.java [moved from fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/MockDataChangedEvent.java with 100% similarity]
vpnservice/fibmanager/fibmanager-shell/pom.xml [moved from fibmanager/fibmanager-shell/pom.xml with 100% similarity]
vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/vpnservice/fibmanager/shell/ShowFibCommand.java [moved from fibmanager/fibmanager-shell/src/main/java/org/opendaylight/vpnservice/fibmanager/shell/ShowFibCommand.java with 100% similarity]
vpnservice/fibmanager/fibmanager-shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml [moved from fibmanager/fibmanager-shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml with 100% similarity]
vpnservice/fibmanager/pom.xml [moved from fibmanager/pom.xml with 100% similarity]
vpnservice/idmanager/idmanager-api/pom.xml [moved from idmanager/idmanager-api/pom.xml with 100% similarity]
vpnservice/idmanager/idmanager-api/src/main/yang/id-manager.yang [moved from idmanager/idmanager-api/src/main/yang/id-manager.yang with 100% similarity]
vpnservice/idmanager/idmanager-impl/pom.xml [moved from idmanager/idmanager-impl/pom.xml with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/config/default-config.xml [moved from idmanager/idmanager-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManager.java [moved from idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManager.java with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManagerServiceProvider.java [moved from idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManagerServiceProvider.java with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdUtils.java [moved from idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdUtils.java with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModule.java [moved from idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModule.java with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModuleFactory.java [moved from idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModuleFactory.java with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/main/yang/idmanager-impl.yang [moved from idmanager/idmanager-impl/src/main/yang/idmanager-impl.yang with 100% similarity]
vpnservice/idmanager/idmanager-impl/src/test/java/org/opendaylight/idmanager/test/IdManagerTest.java [moved from idmanager/idmanager-impl/src/test/java/org/opendaylight/idmanager/test/IdManagerTest.java with 100% similarity]
vpnservice/idmanager/pom.xml [moved from idmanager/pom.xml with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/pom.xml [moved from interfacemgr/interfacemgr-api/pom.xml with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/exceptions/InterfaceAlreadyExistsException.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/exceptions/InterfaceAlreadyExistsException.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/exceptions/InterfaceNotFoundException.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/exceptions/InterfaceNotFoundException.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/exceptions/InterfaceServiceNotFoundException.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/exceptions/InterfaceServiceNotFoundException.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/IfmConstants.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/IfmConstants.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/InterfaceInfo.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/InterfaceInfo.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/InterfaceServiceUtil.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/InterfaceServiceUtil.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/LogicalGroupInterfaceInfo.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/LogicalGroupInterfaceInfo.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/VlanInterfaceInfo.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/globals/VlanInterfaceInfo.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/interfaces/IInterfaceManager.java [moved from interfacemgr/interfacemgr-api/src/main/java/org/opendaylight/vpnservice/interfacemgr/interfaces/IInterfaceManager.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/yang/interface-statistics.yang [moved from interfacemgr/interfacemgr-api/src/main/yang/interface-statistics.yang with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-meta.yang [moved from interfacemgr/interfacemgr-api/src/main/yang/odl-interface-meta.yang with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-rpc.yang [moved from interfacemgr/interfacemgr-api/src/main/yang/odl-interface-rpc.yang with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-service-bindings.yang [moved from interfacemgr/interfacemgr-api/src/main/yang/odl-interface-service-bindings.yang with 100% similarity]
vpnservice/interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang [moved from interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/pom.xml [moved from interfacemgr/interfacemgr-impl/pom.xml with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/config/default-config.xml [moved from interfacemgr/interfacemgr-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmConstants.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmConstants.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmUtil.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmUtil.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/AlivenessMonitorUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/AlivenessMonitorUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceManagerCommonUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceManagerCommonUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/AlivenessMonitorListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/AlivenessMonitorListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/HwVTEPConfigListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/HwVTEPConfigListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/HwVTEPTunnelsStateListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/HwVTEPTunnelsStateListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceConfigListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceConfigListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceTopologyStateListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceTopologyStateListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/TerminationPointStateListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/TerminationPointStateListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/VlanMemberConfigListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/VlanMemberConfigListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForEntriesPerOFTable.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForEntriesPerOFTable.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForEntriesPerOFTableMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForEntriesPerOFTableMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesReceive.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesReceive.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesReceiveMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesReceiveMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesSent.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesSent.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesSentMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortBytesSentMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortDuration.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortDuration.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortDurationMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortDurationMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketReceive.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketReceive.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketReceiveMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketReceiveMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketSent.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketSent.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketSentMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortPacketSentMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveDrop.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveDrop.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveDropMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveDropMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveError.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveError.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveErrorMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/CounterForOFPortReceiveErrorMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/NodeConnectorStatsImpl.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/NodeConnectorStatsImpl.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/PMAgentForNodeConnectorCounters.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/pmcounters/PMAgentForNodeConnectorCounters.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPConfigRemoveHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPConfigRemoveHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPInterfaceConfigAddHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPInterfaceConfigAddHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPInterfaceConfigUpdateHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPInterfaceConfigUpdateHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateRemoveHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateRemoveHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateUpdateHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateUpdateHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/utilities/SouthboundUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/utilities/SouthboundUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigAddHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigAddHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigRemoveHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigRemoveHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigUpdateHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigUpdateHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigRemoveHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigRemoveHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigUpdateHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigUpdateHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateAddHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateAddHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateUpdateHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateUpdateHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateAddHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateAddHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateRemoveHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateRemoveHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateUpdateHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateUpdateHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/utilities/SouthboundUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/utilities/SouthboundUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/utilities/VlanTrunkSouthboundUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/utilities/VlanTrunkSouthboundUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/rpcservice/InterfaceManagerRpcService.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/rpcservice/InterfaceManagerRpcService.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/confighelpers/FlowBasedServicesConfigBindHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/confighelpers/FlowBasedServicesConfigBindHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/confighelpers/FlowBasedServicesConfigUnbindHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/confighelpers/FlowBasedServicesConfigUnbindHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/listeners/FlowBasedServicesConfigListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/listeners/FlowBasedServicesConfigListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/listeners/FlowBasedServicesInterfaceStateListener.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/listeners/FlowBasedServicesInterfaceStateListener.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/statehelpers/FlowBasedServicesStateBindHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/statehelpers/FlowBasedServicesStateBindHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/statehelpers/FlowBasedServicesStateUnbindHelper.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/statehelpers/FlowBasedServicesStateUnbindHelper.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/statusanddiag/InterfaceStatusMonitor.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/statusanddiag/InterfaceStatusMonitor.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/statusanddiag/InterfaceStatusMonitorMBean.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/statusanddiag/InterfaceStatusMonitorMBean.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/interfacemgr/impl/rev150325/InterfacemgrImplModule.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/interfacemgr/impl/rev150325/InterfacemgrImplModule.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/interfacemgr/impl/rev150325/InterfacemgrImplModuleFactory.java [moved from interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/interfacemgr/impl/rev150325/InterfacemgrImplModuleFactory.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/main/yang/interfacemgr-impl.yang [moved from interfacemgr/interfacemgr-impl/src/main/yang/interfacemgr-impl.yang with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/FlowBasedServicesConfigurationTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/FlowBasedServicesConfigurationTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/FlowBasedServicesStateConfigurationTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/FlowBasedServicesStateConfigurationTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/HwVTEPConfigurationTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/HwVTEPConfigurationTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/IfmUtilTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/IfmUtilTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/InterfaceManagerTestUtil.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/InterfaceManagerTestUtil.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/StateInterfaceTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/StateInterfaceTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TopologyStateInterfaceTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TopologyStateInterfaceTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TunnelInterfaceConfigurationTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TunnelInterfaceConfigurationTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/VlanInterfaceConfigurationTest.java [moved from interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/VlanInterfaceConfigurationTest.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-shell/pom.xml [moved from interfacemgr/interfacemgr-shell/pom.xml with 100% similarity]
vpnservice/interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/IfmCLIUtil.java [moved from interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/IfmCLIUtil.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/ShowVlan.java [moved from interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/ShowVlan.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/ShowVxlan.java [moved from interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/ShowVxlan.java with 100% similarity]
vpnservice/interfacemgr/interfacemgr-shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml [moved from interfacemgr/interfacemgr-shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml with 100% similarity]
vpnservice/interfacemgr/pom.xml [moved from interfacemgr/pom.xml with 100% similarity]
vpnservice/itm/itm-api/.gitignore [moved from itm/itm-api/.gitignore with 100% similarity]
vpnservice/itm/itm-api/pom.xml [moved from itm/itm-api/pom.xml with 100% similarity]
vpnservice/itm/itm-api/src/main/java/org/opendaylight/vpnservice/itm/api/IITMProvider.java [moved from itm/itm-api/src/main/java/org/opendaylight/vpnservice/itm/api/IITMProvider.java with 100% similarity]
vpnservice/itm/itm-api/src/main/java/org/opendaylight/vpnservice/itm/globals/ITMConstants.java [moved from itm/itm-api/src/main/java/org/opendaylight/vpnservice/itm/globals/ITMConstants.java with 100% similarity]
vpnservice/itm/itm-api/src/main/yang/itm-config.yang [moved from itm/itm-api/src/main/yang/itm-config.yang with 100% similarity]
vpnservice/itm/itm-api/src/main/yang/itm-rpc.yang [moved from itm/itm-api/src/main/yang/itm-rpc.yang with 100% similarity]
vpnservice/itm/itm-api/src/main/yang/itm-state.yang [moved from itm/itm-api/src/main/yang/itm-state.yang with 100% similarity]
vpnservice/itm/itm-api/src/main/yang/itm.yang [moved from itm/itm-api/src/main/yang/itm.yang with 100% similarity]
vpnservice/itm/itm-impl/pom.xml [moved from itm/itm-impl/pom.xml with 100% similarity]
vpnservice/itm/itm-impl/src/main/config/default-config.xml [moved from itm/itm-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/ItmCliUtils.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/ItmCliUtils.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/SubnetObject.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/SubnetObject.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepAdd.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepAdd.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepCommandHelper.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepCommandHelper.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepCommit.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepCommit.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepConfigureTunnelType.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepConfigureTunnelType.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepDelete.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepDelete.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepDeleteDatastore.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepDeleteDatastore.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepEnableTunnelMonitor.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepEnableTunnelMonitor.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepMonitor.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepMonitor.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepShow.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepShow.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepShowState.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepShowState.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepStateShow.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepStateShow.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaAdd.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaAdd.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaDelete.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaDelete.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaShow.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaShow.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaUpdate.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/VtepSchemaUpdate.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/HwVtep.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/HwVtep.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmExternalTunnelAddWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmExternalTunnelAddWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmExternalTunnelDeleteWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmExternalTunnelDeleteWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmInternalTunnelAddWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmInternalTunnelAddWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmInternalTunnelDeleteWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmInternalTunnelDeleteWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorIntervalWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorIntervalWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorToggleWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorToggleWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmTepAddWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmTepAddWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmTepRemoveWorker.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmTepRemoveWorker.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ITMManager.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ITMManager.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmCache.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmCache.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmProvider.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmProvider.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmUtils.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmUtils.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TransportZoneListener.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TransportZoneListener.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorChangeListener.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorChangeListener.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorIntervalListener.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorIntervalListener.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/VtepConfigSchemaListener.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/VtepConfigSchemaListener.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarm.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarm.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarmMBean.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarmMBean.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/ItmTunnelEventListener.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/ItmTunnelEventListener.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/JMXAlarmAgent.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/JMXAlarmAgent.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/rpc/ItmManagerRpcService.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/rpc/ItmManagerRpcService.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/snd/ITMStatusMonitor.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/snd/ITMStatusMonitor.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/snd/ITMStatusMonitorMBean.java [moved from itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/snd/ITMStatusMonitorMBean.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/vpnservice/itm/impl/rev141210/ItmModule.java [moved from itm/itm-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/vpnservice/itm/impl/rev141210/ItmModule.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/vpnservice/itm/impl/rev141210/ItmModuleFactory.java [moved from itm/itm-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/vpnservice/itm/impl/rev141210/ItmModuleFactory.java with 100% similarity]
vpnservice/itm/itm-impl/src/main/resources/OSGI-INF/blueprint/commands.xml [moved from itm/itm-impl/src/main/resources/OSGI-INF/blueprint/commands.xml with 100% similarity]
vpnservice/itm/itm-impl/src/main/yang/itm-impl.yang [moved from itm/itm-impl/src/main/yang/itm-impl.yang with 100% similarity]
vpnservice/itm/itm-impl/src/test/java/org/opendaylight/vpnservice/itm/impl/ItmProviderTest.java [moved from itm/itm-impl/src/test/java/org/opendaylight/vpnservice/itm/impl/ItmProviderTest.java with 100% similarity]
vpnservice/itm/itm-impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/itm/impl/rev141210/ItmModuleFactoryTest.java [moved from itm/itm-impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/itm/impl/rev141210/ItmModuleFactoryTest.java with 100% similarity]
vpnservice/itm/itm-impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/itm/impl/rev141210/ItmModuleTest.java [moved from itm/itm-impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/itm/impl/rev141210/ItmModuleTest.java with 100% similarity]
vpnservice/itm/pom.xml [moved from itm/pom.xml with 100% similarity]
vpnservice/lockmanager/lockmanager-api/pom.xml [moved from lockmanager/lockmanager-api/pom.xml with 100% similarity]
vpnservice/lockmanager/lockmanager-api/src/main/yang/lock-manager.yang [moved from lockmanager/lockmanager-api/src/main/yang/lock-manager.yang with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/pom.xml [moved from lockmanager/lockmanager-impl/pom.xml with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/config/default-config.xml [moved from lockmanager/lockmanager-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/java/org/opendaylight/lockmanager/LockManager.java [moved from lockmanager/lockmanager-impl/src/main/java/org/opendaylight/lockmanager/LockManager.java with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/java/org/opendaylight/lockmanager/LockManagerServiceProvider.java [moved from lockmanager/lockmanager-impl/src/main/java/org/opendaylight/lockmanager/LockManagerServiceProvider.java with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/java/org/opendaylight/lockmanager/LockManagerUtils.java [moved from lockmanager/lockmanager-impl/src/main/java/org/opendaylight/lockmanager/LockManagerUtils.java with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/lockmanager/impl/rev150819/LockManagerImplModule.java [moved from lockmanager/lockmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/lockmanager/impl/rev150819/LockManagerImplModule.java with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/lockmanager/impl/rev150819/LockManagerImplModuleFactory.java [moved from lockmanager/lockmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/lockmanager/impl/rev150819/LockManagerImplModuleFactory.java with 100% similarity]
vpnservice/lockmanager/lockmanager-impl/src/main/yang/lockmanager-impl.yang [moved from lockmanager/lockmanager-impl/src/main/yang/lockmanager-impl.yang with 100% similarity]
vpnservice/lockmanager/pom.xml [moved from lockmanager/pom.xml with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/pom.xml [moved from mdsalutil/mdsalutil-api/pom.xml with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/AsyncClusteredDataChangeListenerBase.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/AsyncClusteredDataChangeListenerBase.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/AsyncDataChangeListenerBase.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/AsyncDataChangeListenerBase.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/AsyncDataTreeChangeListenerBase.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/AsyncDataTreeChangeListenerBase.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/DataStoreJobCoordinator.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/DataStoreJobCoordinator.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/JobEntry.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/JobEntry.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/JobQueue.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/JobQueue.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/RollbackCallable.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/RollbackCallable.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/TaskRetryLooper.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/datastoreutils/TaskRetryLooper.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/AbstractDataChangeListener.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/AbstractDataChangeListener.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/AbstractSwitchEntity.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/AbstractSwitchEntity.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/ActionInfo.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/ActionInfo.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/ActionType.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/ActionType.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/BucketInfo.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/BucketInfo.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/FlowEntity.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/FlowEntity.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/FlowInfoKey.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/FlowInfoKey.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/GroupEntity.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/GroupEntity.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/GroupInfoKey.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/GroupInfoKey.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/InstructionInfo.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/InstructionInfo.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/InstructionType.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/InstructionType.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALDataStoreUtils.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALDataStoreUtils.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALUtil.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALUtil.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MatchFieldType.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MatchFieldType.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MatchInfo.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MatchInfo.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MetaDataConstants.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MetaDataConstants.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MetaDataUtil.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MetaDataUtil.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NWUtil.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NWUtil.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NwConstants.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NwConstants.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/interfaces/IMdsalApiManager.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/interfaces/IMdsalApiManager.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IEEE8021Q.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IEEE8021Q.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/SystemPropertyReader.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/SystemPropertyReader.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/cache/CacheUtil.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/cache/CacheUtil.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerNotPresentException.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerNotPresentException.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java [moved from mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-api/src/main/yang/odl-mdsalutil.yang [moved from mdsalutil/mdsalutil-api/src/main/yang/odl-mdsalutil.yang with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/pom.xml [moved from mdsalutil/mdsalutil-impl/pom.xml with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/config/default-config.xml [moved from mdsalutil/mdsalutil-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALManager.java [moved from mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALManager.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALUtilProvider.java [moved from mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALUtilProvider.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/NotifyTask.java [moved from mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/NotifyTask.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/mdsalutil/impl/rev150403/MdsaluttilimplModule.java [moved from mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/mdsalutil/impl/rev150403/MdsaluttilimplModule.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/mdsalutil/impl/rev150403/MdsaluttilimplModuleFactory.java [moved from mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/mdsalutil/impl/rev150403/MdsaluttilimplModuleFactory.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/main/yang/mdsalutil-impl.yang [moved from mdsalutil/mdsalutil-impl/src/main/yang/mdsalutil-impl.yang with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/AbstractMockForwardingRulesManager.java [moved from mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/AbstractMockForwardingRulesManager.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/MdSalUtilTest.java [moved from mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/MdSalUtilTest.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/MockFlowForwarder.java [moved from mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/MockFlowForwarder.java with 100% similarity]
vpnservice/mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/MockGroupForwarder.java [moved from mdsalutil/mdsalutil-impl/src/test/java/org/opendaylight/vpnservice/test/MockGroupForwarder.java with 100% similarity]
vpnservice/mdsalutil/pom.xml [moved from mdsalutil/pom.xml with 100% similarity]
vpnservice/model-bgp/pom.xml [moved from model-bgp/pom.xml with 100% similarity]
vpnservice/model-bgp/src/main/yang/bgp.yang [moved from model-bgp/src/main/yang/bgp.yang with 100% similarity]
vpnservice/model-bgp/src/main/yang/ebgp.yang [moved from model-bgp/src/main/yang/ebgp.yang with 100% similarity]
vpnservice/natservice/natservice-api/pom.xml [moved from natservice/natservice-api/pom.xml with 100% similarity]
vpnservice/natservice/natservice-api/src/main/yang/odl-nat.yang [moved from natservice/natservice-api/src/main/yang/odl-nat.yang with 100% similarity]
vpnservice/natservice/natservice-impl/pom.xml [moved from natservice/natservice-impl/pom.xml with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/config/default-config.xml [moved from natservice/natservice-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/DpnInVpnListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/DpnInVpnListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/EventDispatcher.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/EventDispatcher.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworkListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworkListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworksChangeListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworksChangeListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalRoutersListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalRoutersListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPHandler.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPHandler.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/IPAddress.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/IPAddress.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/InterfaceStateEventListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/InterfaceStateEventListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTEntryEvent.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTEntryEvent.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTSwitchSelector.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTSwitchSelector.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptEventHandler.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptEventHandler.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptPacketInHandler.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptPacketInHandler.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptSwitchHA.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptSwitchHA.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatConstants.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatConstants.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatNodeEventListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatNodeEventListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatServiceProvider.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatServiceProvider.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatUtil.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatUtil.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterDpnChangeListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterDpnChangeListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterPortsListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterPortsListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterToVpnListener.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterToVpnListener.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SNATDefaultRouteProgrammer.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SNATDefaultRouteProgrammer.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SessionAddress.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SessionAddress.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/VpnFloatingIpHandler.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/VpnFloatingIpHandler.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModule.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModule.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModuleFactory.java [moved from natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModuleFactory.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/main/yang/natservice-impl.yang [moved from natservice/natservice-impl/src/main/yang/natservice-impl.yang with 100% similarity]
vpnservice/natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/ExternalNetworksChangeListenerTest.java [moved from natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/ExternalNetworksChangeListenerTest.java with 100% similarity]
vpnservice/natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/NaptManagerTest.java [moved from natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/NaptManagerTest.java with 100% similarity]
vpnservice/natservice/pom.xml [moved from natservice/pom.xml with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/pom.xml [moved from neutronvpn/neutronvpn-api/pom.xml with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/l2gw/L2GatewayDevice.java [moved from neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/l2gw/L2GatewayDevice.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/l2gw/utils/L2GatewayCacheUtils.java [moved from neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/l2gw/utils/L2GatewayCacheUtils.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java [moved from neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/interfaces/INeutronVpnManager.java [moved from neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/interfaces/INeutronVpnManager.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/src/main/yang/neutronvpn-api.yang [moved from neutronvpn/neutronvpn-api/src/main/yang/neutronvpn-api.yang with 100% similarity]
vpnservice/neutronvpn/neutronvpn-api/src/main/yang/neutronvpn.yang [moved from neutronvpn/neutronvpn-api/src/main/yang/neutronvpn.yang with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/pom.xml [moved from neutronvpn/neutronvpn-impl/pom.xml with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/config/default-config.xml [moved from neutronvpn/neutronvpn-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronBgpvpnChangeListener.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronBgpvpnChangeListener.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronNetworkChangeListener.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronNetworkChangeListener.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronPortChangeListener.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronPortChangeListener.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronRouterChangeListener.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronRouterChangeListener.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronSubnetChangeListener.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronSubnetChangeListener.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnManager.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnManager.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnUtils.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnUtils.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayUtils.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayUtils.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModuleFactory.java [moved from neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModuleFactory.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang [moved from neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang with 100% similarity]
vpnservice/neutronvpn/neutronvpn-shell/pom.xml [moved from neutronvpn/neutronvpn-shell/pom.xml with 100% similarity]
vpnservice/neutronvpn/neutronvpn-shell/src/main/java/org/opendaylight/vpnservice/neutronvpn/shell/ConfigureL3VpnCommand.java [moved from neutronvpn/neutronvpn-shell/src/main/java/org/opendaylight/vpnservice/neutronvpn/shell/ConfigureL3VpnCommand.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-shell/src/main/java/org/opendaylight/vpnservice/neutronvpn/shell/ShowNeutronPortsCommand.java [moved from neutronvpn/neutronvpn-shell/src/main/java/org/opendaylight/vpnservice/neutronvpn/shell/ShowNeutronPortsCommand.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-shell/src/main/java/org/opendaylight/vpnservice/neutronvpn/shell/ShowVpnConfigCommand.java [moved from neutronvpn/neutronvpn-shell/src/main/java/org/opendaylight/vpnservice/neutronvpn/shell/ShowVpnConfigCommand.java with 100% similarity]
vpnservice/neutronvpn/neutronvpn-shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml [moved from neutronvpn/neutronvpn-shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml with 100% similarity]
vpnservice/neutronvpn/pom.xml [moved from neutronvpn/pom.xml with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-api/pom.xml [moved from nexthopmgr/nexthopmgr-api/pom.xml with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-api/src/main/yang/l3nexthop.yang [moved from nexthopmgr/nexthopmgr-api/src/main/yang/l3nexthop.yang with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/pom.xml [moved from nexthopmgr/nexthopmgr-impl/pom.xml with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/config/default-config.xml [moved from nexthopmgr/nexthopmgr-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/AbstractDataChangeListener.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/AbstractDataChangeListener.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopManager.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopManager.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopmgrProvider.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopmgrProvider.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/OdlInterfaceChangeListener.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/OdlInterfaceChangeListener.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/VpnInterfaceChangeListener.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/VpnInterfaceChangeListener.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/nexthopmgr/impl/rev150325/NexthopmgrImplModule.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/nexthopmgr/impl/rev150325/NexthopmgrImplModule.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/nexthopmgr/impl/rev150325/NexthopmgrImplModuleFactory.java [moved from nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/nexthopmgr/impl/rev150325/NexthopmgrImplModuleFactory.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/main/yang/nexthopmgr-impl.yang [moved from nexthopmgr/nexthopmgr-impl/src/main/yang/nexthopmgr-impl.yang with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/test/java/org/opendaylight/vpnservice/nexthopmgr/test/MockDataChangedEvent.java [moved from nexthopmgr/nexthopmgr-impl/src/test/java/org/opendaylight/vpnservice/nexthopmgr/test/MockDataChangedEvent.java with 100% similarity]
vpnservice/nexthopmgr/nexthopmgr-impl/src/test/java/org/opendaylight/vpnservice/nexthopmgr/test/NexthopManagerTest.java [moved from nexthopmgr/nexthopmgr-impl/src/test/java/org/opendaylight/vpnservice/nexthopmgr/test/NexthopManagerTest.java with 100% similarity]
vpnservice/nexthopmgr/pom.xml [moved from nexthopmgr/pom.xml with 100% similarity]
vpnservice/pom.xml [new file with mode: 0644]
vpnservice/vpnintent/api/pom.xml [moved from vpnintent/api/pom.xml with 100% similarity]
vpnservice/vpnintent/api/src/main/yang/vpnintent.yang [moved from vpnintent/api/src/main/yang/vpnintent.yang with 100% similarity]
vpnservice/vpnintent/impl/pom.xml [moved from vpnintent/impl/pom.xml with 100% similarity]
vpnservice/vpnintent/impl/src/main/config/default-config.xml [moved from vpnintent/impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java [moved from vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MappingServiceManager.java [moved from vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MappingServiceManager.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java [moved from vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/VpnintentProvider.java [moved from vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/VpnintentProvider.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java [moved from vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModule.java [moved from vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModule.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModuleFactory.java [moved from vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModuleFactory.java with 100% similarity]
vpnservice/vpnintent/impl/src/main/yang/vpnintent-impl.yang [moved from vpnintent/impl/src/main/yang/vpnintent-impl.yang with 100% similarity]
vpnservice/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java [moved from vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java with 100% similarity]
vpnservice/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/MappingServiceManagerTests.java [moved from vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/MappingServiceManagerTests.java with 100% similarity]
vpnservice/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/VpnintentProviderTest.java [moved from vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/VpnintentProviderTest.java with 100% similarity]
vpnservice/vpnintent/pom.xml [moved from vpnintent/pom.xml with 100% similarity]
vpnservice/vpnintent/resources/vpnintent.postman_collection [moved from vpnintent/resources/vpnintent.postman_collection with 100% similarity]
vpnservice/vpnmanager/pom.xml [moved from vpnmanager/pom.xml with 100% similarity]
vpnservice/vpnmanager/vpnmanager-api/pom.xml [moved from vpnmanager/vpnmanager-api/pom.xml with 100% similarity]
vpnservice/vpnmanager/vpnmanager-api/src/main/java/org/opendaylight/vpnmanager/api/IVpnManager.java [moved from vpnmanager/vpnmanager-api/src/main/java/org/opendaylight/vpnmanager/api/IVpnManager.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/l3vpn.yang [moved from vpnmanager/vpnmanager-api/src/main/yang/l3vpn.yang with 100% similarity]
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang [moved from vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang with 100% similarity]
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/vpn-rpc.yang [moved from vpnmanager/vpnmanager-api/src/main/yang/vpn-rpc.yang with 100% similarity]
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/vpnmanager-api.yang [moved from vpnmanager/vpnmanager-api/src/main/yang/vpnmanager-api.yang with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/pom.xml [moved from vpnmanager/vpnmanager-impl/pom.xml with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/config/default-config.xml [moved from vpnmanager/vpnmanager-impl/src/main/config/default-config.xml with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/AbstractDataChangeListener.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/AbstractDataChangeListener.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/ArpNotificationHandler.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/ArpNotificationHandler.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/ArpReplyOrRequest.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/ArpReplyOrRequest.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/InterfaceStateChangeListener.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/InterfaceStateChangeListener.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/RouterInterfaceListener.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/RouterInterfaceListener.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetOpDpnManager.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetOpDpnManager.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetRoutePacketInHandler.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetRoutePacketInHandler.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnNotifyTask.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnNotifyTask.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnSubnetRouteHandler.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnSubnetRouteHandler.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/utilities/InterfaceUtils.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/utilities/InterfaceUtils.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnservice/impl/rev150216/VpnserviceImplModule.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnservice/impl/rev150216/VpnserviceImplModule.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnservice/impl/rev150216/VpnserviceImplModuleFactory.java [moved from vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnservice/impl/rev150216/VpnserviceImplModuleFactory.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/main/yang/vpnservice-impl.yang [moved from vpnmanager/vpnmanager-impl/src/main/yang/vpnservice-impl.yang with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/MockDataChangedEvent.java [moved from vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/MockDataChangedEvent.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/SubnetOpDpnManagerTest.java [moved from vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/SubnetOpDpnManagerTest.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/VpnServiceTest.java [moved from vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/VpnServiceTest.java with 100% similarity]
vpnservice/vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/VpnSubnetRouteHandlerTest.java [moved from vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/VpnSubnetRouteHandlerTest.java with 100% similarity]
vpnservice/vpnservice-artifacts/pom.xml [moved from vpnservice-artifacts/pom.xml with 100% similarity]

old mode 100644 (file)
new mode 100755 (executable)
index bbbe4f2..6576f62
@@ -1,24 +1,32 @@
-#
-# Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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
-#
+*.class
+**/target
+bin/
+dist
+**/logs
+products
+repository
+workspace
+*~
+target
 .classpath
 .project
 .settings
-.metadata
-target
+MANIFEST.MF
+opendaylight/northbound/integrationtest/logs/*
+*.ipr
 *.iml
+*.iws
 .idea
-bin
-xtend-gen
-target
+*.pyc
+log.html
+output.xml
+report.html
+*.swp
+.gitignore
+target-ide/
+.vagrant
 .DS_Store
 .checkstyle
 yang-gen-config
 yang-gen-sal
-classes
 maven-metadata-local.xml
-META-INF
index a959a5e3212196e7407645defb498894fe2a4fbc..4b900782c8e5926d087900c36b80a58b5b6fad6b 100644 (file)
@@ -1,5 +1,5 @@
 [gerrit]
 host=git.opendaylight.org
 port=29418
-project=vpnservice.git
+project=netvirt.git
 defaultbranch=master
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..3d967ae
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,70 @@
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+b) its license agreement:
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+b) a copy of this Agreement must be included with each copy of the Program.
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
\ No newline at end of file
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1cf47ae
--- /dev/null
+++ b/README
@@ -0,0 +1,107 @@
+DIRECTORY ORGANIZATION
+======================
+
+- commons
+  +-- parent : Contains Parent pom.xml for all the ovsdb modules.
+
+- features : This folder contains all the Karaf related files.
+
+- karaf : Builds a working controller distribution based on the controller + ovsdb modules and other
+          dependant modules such as openflowplugin
+
+- openstack
+  +-- net-virt : Handles the Openstack Neutron ML2 and Network Service calls and performs all the logic required
+                 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
+
+- resources : Contains some useful resources such as scripts, testing utilities and tools used for deployment
+              or testing the binaries generated from the OVSDB project.
+
+- utils : MD-SAL OpenFlow and OVSDB common utilities.
+
+HOW TO BUILD & RUN
+==================
+
+Pre-requisites : JDK 1.7+, Maven 3+
+
+1. Building a Karaf Feature and deploying it in an Opendaylight Karaf distribution :
+   1. From the root ovsdb/ directory, execute "mvn clean install"
+
+   2. Unzip the karaf-<VERSION_NUMBER>-SNAPSHOT.zip file created from step 1 in the directory ovsdb/karaf/target/:
+      "unzip karaf-<VERSION_NUMBER>-SNAPSHOT.zip"
+
+   3. Once karaf has started and you see the Opendaylight ascii art in the console, the last step
+      is to start the OVSDB plugin framework with the following command in the karaf console:
+      "feature:install odl-ovsdb-openstack" (without quotation marks).
+
+   Sample output from Karaf console :
+
+  opendaylight-user@root>feature:list -i | grep ovsdb
+   odl-ovsdb-southbound-api          | 1.2.1-SNAPSHOT   | x         | odl-ovsdb-southbound-1.2.1-SNAPSHOT     | OpenDaylight :: southbound :: api
+   odl-ovsdb-southbound-impl         | 1.2.1-SNAPSHOT   | x         | odl-ovsdb-southbound-1.2.1-SNAPSHOT     | OpenDaylight :: southbound :: impl
+   odl-ovsdb-southbound-impl-rest    | 1.2.1-SNAPSHOT   | x         | odl-ovsdb-southbound-1.2.1-SNAPSHOT     | OpenDaylight :: southbound :: impl :: REST
+   odl-ovsdb-southbound-impl-ui      | 1.2.1-SNAPSHOT   | x         | odl-ovsdb-southbound-1.2.1-SNAPSHOT     | OpenDaylight :: southbound :: impl :: UI
+   odl-ovsdb-library                 | 1.2.1-SNAPSHOT   | x         | odl-ovsdb-library-1.2.1-SNAPSHOT        | OpenDaylight :: library
+   odl-ovsdb-openstack               | 1.2.1-SNAPSHOT   | x         | ovsdb-1.2.1-SNAPSHOT                    | OpenDaylight :: OVSDB :: OpenStack Network Virtual
+
+2. Building a bundle and deploying it in an Opendaylight Karaf distribution :
+   This method can be used to update and test new code in a bundle. If the bundle of interest is rebuilt as a
+   snapshot with the same version as what it already defined in a feature repo then that new bundle will be used
+   when the feature is loaded in karaf. If karaf is already running with the feature loaded then follow the steps
+   below to load the new bundle:
+
+   1. Find the bundle id of the bundle you are going to rebuild:
+      - bundle:list -s | grep <bundlename>, i.e. bundle:list -s | grep odl-ovsdb-plugin
+
+   2. Instruct karaf to watch the new bundle and reload it if it changes:
+      - bundle:watch <id>
+      - The id is the value returned in 1 above.
+      - You can also watch the bundle URL itself:
+        - bundle:watch mvn:org.opendaylight.ovsdb/plugin/1.0.2-SNAPSHOT
+
+   3. Rebuild bundle.
+      - cd bundle dir, i.e. cd ovsdb/plugin
+      - mvn clean install. This will install the new bundle into the local mvn repo.
+
+   4. karaf will see the changed bundle and reload it.
+
+Running The Integration Tests
+=============================
+
+To run the integration tests locally the following components are required:
+
+ - Docker
+ - Docker Compose
+
+To install docker, follow the installation guide for your platform:
+   http://docs.docker.com/installation/
+
+To install Docker Compose:
+   http://docs.docker.com/compose/install/
+
+To run the integration tests:
+
+    mvn clean install
+    # The first time you need to set everything up
+    docker-compose up -d
+    # Later runs only need the containers to be started
+    docker-compose start
+    # OSX
+    mvn verify -Pintegrationtest -Dovsdbserver.ipaddress=$(boot2docker ip 2>/dev/null) -Dovsdbserver.port=6640
+    # Linux
+    mvn verify -Pintegrationtest -Dovsdbserver.ipaddress=127.0.0.1 -Dovsdbserver.port=6640 -Dovsdb.controller.address=<addr of docker interface> -Dovsdb.userspace.enabled=yes
+    docker-compose stop
+
+On Linux you'll generally need to run fig as root (sudo fig ...).
+
+Running the docker image manually:
+    sudo docker run -itd --cap-add NET_ADMIN -p 6640:6640 jhershbe/centos7-ovs:latest
+
+Skipping unit tests and karaf tests
+====================
+
+mvn clean install -Dmaven.test.skip=true -Dskip.karaf=true
diff --git a/README.Vagrant b/README.Vagrant
new file mode 100644 (file)
index 0000000..bc44a8c
--- /dev/null
@@ -0,0 +1,70 @@
+ODL OVSDB Vagrant
+=================
+
+# Installation
+
+You can download an install for your system from [here](http://www.vagrantup.com/downloads.html)
+
+# Usage
+
+Vagrant is a tool for creating development/test environments.
+The environment created for this project is as follows:
+
+1 x DevStack Control/Compute VM
+1-3 x DevStack Compute VM
+1 x Mininet VM
+
+It's assumed you already have an OVSDB development environment set up.
+
+1. Run `mvn clean install`
+2. Run `vagrant up`
+3. Start the controller (in distirbution/target/opendaylight/...)
+
+> Note: It's assumed that the subnet 192.168.50.x/24 is not in use
+> Your PC is 192.168.50.1. If you would like to change the addressing,
+> you will need to edit the Vagrantfile and hosts.json
+
+Follow the instructions below for Devstack and Mininet
+
+## DevStack VMs
+
+There are two DevStack VMs. One combined control/compute node and a variable number of dedicated compute nodes.
+The following steps are performed when the VM is created or when `vagrant provision` is run.
+
+- Check dependencies are installed
+- Clone the devstack repository to `devstack`
+- Generate a `local.conf` file
+
+To start DevStack
+
+    vagrant ssh devstack-control
+    # or vagrant ssh devstack-compute
+    cd devstack
+    ./stack.sh
+
+> Note: To start more than one compute node
+>       export DEVSTACK_NUM_COMPUTE_NODES=3
+>       vagrant up
+
+## Mininet
+
+There is a single VM provided for running mininet.
+This is for testing that does not require OpenStack Neutron.
+
+The following steps are performed when the VM is created or when `vagrant provision` is run.
+- Check dependencies are installed
+- Clone the mininet repository
+- Install mininet and Open vSwitch
+
+To start Mininet
+
+    vagrant ssh mininet
+    sudo mn
+
+# Port Forwarding
+
+The following ports are forwarded:
+
+localhost:8080 -> opendaylight:8080
+localhost:8000 -> opendaylight:8000
+localhost:8081 -> devstack-control:8080
diff --git a/Vagrantfile b/Vagrantfile
new file mode 100644 (file)
index 0000000..7d43bcb
--- /dev/null
@@ -0,0 +1,73 @@
+# 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|
+
+  config.vm.box = "trusty64"
+  config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-14.04_chef-provisionerless.box"
+  config.vm.provider "vmware_fusion" do |v, override|
+      override.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/vmware/opscode_ubuntu-14.04_chef-provisionerless.box"
+  end
+
+  config.vm.provision "shell", path: "resources/puppet/scripts/bootstrap.sh"
+
+  config.vm.provision "puppet" do |puppet|
+      puppet.hiera_config_path = "resources/puppet/hiera.yaml"
+      puppet.working_directory = "/vagrant/resources/puppet"
+      puppet.manifests_path = "resources/puppet/manifests"
+      puppet.manifest_file  = "base.pp"
+  end
+
+  num_compute_nodes = (ENV['DEVSTACK_NUM_COMPUTE_NODES'] || 1).to_i
+
+  # ip configuration
+  control_ip = "192.168.50.20"
+  compute_ip_base = "192.168.50."
+  compute_ips = num_compute_nodes.times.collect { |n| compute_ip_base + "#{n+21}" }
+
+  config.vm.define "devstack-control" do |control|
+    control.vm.hostname = "devstack-control"
+    control.vm.network "private_network", ip: "#{control_ip}"
+    control.vm.network "forwarded_port", guest: 8080, host: 8081
+    control.vm.provider :virtualbox do |vb|
+      vb.memory = 4096
+    end
+    control.vm.provider "vmware_fusion" do |vf|
+      vf.vmx["memsize"] = "4096"
+    end
+    control.vm.provider :libvirt do |lv|
+      lv.memory = 4096
+    end
+    control.vm.provision "puppet" do |puppet|
+      puppet.hiera_config_path = "resources/puppet/hiera.yaml"
+      puppet.working_directory = "/vagrant/resources/puppet"
+      puppet.manifests_path = "resources/puppet/manifests"
+      puppet.manifest_file  = "devstack-control.pp"
+    end
+  end
+
+  # Devstack Compute Nodes
+  num_compute_nodes.times do |n|
+    config.vm.define "devstack-compute-#{n+1}" do |compute|
+      compute_ip = compute_ips[n]
+      compute_index = n+1
+      compute.vm.hostname = "devstack-compute-#{compute_index}"
+      compute.vm.network "private_network", ip: "#{compute_ip}"
+      compute.vm.provider :virtualbox do |vb|
+        vb.memory = 4096
+      end
+      compute.vm.provider "vmware_fusion" do |vf|
+        vf.vmx["memsize"] = "4096"
+      end
+      compute.vm.provider :libvirt do |lv|
+        lv.memory = 4096
+      end
+      compute.vm.provision "puppet" do |puppet|
+        puppet.hiera_config_path = "resources/puppet/hiera.yaml"
+        puppet.working_directory = "/vagrant/resources/puppet"
+        puppet.manifests_path = "resources/puppet/manifests"
+        puppet.manifest_file  = "devstack-compute.pp"
+      end
+    end
+  end
+end
diff --git a/commons/it/pom.xml b/commons/it/pom.xml
new file mode 100644 (file)
index 0000000..9c38c58
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>mdsal-it-parent</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>it</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+
+  <profiles>
+    <profile>
+      <id>default</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <properties>
+        <skipITs>true</skipITs>
+      </properties>
+    </profile>
+    <profile>
+      <id>integrationtest</id>
+      <activation>
+        <activeByDefault>false</activeByDefault>
+      </activation>
+      <properties>
+        <skipITs>false</skipITs>
+      </properties>
+    </profile>
+  </profiles>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.codehaus.sonar-plugins.java</groupId>
+        <artifactId>sonar-jacoco-listeners</artifactId>
+        <version>${sonar-jacoco-listeners.version}</version>
+        <scope>test</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <configuration>
+          <properties>
+            <property>
+              <name>listener</name>
+              <value>org.sonar.java.jacoco.JUnitListener</value>
+            </property>
+          </properties>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>prep-jacoco-agent</id>
+            <phase>pre-integration-test</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <copy file="${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar"
+                      tofile="target/exam/jars/org.jacoco.agent.jar" />
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/commons/pom.xml b/commons/pom.xml
new file mode 100644 (file)
index 0000000..ac135f1
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>parents</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <packaging>pom</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>it</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644 (file)
index 0000000..08dc273
--- /dev/null
@@ -0,0 +1,6 @@
+ovs:
+ image: jhershbe/centos7-ovs:2.5.1
+ ports:
+   - "6640:6640"
+ command: "/usr/bin/supervisord -n"
+ privileged: true
index dff7cecd96dccbdcfce70a34d7fdb78fc6974cfc..519060f095e2d78c93a32b167197a4c4cea19431 100644 (file)
@@ -1,85 +1,68 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+Copyright (C) 2014 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 INTERNAL
+and is available at http://www.eclipse.org/legal/epl-v10.html
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
   <parent>
     <groupId>org.opendaylight.odlparent</groupId>
     <artifactId>features-parent</artifactId>
     <version>1.7.0-SNAPSHOT</version>
     <relativePath/>
   </parent>
-  <groupId>org.opendaylight.vpnservice</groupId>
-  <artifactId>vpnservice-features</artifactId>
-  <version>0.3.0-SNAPSHOT</version>
-  <name>${project.artifactId}</name>
-  <modelVersion>4.0.0</modelVersion>
-  <prerequisites>
-    <maven>3.1.1</maven>
-  </prerequisites>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>features-netvirt</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
   <properties>
-    <mdsal.version>1.4.0-SNAPSHOT</mdsal.version>
+    <dlux.version>0.4.0-SNAPSHOT</dlux.version>
+    <controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
+    <mdsal.model.version>0.9.0-SNAPSHOT</mdsal.model.version>
+    <neutron.version>0.7.0-SNAPSHOT</neutron.version>
+    <odl.karaf.base.version>1.7.0-SNAPSHOT</odl.karaf.base.version>
     <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
     <restconf.version>1.4.0-SNAPSHOT</restconf.version>
     <yangtools.version>1.0.0-SNAPSHOT</yangtools.version>
-    <mdsal.model.version>0.9.0-SNAPSHOT</mdsal.model.version>
-    <vpnservices.version>0.3.0-SNAPSHOT</vpnservices.version>
-    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
-    <liblldp.version>0.11.0-SNAPSHOT</liblldp.version>
-    <neutron.version>0.7.0-SNAPSHOT</neutron.version>
-    <nic.version>1.2.0-SNAPSHOT</nic.version>
-    <arputil.version>${vpnservices.version}</arputil.version>
-    <mdsalutil.version>${vpnservices.version}</mdsalutil.version>
-    <vpnmanager.version>${vpnservices.version}</vpnmanager.version>
-    <interfacemgr.version>${vpnservices.version}</interfacemgr.version>
-    <elanmgr.version>${vpnservices.version}</elanmgr.version>
-    <nexthopmgr.version>${vpnservices.version}</nexthopmgr.version>
-    <fibmanager.version>${vpnservices.version}</fibmanager.version>
-    <lockmanager.version>${vpnservices.version}</lockmanager.version>
-    <idmanager.version>${vpnservices.version}</idmanager.version>
-    <itm.version>${vpnservices.version}</itm.version>
-    <neutronvpn.version>${vpnservices.version}</neutronvpn.version>
-    <fcaps.manager.version>${vpnservices.version}</fcaps.manager.version>
-    <fcaps.app.version>${vpnservices.version}</fcaps.app.version>
   </properties>
-  <dependencyManagement>
-    <dependencies>
-      <!-- project specific dependencies -->
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>mdsal-artifacts</artifactId>
-        <version>${mdsal.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-      <dependency>
-        <groupId>org.opendaylight.netconf</groupId>
-        <artifactId>restconf-artifacts</artifactId>
-        <version>${restconf.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-    </dependencies>
-  </dependencyManagement>
+
   <dependencies>
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>features-yangtools</artifactId>
-      <classifier>features</classifier>
-      <version>${yangtools.version}</version>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>features-mdsal</artifactId>
-      <classifier>features</classifier>
-      <version>${mdsal.version}</version>
+      <version>${controller.mdsal.version}</version>
       <type>xml</type>
-      <scope>runtime</scope>
+      <classifier>features</classifier>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.mdsal.model</groupId>
@@ -87,382 +70,217 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <version>${mdsal.model.version}</version>
       <classifier>features</classifier>
       <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.nic</groupId>
-      <artifactId>features-nic</artifactId>
-      <classifier>features</classifier>
-      <version>${nic.version}</version>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.ovsdb</groupId>
-      <artifactId>southbound-features</artifactId>
-      <version>${ovsdb.version}</version>
-      <classifier>features</classifier>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.ovsdb</groupId>
-      <artifactId>hwvtepsouthbound-features</artifactId>
-      <version>${ovsdb.version}</version>
-      <classifier>features</classifier>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.openflowplugin</groupId>
-      <artifactId>features-openflowplugin</artifactId>
-      <classifier>features</classifier>
-      <version>${openflowplugin.version}</version>
-      <type>xml</type>
-      <scope>runtime</scope>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.netconf</groupId>
       <artifactId>features-restconf</artifactId>
-      <classifier>features</classifier>
       <version>${restconf.version}</version>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.neutron</groupId>
-      <artifactId>features-neutron</artifactId>
       <classifier>features</classifier>
-      <version>${neutron.version}</version>
       <type>xml</type>
-      <scope>runtime</scope>
     </dependency>
+    <!-- TODO clean up based on what is provided by odlparent -->
     <dependency>
-      <groupId>org.opendaylight.neutron</groupId>
-      <artifactId>dummyprovider</artifactId>
-      <version>${neutron.version}</version>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>vpnmanager-impl</artifactId>
-      <version>${vpnmanager.version}</version>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>vpnmanager-impl</artifactId>
-      <version>${vpnmanager.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>mdsalutil-impl</artifactId>
-      <version>${mdsalutil.version}</version>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-annotations</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>arputil-api</artifactId>
-      <version>${arputil.version}</version>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>arputil-impl</artifactId>
-      <version>${arputil.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
-    </dependency>
-     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>arputil-impl</artifactId>
-      <version>${arputil.version}</version>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>mdsalutil-impl</artifactId>
-      <version>${mdsalutil.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>mdsalutil-api</artifactId>
-      <version>${mdsalutil.version}</version>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>interfacemgr-impl</artifactId>
-      <version>${interfacemgr.version}</version>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>interfacemgr-impl</artifactId>
-      <version>${interfacemgr.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>interfacemgr-api</artifactId>
-      <version>${interfacemgr.version}</version>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>interfacemgr-shell</artifactId>
-      <version>${interfacemgr.version}</version>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>elanmanager-impl</artifactId>
-      <version>${elanmgr.version}</version>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-common</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>elanmanager-impl</artifactId>
-      <version>${elanmgr.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>elanmanager-api</artifactId>
-      <version>${elanmgr.version}</version>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-handler</artifactId>
     </dependency>
     <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>liblldp</artifactId>
-        <version>${liblldp.version}</version>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>alivenessmonitor-impl</artifactId>
-      <version>${vpnservices.version}</version>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>alivenessmonitor-impl</artifactId>
-      <version>${vpnservices.version}</version>
-      <classifier>config</classifier>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>features-neutron</artifactId>
+      <version>${neutron.version}</version>
+      <classifier>features</classifier>
       <type>xml</type>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>alivenessmonitor-api</artifactId>
-      <version>${vpnservices.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>vpnmanager-api</artifactId>
-      <version>${vpnmanager.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>bgpmanager-impl</artifactId>
-      <version>${vpnservices.version}</version>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>bgpmanager-impl</artifactId>
-      <version>${vpnservices.version}</version>
-      <classifier>config</classifier>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin-extension</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
       <type>xml</type>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>bgpmanager-api</artifactId>
-      <version>${vpnservices.version}</version>
+      <artifactId>openstack.net-virt</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>model-bgp</artifactId>
-      <version>2013.07.15.9-SNAPSHOT</version>
+      <artifactId>openstack.net-virt</artifactId>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>fibmanager-impl</artifactId>
-      <version>${fibmanager.version}</version>
+      <artifactId>openstack.net-virt-providers</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>fibmanager-impl</artifactId>
-      <version>${fibmanager.version}</version>
-      <classifier>config</classifier>
+      <artifactId>openstack.net-virt-providers</artifactId>
+      <version>${project.version}</version>
       <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>fibmanager-shell</artifactId>
-      <version>${fibmanager.version}</version>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>schema.openvswitch</artifactId>
+      <version>${ovsdb.version}</version>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>fibmanager-api</artifactId>
-      <version>${fibmanager.version}</version>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>schema.hardwarevtep</artifactId>
+      <version>${ovsdb.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>lockmanager-impl</artifactId>
-      <version>${lockmanager.version}</version>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>lockmanager-impl</artifactId>
-      <version>${lockmanager.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>lockmanager-api</artifactId>
-      <version>${lockmanager.version}</version>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${ovsdb.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>idmanager-impl</artifactId>
-      <version>${idmanager.version}</version>
+      <artifactId>ovsdb-ui-bundle</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>idmanager-impl</artifactId>
-      <version>${idmanager.version}</version>
-      <classifier>config</classifier>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-features</artifactId>
+      <version>${ovsdb.version}</version>
       <type>xml</type>
+      <classifier>features</classifier>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>idmanager-api</artifactId>
-      <version>${idmanager.version}</version>
+      <artifactId>netvirt-api</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>itm-impl</artifactId>
-      <version>${itm.version}</version>
+      <artifactId>hwgw</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>itm-impl</artifactId>
-      <version>${itm.version}</version>
-      <classifier>config</classifier>
+      <artifactId>hwgw</artifactId>
+      <version>${project.version}</version>
       <type>xml</type>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>itm-api</artifactId>
-      <version>${itm.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>dhcpservice-impl</artifactId>
-      <version>${vpnservices.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>dhcpservice-impl</artifactId>
-      <version>${vpnservices.version}</version>
       <classifier>config</classifier>
-      <type>xml</type>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>dhcpservice-api</artifactId>
-      <version>${vpnservices.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>natservice-impl</artifactId>
-      <version>${vpnservices.version}</version>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>natservice-impl</artifactId>
-      <version>${vpnservices.version}</version>
-      <classifier>config</classifier>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>hwvtepsouthbound-features</artifactId>
+      <version>${ovsdb.version}</version>
       <type>xml</type>
+      <classifier>features</classifier>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>natservice-api</artifactId>
-      <version>${vpnservices.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>neutronvpn-api</artifactId>
-      <version>${neutronvpn.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>neutronvpn-impl</artifactId>
-      <version>${neutronvpn.version}</version>
+      <artifactId>neutron</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>neutronvpn-impl</artifactId>
-      <version>${neutronvpn.version}</version>
-      <classifier>config</classifier>
+      <artifactId>neutron</artifactId>
+      <version>${project.version}</version>
       <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>neutronvpn-shell</artifactId>
-      <version>${neutronvpn.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.thrift</groupId>
-      <artifactId>libthrift</artifactId>
-      <version>0.9.1</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.openflowplugin</groupId>
-      <artifactId>features-openflowplugin-extension</artifactId>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>features-dlux</artifactId>
+      <version>${dlux.version}</version>
       <classifier>features</classifier>
-      <version>${openflowplugin.version}</version>
       <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>commons-net</groupId>
-      <artifactId>commons-net</artifactId>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>vpnintent-api</artifactId>
-      <version>${vpnservices.version}</version>
+      <artifactId>utils.netvirt-it-utils</artifactId>
+      <version>${project.version}</version>
+      <!--<scope>test</scope>-->
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>vpnintent-impl</artifactId>
-      <version>${vpnservices.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>vpnintent-impl</artifactId>
-      <version>${vpnservices.version}</version>
-      <classifier>config</classifier>
-      <type>xml</type>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>alarmmanager</artifactId>
-      <version>${fcaps.manager.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>countermanager</artifactId>
-      <version>${fcaps.manager.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>fcaps-api</artifactId>
-      <version>${fcaps.manager.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>fcapsapplication-jmxapi</artifactId>
-      <version>${fcaps.app.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>fcapsapplication-impl</artifactId>
-      <version>${fcaps.app.version}</version>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.ovsdb-it-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <!--<scope>test</scope>-->
     </dependency>
   </dependencies>
 </project>
index ead3c81814dd458bde9a2f0ab5416196e7776f49..752f8e6ded03962fb650a011584c59f29a86066a 100644 (file)
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
-Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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
--->
-<features name="odl-vpnservice-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
-  <repository>mvn:org.opendaylight.yangtools/features-yangtools/{{VERSION}}/xml/features</repository>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<features name="ovsdb-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
   <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.dlux/features-dlux/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/{{VERSION}}/xml/features</repository>
-  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/{{VERSION}}/xml/features</repository>
-  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.netconf/features-restconf/{{VERSION}}/xml/features</repository>
-  <repository>mvn:org.opendaylight.ovsdb/southbound-features/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.neutron/features-neutron/{{VERSION}}/xml/features</repository>
-  <repository>mvn:org.opendaylight.nic/features-nic/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.ovsdb/hwvtepsouthbound-features/{{VERSION}}/xml/features</repository>
-  <feature name='odl-vpnservice-api' version='${project.version}' description='OpenDaylight :: vpnservice :: api '>
-    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
-    <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
-    <feature version='${openflowplugin.version}'>odl-openflowplugin-nsf-model</feature>
-    <feature version="${openflowplugin.version}">odl-openflowplugin-nxm-extensions</feature>
-    <feature version="${ovsdb.version}">odl-ovsdb-southbound-impl-rest</feature>
-    <feature version='${ovsdb.version}'>odl-ovsdb-hwvtepsouthbound-api</feature>
-    <bundle>mvn:org.opendaylight.controller/liblldp/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.neutron/model/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/model-bgp/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/lockmanager-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/idmanager-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/arputil-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/alivenessmonitor-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/fibmanager-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/itm-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/neutronvpn-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/dhcpservice-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/natservice-api/{{VERSION}}</bundle>
-  </feature>
-  <feature name='odl-vpnservice-impl' version='${project.version}' description='OpenDaylight :: vpnservice :: impl '>
-    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
-    <feature version="${ovsdb.version}">odl-ovsdb-southbound-impl-rest</feature>
-    <feature version='${ovsdb.version}'>odl-ovsdb-hwvtepsouthbound</feature>
-    <feature version='${project.version}'>odl-vpnservice-api</feature>
+  <repository>mvn:org.opendaylight.ovsdb/southbound-features/{{VERSION}}/xml/features</repository>
+
+  <feature name="odl-ovsdb-openstack" description="OpenDaylight :: OVSDB :: OpenStack Network Virtualization"
+           version='${project.version}'>
+    <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-model</feature>
+    <feature version="${neutron.version}">odl-neutron-service</feature>
+    <feature version="${ovsdb.version}">odl-ovsdb-southbound-impl-ui</feature>
     <feature version="${openflowplugin.version}">odl-openflowplugin-southbound</feature>
-    <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-services</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nxm-extensions</feature>
+    <bundle>mvn:org.opendaylight.netvirt/utils.servicehelper/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.neutron-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/openstack.net-virt/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/openstack.net-virt-providers/{{VERSION}}</bundle>
     <bundle>mvn:commons-net/commons-net/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/lockmanager-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/idmanager-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/arputil-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-shell/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/fibmanager-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/fibmanager-shell/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/itm-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/neutronvpn-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/neutronvpn-shell/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/dhcpservice-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/elanmanager-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/elanmanager-impl/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/natservice-impl/{{VERSION}}</bundle>
+    <configfile finalname="etc/opendaylight/karaf/netvirt-impl-default-config.xml">mvn:org.opendaylight.netvirt/openstack.net-virt/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="etc/opendaylight/karaf/netvirt-providers-impl-default-config.xml">mvn:org.opendaylight.netvirt/openstack.net-virt-providers/{{VERSION}}/xml/config</configfile>
+  </feature>
 
-    <!--<bundle>mvn:org.opendaylight.vpnservice.third-party/org.apache.thriftlib/1.1.0-SNAPSHOT</bundle>-->
-    <bundle>wrap:mvn:org.apache.thrift/libthrift/0.9.1$overwrite=merge&amp;Bundle-Version=0.9.1&amp;Export-Package=*;-noimport:=true;version="0.9.1"</bundle>
-    <!--<bundle>wrap:mvn:javax.servlet/servlet-api/2.5</bundle>-->
-    <configfile finalname="lockmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/lockmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="idmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/idmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="idmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/idmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="bgpmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/bgpmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="mdsalutil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/mdsalutil-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="interfacemgr-impl-default-config.xml">mvn:org.opendaylight.vpnservice/interfacemgr-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="arputil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/arputil-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="alivenessmonitor-impl-default-config.xml">mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="vpnmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/vpnmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="fibmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/fibmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="itm-impl-default-config.xml">mvn:org.opendaylight.vpnservice/itm-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="neutronvpn-impl-default-config.xml">mvn:org.opendaylight.vpnservice/neutronvpn-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="dhcpservice-impl-default-config.xml">mvn:org.opendaylight.vpnservice/dhcpservice-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="elanmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/elanmanager-impl/{{VERSION}}/xml/config</configfile>
-    <configfile finalname="natservice-impl-default-config.xml">mvn:org.opendaylight.vpnservice/natservice-impl/{{VERSION}}/xml/config</configfile>
+  <feature name="odl-ovsdb-openstack-it" description="OpenDaylight :: OVSDB :: OpenStack Network Virtualization IT"
+           version='${project.version}'>
+    <feature version="${project.version}">odl-ovsdb-openstack</feature>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.ovsdb-it-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.netvirt-it-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.neutron-utils/{{VERSION}}</bundle>
+  </feature>
+
+  <feature name="odl-ovsdb-ui" description="OpenDaylight :: OVSDB :: DLUX Integration Plugin" version='${project.version}'>
+    <feature version="${dlux.version}">odl-dlux-core</feature>
+    <bundle>mvn:org.opendaylight.netvirt/ovsdb-ui-bundle/{{VERSION}}</bundle>
+  </feature>
 
+  <feature name='odl-netvirt-api' version='${project.version}' description='OpenDaylight :: netvirt :: api'>
+    <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
+    <bundle>mvn:org.opendaylight.netvirt/netvirt-api/{{VERSION}}</bundle>
   </feature>
-  <feature name='odl-vpnservice-impl-rest' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: REST '>
-    <feature version="${project.version}">odl-vpnservice-impl</feature>
+
+  <feature name='odl-netvirt-rest' version='${project.version}' description='OpenDaylight :: netvirt :: REST'>
+    <feature version="${project.version}">odl-netvirt-api</feature>
     <feature version="${restconf.version}">odl-restconf</feature>
   </feature>
-  <feature name='odl-vpnservice-impl-ui' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: UI'>
-    <feature version="${project.version}">odl-vpnservice-impl-rest</feature>
+
+  <feature name='odl-netvirt-ui' version='${project.version}' description='OpenDaylight :: netvirt :: UI'>
+    <feature version="${project.version}">odl-netvirt-rest</feature>
     <feature version="${restconf.version}">odl-mdsal-apidocs</feature>
-    <feature version="${mdsal.version}">odl-mdsal-xsql</feature>
+    <feature version="${controller.mdsal.version}">odl-mdsal-xsql</feature>
   </feature>
-  <feature name='odl-vpnservice-core' version='${project.version}' description='OpenDaylight :: vpnservice :: core'>
-    <feature version="${neutron.version}">odl-neutron-service</feature>
-    <bundle>mvn:org.opendaylight.neutron/dummyprovider/{{VERSION}}</bundle>
-    <feature version="${project.version}">odl-vpnservice-impl-ui</feature>
+
+  <feature name='odl-netvirt-hwgw' version='${project.version}' description='OpenDaylight :: netvirt :: Hardware Gateway'>
+    <feature version="${project.version}">odl-netvirt-api</feature>
+    <feature version='${ovsdb.version}'>odl-ovsdb-hwvtepsouthbound</feature>
+    <bundle>mvn:org.opendaylight.netvirt/hwgw/{{VERSION}}</bundle>
+    <configfile finalname="etc/opendaylight/karaf/hwgw-default-config.xml">mvn:org.opendaylight.netvirt/hwgw/{{VERSION}}/xml/config</configfile>
   </feature>
-  <feature name='odl-vpnservice-openstack' version='${project.version}' description='OpenDaylight :: vpnservice :: openstack'>
+
+  <feature name='odl-netvirt-neutron' version='${project.version}' description='OpenDaylight :: netvirt :: Neutron Renderer'>
+    <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
     <feature version="${neutron.version}">odl-neutron-service</feature>
-    <bundle>mvn:org.opendaylight.neutron/dummyprovider/{{VERSION}}</bundle>
-    <feature version="${project.version}">odl-vpnservice-impl-rest</feature>
-  </feature>
-  <feature name='odl-vpnservice-intent' version='${project.version}' description='OpenDaylight :: vpnservice :: intent'>
-    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
-    <feature version='${nic.version}'>odl-nic-listeners</feature>
-    <bundle>mvn:org.opendaylight.vpnservice/vpnintent-api/{{VERSION}}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}</bundle>
-    <configfile finalname="vpnintent-impl-default-config.xml">mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}/xml/config</configfile>
-  </feature>
-  <feature name='odl-fcaps-framework' version='${project.version}' description='OpenDaylight :: fcapsframework'>
-    <bundle>mvn:org.opendaylight.vpnservice/fcaps-api/${fcaps.manager.version}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/alarmmanager/${fcaps.manager.version}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/countermanager/${fcaps.manager.version}</bundle>
+    <feature version="${project.version}">odl-netvirt-ui</feature>
+    <bundle>mvn:org.opendaylight.netvirt/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/neutron/{{VERSION}}</bundle>
+    <configfile finalname="etc/opendaylight/karaf/netvirt-neutron-default-config.xml">mvn:org.opendaylight.netvirt/neutron/{{VERSION}}/xml/config</configfile>
   </feature>
-  <feature name='odl-fcaps-application' version='${project.version}' description='OpenDaylight :: fcapsapp'>
-    <feature version="${openflowplugin.version}">odl-openflowplugin-all</feature>
-    <bundle>mvn:org.opendaylight.vpnservice/fcapsapplication-jmxapi/${fcaps.app.version}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/fcapsapplication-impl/${fcaps.app.version}</bundle>
-    <configfile finalname="etc/opendaylight/karaf/73-fcaps-app.xml">mvn:org.opendaylight.vpnservice/fcapsapplication-impl/${fcaps.app.version}/xml/config    </configfile>
+
+  <feature name='odl-netvirt-it' version='${project.version}' description='OpenDaylight :: netvirt :: IT'>
+    <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version="${neutron.version}">odl-neutron-service</feature>
+    <feature version="${project.version}">odl-netvirt-neutron</feature>
+    <feature version="${ovsdb.version}">odl-ovsdb-southbound-api</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-model</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nxm-extensions</feature>
+    <bundle>mvn:org.opendaylight.netvirt/utils.servicehelper/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.neutron-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.netvirt-it-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.neutron-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
   </feature>
-  </features>
+</features>
diff --git a/karaf/pom.xml b/karaf/pom.xml
new file mode 100644 (file)
index 0000000..3d70ae6
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>karaf-parent</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>karaf</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <properties>
+    <!-- uncomment the next line if you want karaf to automatically load the feature -->
+    <!-- <karaf.localFeature>odl-ovsdb-openstack</karaf.localFeature> -->
+  </properties>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>netvirt-artifacts</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <!-- scope is compile so all features (there is only one) are installed
+      into startup.properties and the feature repo itself is not installed -->
+      <groupId>org.apache.karaf.features</groupId>
+      <artifactId>framework</artifactId>
+      <type>kar</type>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>features-netvirt</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <!-- DO NOT deploy the karaf artifact -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/netvirt-artifacts/pom.xml b/netvirt-artifacts/pom.xml
new file mode 100644 (file)
index 0000000..9db829e
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>netvirt-artifacts</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>features-netvirt</artifactId>
+        <version>${project.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+</project>
diff --git a/netvirt/api/pom.xml b/netvirt/api/pom.xml
new file mode 100644 (file)
index 0000000..d3faad4
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.mdsal</groupId>
+    <artifactId>binding-parent</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>opendaylight-l2-types</artifactId>
+    </dependency>
+  </dependencies>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>netvirt-api</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.yang.gen.v1.*,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.*,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.common.rev151227,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.devices.rev151227,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.port,
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/netvirt/api/src/main/yang/netvirt-common.yang b/netvirt/api/src/main/yang/netvirt-common.yang
new file mode 100644 (file)
index 0000000..e727e8e
--- /dev/null
@@ -0,0 +1,105 @@
+module netvirt-common {
+    yang-version 1;
+    namespace "urn:opendaylight:netvirt:common";
+    prefix "common";
+
+    revision "2015-12-27" {
+        description "Initial revision of netvirt common attributes";
+    }
+
+    import ietf-yang-types { prefix yang; }
+
+    identity network-type-base {
+        description "Base network type";
+    }
+
+    identity network-type-flat {
+        base network-type-base;
+        description "network type flat";
+    }
+
+    identity network-type-gre {
+        base network-type-base;
+        description "network type gre";
+    }
+
+    identity network-type-vlan {
+        base network-type-base;
+        description "network type vlan";
+    }
+
+    identity network-type-vxlan {
+        base network-type-base;
+        description "network type vxlan";
+    }
+
+    identity network-type-vxlan-gpe {
+        base network-type-base;
+        description "network type vxlan-gpe";
+    }
+
+    typedef network-type {
+        type identityref {
+            base network-type-base;
+        }
+        description "This type is used to refer to a network Type.";
+    }
+
+    grouping base-attributes {
+        leaf uuid {
+            type yang:uuid;
+            description "UUID to index this object.";
+        }
+
+        leaf name {
+            type string;
+            description "Optional human-readable name for the item. Might not be unique.";
+        }
+
+        leaf description {
+            type string;
+            description "Optional human-readable description for the item. Might not be unique.";
+        }
+
+        list other-config {
+            description "This is used to store information needed by the renderer(s).  In general,
+                         it might be used as a cookie to relate external objects or configuration with
+                         the given NetVirt object.  For example, we may store neutron logical port
+                         information here so that the OVS southbound renderer can match up the port
+                         reported by OVSDB with the Neutron port configured by Neutron.";
+            key config-key;
+            leaf config-key {
+                description "Key to identify the piece of config info.
+                             This needs to be unique both within and between renderers.
+                             Format: <renderer-name>:<renderer-unique-key>";
+                type string;
+            }
+            leaf config-value {
+                type string;
+            }
+        }
+    }
+
+    grouping admin-attributes {
+        leaf admin-state-up {
+            type boolean;
+            description "The administrative state of the object, which is up (true) or down (false).";
+        }
+        leaf status {
+            type string;
+            description "The object status.";
+        }
+    }
+
+    grouping device-locator-ref {
+        leaf device-uuid {
+            type yang:uuid;
+            description "Reference to the the device for this port";
+        }
+
+        leaf device-locator-uuid {
+            type yang:uuid;
+            description "Reference to the the device locator for this port";
+        }
+    }
+}
diff --git a/netvirt/api/src/main/yang/netvirt-devices.yang b/netvirt/api/src/main/yang/netvirt-devices.yang
new file mode 100644 (file)
index 0000000..2f9bd75
--- /dev/null
@@ -0,0 +1,105 @@
+module netvirt-devices {
+    yang-version 1;
+    namespace "urn:opendaylight:netvirt:devices";
+    prefix "devices";
+
+    revision "2015-12-27" {
+        description "Initial revision of netvirt devices definition";
+    }
+
+    import ietf-yang-types { prefix yang; }
+    import ietf-inet-types { prefix inet; }
+    import netvirt-common { prefix "common"; }
+    import opendaylight-l2-types { prefix l2types; }
+
+
+
+    grouping flat-attributes {
+    }
+
+    grouping vlan-attributes {
+    }
+
+    grouping gre-attributes {
+        leaf ip-addr {
+            type inet:ip-address;
+        }
+        leaf port {
+            type inet:port-number;
+        }
+    }
+
+    grouping vxlan-attributes {
+        leaf ip-addr {
+            type inet:ip-address;
+        }
+        leaf port {
+            type inet:port-number;
+        }
+    }
+
+    grouping vxlan-gpe-attributes {
+        leaf ip-addr {
+            type inet:ip-address;
+        }
+        leaf port {
+            type inet:port-number;
+        }
+    }
+
+    grouping device-locator {
+        uses common:base-attributes;
+
+        leaf locator-type {
+            type common:network-type;
+        }
+
+        choice locator-attr {
+            case flat {
+                uses flat-attributes;
+            }
+            case vlan {
+                uses vlan-attributes;
+            }
+            case gre {
+                uses gre-attributes;
+            }
+            case vxlan {
+                uses vxlan-attributes;
+            }
+            case vxlan-gpe {
+                uses vxlan-gpe-attributes;
+            }
+        }
+    }
+
+    grouping device {
+        uses common:base-attributes;
+
+        leaf device-type {
+            type enumeration {
+                 enum ovs;
+                 enum hwgw;
+             }
+        }
+
+        // TODO: Need to look at info needed per bridge.
+        list bridges {
+            leaf name {
+                type string;
+            }
+        }
+
+        list device-locators {
+            key uuid;
+            uses device-locator;
+        }
+    }
+
+    container devices {
+        list device {
+            key uuid;
+            uses device;
+        }
+    }
+}
diff --git a/netvirt/api/src/main/yang/netvirt-l2-networks.yang b/netvirt/api/src/main/yang/netvirt-l2-networks.yang
new file mode 100644 (file)
index 0000000..2d92742
--- /dev/null
@@ -0,0 +1,53 @@
+module netvirt-l2-networks {
+    yang-version 1;
+    namespace "urn:opendaylight:netvirt:l2-networks";
+    prefix "l2-networks";
+
+    revision "2015-12-27" {
+        description "Initial revision of netvirt l2-networks definition";
+    }
+
+    import ietf-inet-types { prefix inet; revision-date 2010-09-24; }
+    import ietf-yang-types { prefix yang; }
+    import netvirt-common { prefix "common"; }
+
+    container l2-networks {
+        list l2-network {
+            uses common:base-attributes;
+            uses common:admin-attributes;
+
+            description "Description: Logical Layer 2 Networks.  E.g., a Neutron Network.  Typically, an l2-network
+                         defines an L2 broadcast domain and, unless otherwise prohibited, endpoints attached to ports
+                         on an l2-network can communicate with each other.  All l2-network are independent, and
+                         communication between l2-network is only allowed via other means, such as through an
+                         l3-router.";
+
+            key uuid;
+
+            leaf network-type {
+                type common:network-type;
+                description "The type of physical network that maps to this network resource.";
+            }
+
+            leaf segmentation-id {
+                type string;
+                description "An isolated segment on the physical network. The network-type
+                            attribute defines the segmentation model. For example, if network-type
+                            is vlan, this ID is a vlan identifier. If network-type is gre,
+                            this ID is a gre key.";
+            }
+
+            leaf shared {
+                type boolean;
+                default "false";
+                description "Indicates whether this network or subnet is shared across all
+                            tenants. By default, only administrative users can change this
+                            value.";
+            }
+
+            list device-locators {
+                uses common:device-locator-ref;
+            }
+        }
+    }
+}
diff --git a/netvirt/api/src/main/yang/netvirt-ports.yang b/netvirt/api/src/main/yang/netvirt-ports.yang
new file mode 100644 (file)
index 0000000..3a30abc
--- /dev/null
@@ -0,0 +1,161 @@
+module netvirt-ports {
+    yang-version 1;
+    namespace "urn:opendaylight:netvirt:ports";
+    prefix "ports";
+
+    revision "2015-12-27" {
+        description "Initial revision of netvirt ports definition";
+    }
+
+    import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
+    import ietf-yang-types { prefix yang; revision-date "2013-07-15";}
+    import netvirt-common { prefix "common"; }
+
+
+    identity port-type-base {
+        description "Base port type";
+    }
+
+    identity port-type-l2-network {
+        base port-type-base;
+        description "port type l2-network";
+    }
+
+    identity port-type-router {
+        base port-type-base;
+        description "port type router";
+    }
+
+    identity port-type-router-interface-distributed {
+        base port-type-base;
+        description "port type router interface distributed";
+    }
+
+    identity port-type-router-gateway {
+        base port-type-base;
+        description "port type router gateway";
+    }
+
+    identity port-type-dhcp {
+        base port-type-base;
+        description "port type dhcp";
+    }
+
+    identity port-type-floating-ip {
+        base port-type-base;
+        description "port type floatingip";
+    }
+
+    identity port-type-compute-nova {
+        base port-type-base;
+        description "port type compute nova";
+    }
+
+    typedef port-type {
+        type identityref {
+            base port-type-base;
+        }
+        description "This type is used to refer to an port Type.";
+    }
+
+    identity port-binding-type-base {
+        description "Base port-binding type";
+    }
+
+    identity port-binding-type-vlan {
+        base port-binding-type-base;
+        description "port-binding type vlan";
+    }
+
+    identity port-binding-type-vxlan {
+        base port-binding-type-base;
+        description "port-binding type vxlan";
+    }
+
+    typedef port-binding-type {
+        type identityref {
+            base port-binding-type-base;
+        }
+        description "The port binding is used to bind one port to another in a hierarchical.";
+    }
+
+    grouping end-point {
+        uses common:base-attributes;
+
+        leaf macaddr {
+            type yang:mac-address;
+            description "MAC address entry";
+        }
+
+        leaf-list ipaddrs {
+            description "Mechanism used to bind ports.";
+            type inet:ip-address;
+        }
+    }
+
+    grouping parent-port-binding {
+        description "Optional. Used to bind one port to another hierarchically.  For example, a port
+                     binding may be used to support multiple containers in a single VM. In this model
+                     each container could use a VLAN-based sub-port on a single tap port.";
+
+        leaf type {
+            description "How is this port bound to the other.  E.g., VLAN";
+            type port-binding-type;
+        }
+
+        leaf id {
+            description "Depends on binding type.  E.g., if the type is VLAN, this would be the VLAN ID";
+            type string;
+        }
+
+        leaf parent-port {
+            description "Must be the UUID of another port.";
+            type yang:uuid;
+        }
+    }
+
+    grouping port {
+        uses common:base-attributes;
+        uses common:admin-attributes;
+
+        leaf port-type {
+            type port-type;
+            description "The type of port.";
+        }
+
+        leaf parent {
+            type yang:uuid;
+            description "The UUID of the object this port is a member of.  For example, if the type is
+                         port-type-l2-network, this will be the UUID of the l2-network";
+        }
+
+        uses parent-port-binding;
+
+        // TODO: Can we use a leafref for the device locator?
+        leaf device-uuid {
+            type yang:uuid;
+            description "Reference to the the device for this port";
+        }
+
+        leaf device-locator-uuid {
+            type yang:uuid;
+            description "Reference to the the device locator for this port";
+        }
+
+        list end-points {
+
+            key macaddr;
+
+            uses end-point;
+        }
+    }
+
+    container ports {
+        list port {
+            description "List of ports.  Each port entry contains both logical and physical information.";
+
+            key uuid;
+            uses port;
+        }
+    }
+}
diff --git a/netvirt/api/src/main/yang/netvirt.yang b/netvirt/api/src/main/yang/netvirt.yang
new file mode 100644 (file)
index 0000000..720f99e
--- /dev/null
@@ -0,0 +1,9 @@
+module netvirt {
+    yang-version 1;
+    namespace "urn:opendaylight:netvirt";
+    prefix "netvirt";
+
+    revision "2015-12-27" {
+        description "Initial revision of netvirt model";
+    }
+}
diff --git a/netvirt/it/pom.xml b/netvirt/it/pom.xml
new file mode 100644 (file)
index 0000000..87b7b27
--- /dev/null
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.netvirt</groupId>
+    <artifactId>it</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath>../../commons/it</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>netvirt-it</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <properties>
+    <controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
+    <karaf.distro.groupId>org.opendaylight.ovsdb</karaf.distro.groupId>
+    <karaf.distro.artifactId>karaf</karaf.distro.artifactId>
+    <karaf.distro.version>${project.version}</karaf.distro.version>
+    <karaf.distro.type>zip</karaf.distro.type>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>features-netvirt</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-api</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.netvirt-it-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.neutron-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.southbound-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar-plugins.java</groupId>
+      <artifactId>sonar-jacoco-listeners</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <configuration>
+        <!--<excludes>
+            <exclude>**/NetvirtIT.java</exclude>
+          </excludes>-->
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/netvirt/it/src/test/java/org/opendaylight/netvirt/netvirt/it/NetvirtIT.java b/netvirt/it/src/test/java/org/opendaylight/netvirt/netvirt/it/NetvirtIT.java
new file mode 100644 (file)
index 0000000..d3e23c7
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * 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.netvirt.it;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.netvirt.utils.netvirt.it.utils.ItConstants;
+import org.opendaylight.netvirt.utils.netvirt.it.utils.NetvirtItUtils;
+import org.opendaylight.netvirt.utils.neutron.utils.NeutronModelsDataStoreHelper;
+import org.opendaylight.netvirt.utils.neutron.utils.NeutronUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.NotifyingDataChangeListener;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+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.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption;
+import org.ops4j.pax.exam.options.MavenUrlReference;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class NetvirtIT extends AbstractMdsalTestBase {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtIT.class);
+    private static final String FEATURE = "odl-netvirt-it";
+    private static DataBroker dataBroker = null;
+    private static NetvirtItUtils itUtils;
+    private static String addressStr;
+    private static String portStr;
+    private static String connectionType;
+    private static String controllerStr;
+    private static AtomicBoolean setup = new AtomicBoolean(false);
+    private static MdsalUtils mdsalUtils = null;
+    private static SouthboundUtils southboundUtils;
+    private static NeutronUtils neutronUtils = new NeutronUtils();
+    private static NeutronModelsDataStoreHelper neutronModelsDataStoreHelper;
+    private static final String NETWORK_TYPE_VXLAN = "vxlan";
+
+    @Override
+    public String getModuleName() {
+        return "netvirt-neutron";
+    }
+
+    @Override
+    public String getInstanceName() { return "netvirt-neutron"; }
+
+    @Override
+    public MavenUrlReference getFeatureRepo() {
+        return maven()
+                .groupId("org.opendaylight.netvirt")
+                .artifactId("features-netvirt")
+                .classifier("features")
+                .type("xml")
+                .versionAsInProject();
+    }
+
+    @Override
+    public String getFeatureName() {
+        return FEATURE;
+    }
+
+    @Configuration
+    @Override
+    public Option[] config() {
+        Option[] parentOptions = super.config();
+        Option[] propertiesOptions = getPropertiesOptions();
+        Option[] otherOptions = getOtherOptions();
+        Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
+        System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
+        System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
+        System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
+                otherOptions.length);
+        return options;
+    }
+
+    private Option[] getOtherOptions() {
+        return new Option[] {
+                wrappedBundle(
+                        mavenBundle("org.opendaylight.netvirt", "utils.mdsal-openflow")
+                                .version(asInProject())
+                                .type("jar")),
+                configureConsole().startLocalConsole(),
+                //vmOption("-verbose:class"),
+                vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
+                keepRuntimeFolder()
+        };
+    }
+
+    private Option[] getPropertiesOptions() {
+        return new Option[] {
+                propagateSystemProperties(ItConstants.SERVER_IPADDRESS, ItConstants.SERVER_PORT,
+                        ItConstants.CONNECTION_TYPE, ItConstants.CONTROLLER_IPADDRESS,
+                        ItConstants.USERSPACE_ENABLED),
+        };
+    }
+
+    @Override
+    public Option getLoggingOption() {
+        return composite(
+                editConfigurationFilePut(ItConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb",
+                        LogLevelOption.LogLevel.TRACE.name()),
+                editConfigurationFilePut(ItConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        logConfiguration(NetvirtIT.class),
+                        LogLevelOption.LogLevel.INFO.name()),
+                editConfigurationFilePut(ItConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.neutron",
+                        LogLevelOption.LogLevel.TRACE.name()),
+                super.getLoggingOption());
+    }
+
+    protected String usage() {
+        return "Integration Test needs a valid connection configuration as follows :\n"
+                + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
+                + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
+    }
+
+    private void getProperties() {
+        Properties props = System.getProperties();
+        addressStr = props.getProperty(ItConstants.SERVER_IPADDRESS);
+        portStr = props.getProperty(ItConstants.SERVER_PORT, ItConstants.DEFAULT_SERVER_PORT);
+        connectionType = props.getProperty(ItConstants.CONNECTION_TYPE, "active");
+        controllerStr = props.getProperty(ItConstants.CONTROLLER_IPADDRESS, "0.0.0.0");
+        String userSpaceEnabled = props.getProperty(ItConstants.USERSPACE_ENABLED, "no");
+        LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
+                        "userspace.enabled: {}",
+                connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
+        if (connectionType.equalsIgnoreCase(ItConstants.CONNECTION_TYPE_ACTIVE)) {
+            if (addressStr == null) {
+                fail(usage());
+            }
+        }
+    }
+
+    @After
+    public void teardown() {
+        closeWaitFors();
+    }
+
+    @Before
+    @Override
+    public void setup() throws InterruptedException {
+        if (setup.get()) {
+            LOG.info("Skipping setUp, already initialized");
+            return;
+        }
+
+        try {
+            super.setup();
+        } catch (Exception e) {
+            LOG.warn("Failed to setup test", e);
+            fail("Failed to setup test: " + e);
+        }
+
+        getProperties();
+
+        if (connectionType.equalsIgnoreCase(ItConstants.CONNECTION_TYPE_ACTIVE)) {
+            if (addressStr == null) {
+                fail(usage());
+            }
+        }
+
+        dataBroker = NetvirtItUtils.getDatabroker(getProviderContext());
+        itUtils = new NetvirtItUtils(dataBroker);
+        mdsalUtils = new MdsalUtils(dataBroker);
+        assertNotNull("mdsalUtils should not be null", mdsalUtils);
+        // TODO: Not used yet since openstack is not running to write the netvirt:1 to mdsal
+        // Only need neutron northbound right now
+        //assertTrue("Did not find " + ItConstants.NETVIRT_TOPOLOGY_ID, itUtils.getNetvirtTopology());
+        southboundUtils = new SouthboundUtils(mdsalUtils);
+        neutronModelsDataStoreHelper = new NeutronModelsDataStoreHelper(dataBroker);
+        setup.set(true);
+    }
+
+    private BindingAwareBroker.ProviderContext getProviderContext() {
+        BindingAwareBroker.ProviderContext providerContext = null;
+        for (int i=0; i < 60; i++) {
+            providerContext = getSession();
+            if (providerContext != null) {
+                break;
+            } else {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.warn("Interrupted while waiting for provider context", e);
+                }
+            }
+        }
+        assertNotNull("providercontext should not be null", providerContext);
+        /* One more second to let the provider finish initialization */
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            LOG.warn("Interrupted while waiting for other provider", e);
+        }
+        return providerContext;
+    }
+
+    @Test
+    public void testNetvirtFeatureLoad() {
+        assertTrue("Feature " + FEATURE + " was not loaded", true);
+    }
+
+    private List<NotifyingDataChangeListener> waitList = new ArrayList<>();
+    private void closeWaitFors() {
+        for (Iterator<NotifyingDataChangeListener> iterator = waitList.iterator(); iterator.hasNext();) {
+            NotifyingDataChangeListener listener = iterator.next();
+            iterator.remove();
+            try {
+                listener.close();
+            } catch (Exception ex) {
+                LOG.warn("Failed to close registration {}", listener, ex);
+            }
+        }
+        LOG.info("waitList size {}", waitList.size());
+    }
+
+    @Test
+    public void testNetvirtNeutron() throws InterruptedException {
+        final String networkId = "521e29d6-67b8-4b3c-8633-027d21195111";
+        final String tenantId = "521e29d6-67b8-4b3c-8633-027d21195100";
+
+        InstanceIdentifier<Network> path = neutronModelsDataStoreHelper.getNeutronNetworkPath(new Uuid(networkId));
+        final NotifyingDataChangeListener networkOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, waitList);
+        networkOperationalListener.registerDataChangeListener(dataBroker);
+
+        NeutronNetwork nn = neutronUtils.createNeutronNetwork(networkId, tenantId,
+                NETWORK_TYPE_VXLAN, "100");
+
+        networkOperationalListener.waitForCreation();
+
+        Network network = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+        assertNotNull("the network was not found in mdsal", network);
+    }
+}
diff --git a/netvirt/pom.xml b/netvirt/pom.xml
new file mode 100644 (file)
index 0000000..d908771
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>netvirt-aggregator</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>netvirt</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>api</module>
+    <module>renderers</module>
+  </modules>
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+</project>
diff --git a/netvirt/renderers/hwgw/pom.xml b/netvirt/renderers/hwgw/pom.xml
new file mode 100644 (file)
index 0000000..cb6e0c7
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>hwgw</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <dependencies>
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/netvirt/renderers/hwgw/src/main/config/default-config.xml b/netvirt/renderers/hwgw/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..c60959c
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright (c) 2015 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
+-->
+<snapshot>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:netvirt:hwgw?module=hwgw&amp;revision=2015-12-27</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+  </required-capabilities>
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:hwgw">prefix:hwgw</type>
+          <name>hwgw-default</name>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/netvirt/renderers/hwgw/src/main/java/org/opendaylight/netvirt/netvirt/renderers/hwgw/HwgwProvider.java b/netvirt/renderers/hwgw/src/main/java/org/opendaylight/netvirt/netvirt/renderers/hwgw/HwgwProvider.java
new file mode 100644 (file)
index 0000000..37dd5ff
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 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.netvirt.renderers.hwgw;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwgwProvider implements BindingAwareProvider, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwgwProvider.class);
+
+    @Override
+    public void onSessionInitiated(ProviderContext session) {
+        LOG.info("HwgwProvider Session Initiated");
+    }
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("HwgwProvider Closed");
+    }
+
+}
diff --git a/netvirt/renderers/hwgw/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModule.java b/netvirt/renderers/hwgw/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModule.java
new file mode 100644 (file)
index 0000000..45a930b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227;
+
+import org.opendaylight.netvirt.netvirt.renderers.hwgw.HwgwProvider;
+
+public class HwgwModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227.AbstractHwgwModule {
+    public HwgwModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public HwgwModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227.HwgwModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        HwgwProvider provider = new HwgwProvider();
+        getBrokerDependency().registerProvider(provider);
+        return provider;
+    }
+
+}
diff --git a/netvirt/renderers/hwgw/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleFactory.java b/netvirt/renderers/hwgw/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleFactory.java
new file mode 100644 (file)
index 0000000..fa1e856
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015 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
+ */
+/*
+* Generated file
+*
+* Generated from: yang module name: hwgw yang module local name: hwgw
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri Jan 02 13:49:24 CST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227;
+public class HwgwModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227.AbstractHwgwModuleFactory {
+
+}
diff --git a/netvirt/renderers/hwgw/src/main/yang/hwgw.yang b/netvirt/renderers/hwgw/src/main/yang/hwgw.yang
new file mode 100644 (file)
index 0000000..22b2f50
--- /dev/null
@@ -0,0 +1,35 @@
+module hwgw {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:hwgw";
+    prefix "hwgw";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+
+    description
+        "Service definition for hwgw project";
+
+    revision "2015-12-27" {
+        description
+            "Initial revision";
+    }
+
+    identity hwgw {
+        base config:module-type;
+        config:java-name-prefix Hwgw;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case hwgw {
+            when "/config:modules/config:module/config:type = 'hwgw'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/netvirt/renderers/hwgw/src/test/java/org/opendaylight/netvirt/netvirt/renderers/hwgw/HwgwProviderTest.java b/netvirt/renderers/hwgw/src/test/java/org/opendaylight/netvirt/netvirt/renderers/hwgw/HwgwProviderTest.java
new file mode 100644 (file)
index 0000000..54ff725
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 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.netvirt.renderers.hwgw;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+
+import static org.mockito.Mockito.mock;
+
+public class HwgwProviderTest {
+    @Test
+    public void testOnSessionInitiated() {
+        HwgwProvider provider = new HwgwProvider();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.onSessionInitiated(mock(BindingAwareBroker.ProviderContext.class));
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        HwgwProvider provider = new HwgwProvider();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.close();
+    }
+}
diff --git a/netvirt/renderers/hwgw/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleFactoryTest.java b/netvirt/renderers/hwgw/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleFactoryTest.java
new file mode 100644 (file)
index 0000000..09e4f71
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227;
+
+import org.junit.Test;
+
+public class HwgwModuleFactoryTest {
+    @Test
+    public void testFactoryConstructor() {
+        // ensure no exceptions on construction
+        new HwgwModuleFactory();
+    }
+}
diff --git a/netvirt/renderers/hwgw/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleTest.java b/netvirt/renderers/hwgw/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/hwgw/rev151227/HwgwModuleTest.java
new file mode 100644 (file)
index 0000000..ade11ef
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.hwgw.rev151227;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.netvirt.netvirt.renderers.hwgw.HwgwProvider;
+
+import javax.management.ObjectName;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class HwgwModuleTest {
+    @Test
+    public void testCustomValidation() {
+        HwgwModule module = new HwgwModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class));
+
+        // ensure no exceptions on validation
+        // currently this method is empty
+        module.customValidation();
+    }
+
+    @Test
+    public void testCreateInstance() throws Exception {
+        // configure mocks
+        DependencyResolver dependencyResolver = mock(DependencyResolver.class);
+        BindingAwareBroker broker = mock(BindingAwareBroker.class);
+        when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
+
+        // create instance of module with injected mocks
+        HwgwModule module = new HwgwModule(mock(ModuleIdentifier.class), dependencyResolver);
+
+        // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+        AutoCloseable closeable = module.getInstance();
+
+        // verify that the module registered the returned provider with the broker
+        verify(broker).registerProvider((HwgwProvider)closeable);
+
+        // ensure no exceptions on close
+        closeable.close();
+    }
+}
diff --git a/netvirt/renderers/neutron/pom.xml b/netvirt/renderers/neutron/pom.xml
new file mode 100644 (file)
index 0000000..16cf1a8
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>neutron</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <neutron.model.version>0.7.0-SNAPSHOT</neutron.model.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>model</artifactId>
+      <version>${neutron.model.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netvirt-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>mdsal-it-base</artifactId>
+      <version>1.4.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/netvirt/renderers/neutron/src/main/config/default-config.xml b/netvirt/renderers/neutron/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..7cb1144
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright (c) 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
+-->
+<snapshot>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:netvirt:neutron?module=netvirt-neutron&amp;revision=2016-03-08</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+  </required-capabilities>
+  <configuration>
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:neutron">prefix:netvirt-neutron</type>
+          <name>netvirt-neutron</name>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/Constants.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/Constants.java
new file mode 100644 (file)
index 0000000..a47ce66
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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.netvirt.renderers.neutron;
+
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableBiMap.Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.common.rev151227.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeComputeNova;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeDhcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeFloatingIp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeRouterGateway;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeRouterInterfaceDistributed;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.PortTypeRouter;
+
+/**
+ * A collection of configuration constants
+ */
+public final class Constants {
+
+    /*
+     * Port owner descriptions used by Openstack Neutron
+     */
+    public static final String OWNER_ROUTER_INTERFACE = "network:router_interface";
+    public static final String OWNER_ROUTER_INTERFACE_DISTRIBUTED = "network:router_interface_distributed";
+    public static final String OWNER_ROUTER_GATEWAY = "network:router_gateway";
+    public static final String OWNER_NETWORK_DHCP = "network:dhcp";
+    public static final String OWNER_FLOATING_IP = "network:floatingip";
+    public static final String OWNER_COMPUTE_NOVA = "compute:nova";
+
+
+    public static final ImmutableBiMap<String, Class<? extends PortTypeBase>> NETVIRT_NEUTRON_PORT_TYPE_MAP
+            = new ImmutableBiMap.Builder<String, Class<? extends PortTypeBase>>()
+            .put(OWNER_ROUTER_INTERFACE, PortTypeRouter.class)
+            .put(OWNER_ROUTER_INTERFACE_DISTRIBUTED, PortTypeRouterInterfaceDistributed.class)
+            .put(OWNER_ROUTER_GATEWAY, PortTypeRouterGateway.class)
+            .put(OWNER_NETWORK_DHCP, PortTypeDhcp.class)
+            .put(OWNER_FLOATING_IP, PortTypeFloatingIp.class)
+            .put(OWNER_COMPUTE_NOVA, PortTypeComputeNova.class)
+            .build();
+
+    /*
+     * Network type descriptions used by Openstack Neutron
+     */
+    public static final String NETWORK_TYPE_FLAT = "NetworkTypeFlat";
+    public static final String NETWORK_TYPE_VLAN = "NetworkTypeVlan";
+    public static final String NETWORK_TYPE_VXLAN = "NetworkTypeVxlan";
+    public static final String NETWORK_TYPE_GRE = "NetworkTypeGre";
+
+    public static final ImmutableBiMap<String, Class<? extends NetworkTypeBase>> NETVIRT_NEUTRON_NETWORK_TYPE_MAP
+            = new ImmutableBiMap.Builder<String, Class<? extends NetworkTypeBase>>()
+            .put(NETWORK_TYPE_FLAT, NetworkTypeFlat.class)
+            .put(NETWORK_TYPE_VLAN, NetworkTypeVlan.class)
+            .put(NETWORK_TYPE_VXLAN, NetworkTypeVxlan.class)
+            .put(NETWORK_TYPE_GRE, NetworkTypeGre.class)
+            .build();
+
+    public static final String NETVIRT_NEUTRON_OWNER_ENTITY_TYPE = "ovsdb-netvirt-neutron-provider";
+
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/DataProcessor.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/DataProcessor.java
new file mode 100644 (file)
index 0000000..72504a9
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 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.netvirt.renderers.neutron;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * netvirt data processor
+ * org.opendaylight.ovsdb.netvirt
+ */
+public interface DataProcessor<D extends DataObject> {
+
+    /**
+     * Method removes DataObject which is identified by InstanceIdentifier.
+     *
+     * @param identifier - the whole path to DataObject
+     * @param del - DataObject for removing
+     */
+    void remove(InstanceIdentifier<D> identifier, D del);
+
+    /**
+     * Method updates the original DataObject to the update DataObject.
+     * Both are identified by same InstanceIdentifier.
+     *
+     * @param identifier - the whole path to DataObject
+     * @param original - original DataObject (for update)
+     * @param update - changed DataObject (contain updates)
+     */
+    void update(InstanceIdentifier<D> identifier, D original, D update);
+
+    /**
+     * Method adds the DataObject which is identified by InstanceIdentifier
+     * to device.
+     *
+     * @param identifier - the whole path to new DataObject
+     * @param add - new DataObject
+     */
+    void add(InstanceIdentifier<D> identifier, D add);
+
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/DelegatingDataTreeListener.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/DelegatingDataTreeListener.java
new file mode 100644 (file)
index 0000000..ec0c05b
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, 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.netvirt.renderers.neutron;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.*;
+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 DataProcessor}.
+ */
+public class DelegatingDataTreeListener<T extends DataObject> implements AutoCloseable, ClusteredDataTreeChangeListener<T> {
+    private static final Logger LOG = LoggerFactory.getLogger(DelegatingDataTreeListener.class);
+    protected NeutronProvider provider;
+    protected DataBroker db;
+    private final ExecutorService executorService = Executors.newFixedThreadPool(1);
+    private final DataProcessor<T> dataProcessor;
+    private ListenerRegistration<DelegatingDataTreeListener<T>> listenerRegistration;
+
+    public DelegatingDataTreeListener(NeutronProvider provider, DataProcessor<T> dataProcessor,
+                                      DataBroker db, DataTreeIdentifier<T> treeId) {
+        this.provider = Preconditions.checkNotNull(provider, "provider can not be null!");
+        this.dataProcessor = Preconditions.checkNotNull(dataProcessor, "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!"));
+    }
+
+    private void registerListener(final DataBroker db, DataTreeIdentifier<T> treeId) {
+        try {
+            LOG.info("Registering Data Change Listener for {}", getClass().getSimpleName());
+            this.db = db;
+            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<DataTreeModification<T>> changes) {
+        for (DataTreeModification<T> change : changes) {
+            final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
+            final DataObjectModification<T> mod = change.getRootNode();
+            switch (mod.getModificationType()) {
+                case DELETE:
+                    dataProcessor.remove(key, mod.getDataBefore());
+                    break;
+                case SUBTREE_MODIFIED:
+                    dataProcessor.update(key, mod.getDataBefore(), mod.getDataAfter());
+                    break;
+                case WRITE:
+                    if (mod.getDataBefore() == null) {
+                        dataProcessor.add(key, mod.getDataAfter());
+                    } else {
+                        dataProcessor.update(key, mod.getDataBefore(), mod.getDataAfter());
+                    }
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
+            }
+        }
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<T>> changes) {
+        Preconditions.checkNotNull(changes, "Changes may not be null!");
+        executorService.submit(new Runnable() {
+            @Override
+            public void run() {
+                processChanges(changes);
+            }
+        });
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            listenerRegistration.close();
+            listenerRegistration = null;
+        }
+    }
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/MdsalHelper.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/MdsalHelper.java
new file mode 100644 (file)
index 0000000..18923a6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Red Hat 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.netvirt.renderers.neutron;
+
+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.devices.rev151227.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.devices.rev151227.devices.Device;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.devices.rev151227.devices.DeviceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.L2Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.l2.networks.L2Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.l2.networks.L2NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.PortKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MdsalHelper {
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalHelper.class);
+    public static InstanceIdentifier<Port> createPortInstanceIdentifier(Uuid portUuid) {
+        return InstanceIdentifier.create(Ports.class)
+                .child(Port.class, new PortKey(portUuid));
+    }
+
+    public static InstanceIdentifier<L2Network> createL2NetworkInstanceIdentifier(Uuid networkUuid) {
+        return InstanceIdentifier.create(L2Networks.class)
+                .child(L2Network.class, new L2NetworkKey(networkUuid));
+    }
+
+    public static InstanceIdentifier<Device> createDeviceInstanceIdentifier(Uuid deviceUuid) {
+        return InstanceIdentifier.create(Devices.class)
+                .child(Device.class, new DeviceKey(deviceUuid));
+    }
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronNetworkChangeListener.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..afbe7a9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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.netvirt.renderers.neutron;
+
+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.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Data tree listener for Neutron Network
+ */
+public class NeutronNetworkChangeListener extends DelegatingDataTreeListener<Network> {
+    /**
+     * {@link NeutronNetworkChangeListener} constructor.
+     * @param provider Neutron Provider
+     * @param db MdSal {@link DataBroker}
+     */
+    public NeutronNetworkChangeListener(final NeutronProvider provider, final DataBroker db) {
+        super(provider, new NeutronNetworkDataProcessor(provider, db), db,
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.create(Neutron.class).child(Networks.class).child(Network.class)));
+    }
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronNetworkDataProcessor.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronNetworkDataProcessor.java
new file mode 100644 (file)
index 0000000..e83a6c1
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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.netvirt.renderers.neutron;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.common.rev151227.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.l2.networks.L2Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.l2.networks.L2NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.l2.networks.L2NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data processor for Neutron Network
+ */
+public class NeutronNetworkDataProcessor implements DataProcessor<Network> {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkDataProcessor.class);
+    private final MdsalUtils mdsalUtils;
+    private final NeutronProvider provider;
+
+    /**
+     *
+     * @param provider - Neutron provider
+     * @param db - mdsal
+     */
+    public NeutronNetworkDataProcessor(final NeutronProvider provider, DataBroker db) {
+        this.provider = Preconditions.checkNotNull(provider, "Provider can not be null!");
+        mdsalUtils = new MdsalUtils(db);
+    }
+
+    /**
+     * Remove a netvirt network from mdsal
+     *
+     * @param identifier - the whole path to DataObject
+     * @param change - port to be removed
+     */
+    @Override
+    public void remove(final InstanceIdentifier<Network> identifier,
+                       final Network change) {
+        Preconditions.checkNotNull(change, "Removed object can not be null!");
+        LOG.debug("Delete Neutron Network model data changes for key: {} delete: {}", identifier, change);
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l2.networks.rev151227.l2.networks.L2Network> networkIid =
+                MdsalHelper.createL2NetworkInstanceIdentifier(change.getUuid());
+
+        LOG.debug("Remove netvirt network uuid {} from mdsal", change.getUuid());
+        try {
+            boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, networkIid);
+            if (result) {
+                LOG.debug("Remove netvirt network from mdsal success. Result: {}", result);
+            } else {
+                LOG.warn("Remove nevtirt network failed. Result: {}", result);
+            }
+        } catch (Exception e) {
+            LOG.warn("Remove netvirt network failed: exception {}", e);
+        }
+    }
+
+    /**
+     * Update a netvirt network in mdsal
+     *
+     * @param identifier - the whole path to DataObject
+     * @param original - original DataObject (for update)
+     * @param change - network to be updated
+     */
+
+    @Override
+    public void update(final InstanceIdentifier<Network> identifier,
+                       final Network original, final Network change) {
+        Preconditions.checkNotNull(original, "Updated original object can not be null!");
+        Preconditions.checkNotNull(change, "Updated change object can not be null!");
+        LOG.debug("Update Neutron Network model data changes for key: {} delete: {}", identifier, change);
+        remove(identifier, original);
+        add(identifier, change);
+    }
+
+    private void addExtensions(L2NetworkBuilder l2NetworkBuilder, Network network)
+    {
+        NetworkProviderExtension  providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        if (providerExtension != null) {
+            if (providerExtension.getSegmentationId() != null) {
+                l2NetworkBuilder.setSegmentationId(providerExtension.getSegmentationId());
+            }
+
+            if (Constants.NETVIRT_NEUTRON_NETWORK_TYPE_MAP.get(providerExtension.getNetworkType().getSimpleName()) != null) {
+                l2NetworkBuilder.setNetworkType(Constants.NETVIRT_NEUTRON_NETWORK_TYPE_MAP.get(providerExtension.getNetworkType().getSimpleName()));
+            } else {
+                LOG.warn("Neutron Network Type not supported.. using Flat for network {}", network);
+                l2NetworkBuilder.setNetworkType(NetworkTypeBase.class);
+            }
+        }
+    }
+
+    /**
+     * Add a netvirt Network to mdsal
+     *
+     * @param identifier - the whole path to new DataObject
+     * @param change - port to be added
+     */
+    @Override
+    public void add(final InstanceIdentifier<Network> identifier,
+                    final Network change) {
+        Preconditions.checkNotNull(change, "Added object can not be null!");
+        LOG.debug("Create Neutron Network model data changes for identifier: {} change: {}", identifier, change);
+        L2NetworkBuilder l2NetworkBuilder = new L2NetworkBuilder();
+
+        InstanceIdentifier<L2Network> networkIid = MdsalHelper.createL2NetworkInstanceIdentifier(change.getUuid());
+        addExtensions(l2NetworkBuilder, change);
+
+        if (change.isAdminStateUp() != null) {
+            l2NetworkBuilder.setAdminStateUp(change.isAdminStateUp());
+        }
+        if (change.getName() != null) {
+            l2NetworkBuilder.setName(change.getName());
+        }
+        if (change.isShared() != null) {
+            l2NetworkBuilder.setShared(change.isShared());
+        }
+        if (change.getStatus() != null) {
+            l2NetworkBuilder.setStatus(change.getStatus());
+        }
+        if (change.getTenantId() != null) {
+            // TODO
+            //l2NetworkBuilder.setTenantId(change.getTenantId());
+        }
+        if (change.getUuid() != null) {
+            l2NetworkBuilder.setUuid(change.getUuid());
+            l2NetworkBuilder.setKey(new L2NetworkKey(change.getUuid()));
+        }
+
+        LOG.debug("Add Netvirt network {} to mdsal", l2NetworkBuilder.build().toString());
+        try {
+            boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, networkIid, l2NetworkBuilder.build());
+            if (result) {
+                LOG.debug("createNetwork:addToMdSal success. Result: {}", result);
+            } else {
+                LOG.warn("createNetwork:addToMdSal failed. Result: {}", result);
+            }
+        } catch (Exception e) {
+            LOG.warn("create Netvirt Network : addToMdSal exception {}", e);
+        }
+    }
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortChangeListener.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortChangeListener.java
new file mode 100644 (file)
index 0000000..8ac6edd
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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.netvirt.renderers.neutron;
+
+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.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.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Data tree listener for Neutron Port
+ */
+public class NeutronPortChangeListener extends DelegatingDataTreeListener<Port> {
+    /**
+     * {@link NeutronPortChangeListener} constructor.
+     * @param provider Neutron Provider
+     * @param db MdSal {@link DataBroker}
+     */
+    public NeutronPortChangeListener(final NeutronProvider provider, final DataBroker db) {
+        super(provider, new NeutronPortDataProcessor(provider, db), db,
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class)));
+    }
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortDataProcessor.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortDataProcessor.java
new file mode 100644 (file)
index 0000000..6d5e76b
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright © 2015, 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.netvirt.renderers.neutron;
+
+import com.google.common.base.Preconditions;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+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.ports.rev151227.PortTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.port.EndPoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.port.EndPointsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.PortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.PortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data processor for Neutron Port
+ */
+public class NeutronPortDataProcessor implements DataProcessor<Port> {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronPortDataProcessor.class);
+    private MdsalUtils mdsalUtils;
+    private final NeutronProvider provider;
+
+    /**
+     *
+     * @param provider - Neutron provider
+     * @param db - mdsal
+     */
+    public NeutronPortDataProcessor(final NeutronProvider provider, DataBroker db) {
+        this.provider = Preconditions.checkNotNull(provider, "Provider can not be null!");
+        mdsalUtils = new MdsalUtils(db);
+    }
+
+    /**
+     * Remove a netvirt from mdsal
+     *
+     * @param identifier - the whole path to DataObject
+     * @param change - port to be removed
+     */
+    @Override
+    public void remove(final InstanceIdentifier<Port> identifier,
+                       final Port change) {
+        Preconditions.checkNotNull(change, "Removed object can not be null!");
+        LOG.debug("Delete Neutron Port model data changes for key: {} delete: {}", identifier, change);
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port> portIid =
+                MdsalHelper.createPortInstanceIdentifier(change.getUuid());
+
+        LOG.debug("Remove netvirt Port uuid {} from mdsal", change.getUuid());
+        try {
+            boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, portIid);
+            if (result) {
+                LOG.debug("Remove netvirt port from mdsal success. Result: {}", result);
+            } else {
+                LOG.warn("Remove nevtirt port failed. Result: {}", result);
+            }
+        } catch (Exception e) {
+            LOG.warn("Remove netvirt port failed: exception {}", e);
+        }
+    }
+
+    /**
+     * Update a netvirt port in mdsal
+     *
+     * @param identifier - the whole path to DataObject
+     * @param original - original DataObject (for update)
+     * @param change - port to be updated
+     */
+
+    @Override
+    public void update(final InstanceIdentifier<Port> identifier,
+                       final Port original, final Port change) {
+        Preconditions.checkNotNull(original, "Updated original object can not be null!");
+        Preconditions.checkNotNull(original, "Updated update object can not be null!");
+        remove(identifier, original);
+        LOG.debug("Update Neutron Port model data changes for key: {} delete: {}", identifier, change);
+        remove(identifier, original);
+        add(identifier, change);
+    }
+
+    /**
+     * Add a netvirt port to mdsal
+     *
+     * @param identifier - the whole path to new DataObject
+     * @param change - port to be added
+     */
+    @Override
+    public void add(final InstanceIdentifier<Port> identifier,
+                    final Port change) {
+        Preconditions.checkNotNull(change, "Added object can not be null!");
+        LOG.debug("Create Neutron Port model data changes for identifier: {} change: {}", identifier, change);
+        PortBuilder portBuilder = new PortBuilder();
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port> portIid =
+                MdsalHelper.createPortInstanceIdentifier(change.getUuid());
+
+        portBuilder.setStatus(change.getStatus());
+        if (change.isAdminStateUp() != null) {
+            portBuilder.setAdminStateUp(change.isAdminStateUp());
+        }
+        portBuilder.setName(change.getName());
+
+        // TODO
+        // Some neutron fields to consider for netvirt model
+        // tenant-id
+        // network-id
+        // extra-dhcp-opts list
+        // fixed-ips list
+        // security groups
+        // vif-details list
+        // vif-type
+        // vnic-type
+        // profile
+        // port-security-enabled
+        // host-id
+
+        if (Constants.NETVIRT_NEUTRON_PORT_TYPE_MAP.get(change.getDeviceOwner()) != null) {
+            portBuilder.setPortType(Constants.NETVIRT_NEUTRON_PORT_TYPE_MAP.get(change.getDeviceOwner()));
+        } else {
+            LOG.warn("Unsupported device owner for neutron port identifier: {}  port: {}", identifier, change);
+            portBuilder.setPortType(PortTypeBase.class);
+        }
+
+        // TODO - set parent when applicable
+        //portB.setParent(change.getParent());
+
+        portBuilder.setDeviceUuid(new Uuid(change.getDeviceId()));
+        portBuilder.setDeviceLocatorUuid(change.getNetworkId());
+        portBuilder.setKey(new PortKey(change.getUuid()));
+
+        if (change.getFixedIps() != null) {
+            List<IpAddress> ipAddressList = new ArrayList<>();
+            for (FixedIps ips : change.getFixedIps()) {
+                ipAddressList.add(new IpAddress(ips.getIpAddress().getValue()));
+            }
+            EndPoints endPoint = new EndPointsBuilder()
+                    .setMacaddr(new MacAddress(change.getMacAddress()))
+                    .setIpaddrs(ipAddressList)
+                    .build();
+            portBuilder.setEndPoints(Collections.singletonList(endPoint));
+        }
+
+        LOG.debug("Add Netvirt Port {} to mdsal", portBuilder.build().toString());
+        try {
+            boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, portIid, portBuilder.build());
+            if (result) {
+                LOG.debug("createPort:addToMdSal success. Result: {}", result);
+            } else {
+                LOG.warn("createPort:addToMdSal failed. Result: {}", result);
+            }
+        } catch (Exception e) {
+            LOG.warn("create Netvirt Port : addToMdSal exception {}", e);
+        }
+    }
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronProvider.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronProvider.java
new file mode 100644 (file)
index 0000000..41f33f3
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 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.netvirt.renderers.neutron;
+
+import com.google.common.base.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.osgi.framework.BundleContext;
+
+public class NeutronProvider implements BindingAwareProvider, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronProvider.class);
+    private BundleContext bundleContext = null;
+    private static DataBroker dataBroker = null;
+    private static EntityOwnershipService entityOwnershipService;
+    private static final Entity ownerInstanceEntity = new Entity(Constants.NETVIRT_NEUTRON_OWNER_ENTITY_TYPE,
+            Constants.NETVIRT_NEUTRON_OWNER_ENTITY_TYPE);
+    private NeutronPortChangeListener neutronPortChangeListener;
+    private NeutronNetworkChangeListener neutronNetworkChangeListener;
+
+    public NeutronProvider(BundleContext bundleContext, EntityOwnershipService eos) {
+        LOG.info("Netvirt NeutronProvider: bundleContext: {}", bundleContext);
+        this.bundleContext = bundleContext;
+        entityOwnershipService = eos;
+    }
+
+    public NeutronProvider() {
+        LOG.info("Netvirt NeutronProvider created");
+    }
+
+    public static boolean isMasterProviderInstance() {
+        if (entityOwnershipService != null) {
+            Optional<EntityOwnershipState> state = entityOwnershipService.getOwnershipState(ownerInstanceEntity);
+            return state.isPresent() && state.get().isOwner();
+        }
+        return false;
+    }
+
+
+    @Override
+    public void onSessionInitiated(ProviderContext providerContext) {
+        dataBroker = providerContext.getSALService(DataBroker.class);
+        LOG.info("Netvirt NeutronProvider: onSessionInitiated dataBroker: {}", dataBroker);
+
+        neutronPortChangeListener = new NeutronPortChangeListener(this, dataBroker);
+        neutronNetworkChangeListener = new NeutronNetworkChangeListener(this, dataBroker);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (neutronPortChangeListener != null) {
+            neutronPortChangeListener.close();
+        }
+        if (neutronNetworkChangeListener != null) {
+            neutronNetworkChangeListener.close();
+        }
+        LOG.info("Netvirt NeutronProvider Closed");
+    }
+
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModule.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModule.java
new file mode 100644 (file)
index 0000000..52cc310
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308;
+
+import org.opendaylight.netvirt.netvirt.renderers.neutron.NeutronProvider;
+
+public class NeutronModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308.AbstractNeutronModule {
+    public NeutronModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NeutronModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308.NeutronModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        NeutronProvider provider = new NeutronProvider();
+        getBrokerDependency().registerProvider(provider);
+        return provider;
+    }
+
+}
diff --git a/netvirt/renderers/neutron/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleFactory.java b/netvirt/renderers/neutron/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleFactory.java
new file mode 100644 (file)
index 0000000..98cd54a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 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
+ */
+/*
+* Generated file
+*
+* Generated from: yang module name: neutron yang module local name: neutron
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308;
+public class NeutronModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308.AbstractNeutronModuleFactory {
+
+}
diff --git a/netvirt/renderers/neutron/src/main/yang/netvirt-neutron.yang b/netvirt/renderers/neutron/src/main/yang/netvirt-neutron.yang
new file mode 100644 (file)
index 0000000..85f7888
--- /dev/null
@@ -0,0 +1,36 @@
+module netvirt-neutron {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:neutron";
+    prefix "neutron";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+    import opendaylight-entity-ownership-service {prefix eos; revision-date 2015-08-10;}
+
+    description
+        "Service definition for NetVirt Neutron renderer";
+
+    revision "2016-03-08" {
+        description
+            "Initial revision";
+    }
+
+    identity netvirt-neutron {
+        base config:module-type;
+        config:java-name-prefix Neutron;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netvirt-neutron {
+            when "/config:modules/config:module/config:type = 'netvirt-neutron'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/netvirt/renderers/neutron/src/test/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortDataProcessorTest.java b/netvirt/renderers/neutron/src/test/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronPortDataProcessorTest.java
new file mode 100644 (file)
index 0000000..345dbca
--- /dev/null
@@ -0,0 +1,149 @@
+package org.opendaylight.netvirt.netvirt.renderers.neutron;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+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.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.PortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import com.google.common.base.Optional;
+
+/**
+ * Unit test for {@link NeutronPortDataProcessor}
+ */
+public class NeutronPortDataProcessorTest extends AbstractDataBrokerTest {
+    private static final Uuid portId = new Uuid("aaaaaaaa-bbbb-cccc-dddd-123456789012");
+    private static final Uuid portId2 = new Uuid("11111111-2222-3333-4444-555555555555");
+    private static final Uuid portId3 = new Uuid("33333333-3333-3333-3333-333333333333");
+    ProviderContext session;
+    NeutronPortDataProcessor neutronPortDataProcessor;
+    boolean initialized = false;
+
+    private org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port readFromMdSal(Uuid uuid) throws Exception {
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port> portIid =
+                MdsalHelper.createPortInstanceIdentifier(uuid);
+
+        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port netvirtPort = null;
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port> data =
+            getDataBroker()
+            .newReadOnlyTransaction()
+            .read(LogicalDatastoreType.CONFIGURATION, portIid)
+            .get();
+        return data.orNull();
+    }
+
+    private Port createNeutronPort(Uuid uuid, String name, boolean adminStateUp ) throws Exception {
+        String addr = "100.100.100.100";
+        List<FixedIps> ips = new ArrayList<>();
+        FixedIpsBuilder fixedIpsBuilder = new FixedIpsBuilder()
+                .setIpAddress(new IpAddress(addr.toCharArray()))
+                .setSubnetId(new Uuid("12345678-1234-1234-1234-222222222222"));
+        ips.add(fixedIpsBuilder.build());
+
+
+        return (new PortBuilder()
+                .setStatus("Up")
+                .setAdminStateUp(adminStateUp)
+                .setName(name)
+                .setDeviceOwner("compute:nova")
+                .setDeviceId("12345678-1234-1234-1234-123456789012")
+                .setUuid(uuid)
+                .setMacAddress("00:00:01:02:03:04")
+                .setFixedIps(ips)
+                .build());
+    }
+
+    private void initialize() {
+        if (!initialized) {
+            session = mock(ProviderContext.class);
+            when(session.getSALService(DataBroker.class)).thenReturn(getDataBroker());
+            neutronPortDataProcessor = new NeutronPortDataProcessor(new NeutronProvider(), session.getSALService(DataBroker.class));
+            initialized = true;
+        }
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+        //Do some setup and initialization
+        initialize();
+
+        //Create Neutron port
+        Port neutronPort = createNeutronPort(portId2, "testRemovePort", true);
+        InstanceIdentifier<Port> instanceIdentifier = InstanceIdentifier.create(Ports.class).child(Port.class);
+
+        //Add the Neutron port.This should result in a Netvirt port being created, and added to mdsal.
+        neutronPortDataProcessor.add(instanceIdentifier, neutronPort);
+
+        //Verify the Netvirt port was added to mdsal
+        assertNotNull(readFromMdSal(neutronPort.getUuid()));
+
+        //Delete the Netvirt port that was just put into mdsal, and verify that it was removed from mdsal.
+        neutronPortDataProcessor.remove(instanceIdentifier, neutronPort);
+        assertNull(readFromMdSal(neutronPort.getUuid()));
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        //Do some setup and initialization
+        initialize();
+
+        //Create Neutron port
+        Port neutronPort = createNeutronPort(portId3, "testUpdatePort", true);
+        InstanceIdentifier<Port> instanceIdentifier = InstanceIdentifier.create(Ports.class).child(Port.class);
+
+        //Add the Neutron port. This should result in a Netvirt port being created, and added to mdsal.
+        neutronPortDataProcessor.add(instanceIdentifier, neutronPort);
+
+        //Verify the Netvirt port was added to mdsal
+        assertNotNull(readFromMdSal(neutronPort.getUuid()));
+
+        //Create a second Neutron port, with different values for "name" and "AdminStateUp"
+        Port neutronPort1 = createNeutronPort(portId3, "portUpdatedTest", false);
+
+        //Update the Neutron port. This should result in the netvirt port in mdsal being updated, with a new name and
+        //admin state
+        neutronPortDataProcessor.update(instanceIdentifier, neutronPort, neutronPort1);
+
+        //Verify that the netvirt port was updated in mdsal
+        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port netvirtPort = readFromMdSal(neutronPort1.getUuid());
+        assertNotNull(netvirtPort);
+        assertEquals("Error, name not updated", netvirtPort.getName(), neutronPort1.getName());
+        assertEquals("Error, admin state not updated", netvirtPort.isAdminStateUp(), neutronPort1.isAdminStateUp());
+    }
+
+    @Test
+    public void testAdd() throws Exception {
+        //Do some setup and initialization
+        initialize();
+
+        //Create Neutron port.
+        Port neutronPort = createNeutronPort(portId, "testAddPort", true);
+        InstanceIdentifier<Port> instanceIdentifier = InstanceIdentifier.create(Ports.class).child(Port.class);
+
+        //Add the Neutron port.This should result in a Netvirt port being created, and added to mdsal.
+        neutronPortDataProcessor.add(instanceIdentifier, neutronPort);
+
+        //Verify that the Netvirt port was added to mdsal, and that the contents of the Netvirt port are correct.
+        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ports.rev151227.ports.Port netvirtPort = readFromMdSal(neutronPort.getUuid());
+        assertNotNull(netvirtPort);
+        assertEquals("Error, status not correct", netvirtPort.getStatus(), neutronPort.getStatus());
+        assertEquals("Error, name not correct", netvirtPort.getName(), neutronPort.getName());
+        assertEquals("Error, admin state not correct", netvirtPort.isAdminStateUp(), neutronPort.isAdminStateUp());
+        assertEquals("Error, dev id is not correct", netvirtPort.getDeviceUuid().getValue(), neutronPort.getDeviceId());
+        assertEquals("Error, uuid is not correct", netvirtPort.getUuid().getValue(), neutronPort.getUuid().getValue());
+    }
+
+}
\ No newline at end of file
diff --git a/netvirt/renderers/neutron/src/test/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronProviderTest.java b/netvirt/renderers/neutron/src/test/java/org/opendaylight/netvirt/netvirt/renderers/neutron/NeutronProviderTest.java
new file mode 100644 (file)
index 0000000..dbcc924
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 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.netvirt.renderers.neutron;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+
+import static org.mockito.Mockito.mock;
+
+public class NeutronProviderTest {
+    @Test
+    public void testOnSessionInitiated() {
+
+        NeutronProvider provider = new NeutronProvider();
+
+        // ensure no exceptions
+        // currently this method is empty
+
+        //TODO
+        //provider.onSessionInitiated(mock(BindingAwareBroker.ProviderContext.class));
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        NeutronProvider provider = new NeutronProvider();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.close();
+    }
+}
diff --git a/netvirt/renderers/neutron/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleFactoryTest.java b/netvirt/renderers/neutron/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleFactoryTest.java
new file mode 100644 (file)
index 0000000..76bf797
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308;
+
+import org.junit.Test;
+
+public class NeutronModuleFactoryTest {
+    @Test
+    public void testFactoryConstructor() {
+        // ensure no exceptions on construction
+        new NeutronModuleFactory();
+    }
+}
diff --git a/netvirt/renderers/neutron/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleTest.java b/netvirt/renderers/neutron/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/neutron/rev160308/NeutronModuleTest.java
new file mode 100644 (file)
index 0000000..46b2228
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.neutron.rev160308;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.netvirt.netvirt.renderers.neutron.NeutronProvider;
+
+import javax.management.ObjectName;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class NeutronModuleTest {
+    @Test
+    public void testCustomValidation() {
+        NeutronModule module = new NeutronModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class));
+
+        // ensure no exceptions on validation
+        // currently this method is empty
+        module.customValidation();
+    }
+
+    @Test
+    public void testCreateInstance() throws Exception {
+        // configure mocks
+        DependencyResolver dependencyResolver = mock(DependencyResolver.class);
+        BindingAwareBroker broker = mock(BindingAwareBroker.class);
+        when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
+
+        // create instance of module with injected mocks
+        NeutronModule module = new NeutronModule(mock(ModuleIdentifier.class), dependencyResolver);
+
+        // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+        AutoCloseable closeable = module.getInstance();
+
+        // verify that the module registered the returned provider with the broker
+        verify(broker).registerProvider((NeutronProvider)closeable);
+
+        // ensure no exceptions on close
+        closeable.close();
+    }
+}
diff --git a/netvirt/renderers/pom.xml b/netvirt/renderers/pom.xml
new file mode 100644 (file)
index 0000000..cc2c627
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 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 INTERNAL
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>renderers-aggregator</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>renderers</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>hwgw</module>
+    <module>neutron</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+</project>
diff --git a/openstack/net-virt-it/pom.xml b/openstack/net-virt-it/pom.xml
new file mode 100644 (file)
index 0000000..d07c222
--- /dev/null
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v1.0 which accompanies this distribution,
+and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.netvirt</groupId>
+    <artifactId>it</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath>../../commons/it</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-it</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <properties>
+    <controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
+    <karaf.distro.groupId>org.opendaylight.netvirt</karaf.distro.groupId>
+    <karaf.distro.artifactId>karaf</karaf.distro.artifactId>
+    <karaf.distro.version>${project.version}</karaf.distro.version>
+    <karaf.distro.type>zip</karaf.distro.type>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>features-netvirt</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar-plugins.java</groupId>
+      <artifactId>sonar-jacoco-listeners</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.netvirt-it-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.ovsdb-it-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.neutron-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java b/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java
new file mode 100644 (file)
index 0000000..6ac8085
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 2015 - 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.openstack.netvirt.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.netvirt.utils.netvirt.it.utils.NetvirtItUtils;
+import org.opendaylight.netvirt.utils.netvirt.it.utils.NeutronNetItUtil;
+import org.opendaylight.netvirt.utils.neutron.utils.NeutronUtils;
+import org.opendaylight.neutron.spi.INeutronPortCRUD;
+import org.opendaylight.neutron.spi.INeutronSecurityGroupCRUD;
+import org.opendaylight.neutron.spi.INeutronSecurityRuleCRUD;
+import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.lib.notation.Version;
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.ovsdb.it.utils.OvsdbItUtils;
+import org.opendaylight.ovsdb.utils.ovsdb.it.utils.NodeInfo;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption;
+import org.ops4j.pax.exam.options.MavenUrlReference;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Integration tests for netvirt
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class NetvirtIT extends AbstractMdsalTestBase {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtIT.class);
+    private static DataBroker dataBroker = null;
+    private static OvsdbItUtils itUtils;
+    private static NetvirtItUtils nvItUtils;
+    private static String addressStr;
+    private static String portStr;
+    private static String connectionType;
+    private static String controllerStr;
+    private static AtomicBoolean setup = new AtomicBoolean(false);
+    private static MdsalUtils mdsalUtils = null;
+    private static Southbound southbound = null;
+    private static PipelineOrchestrator pipelineOrchestrator = null;
+    private static SouthboundUtils southboundUtils;
+    private static NeutronUtils neutronUtils = new NeutronUtils();
+    private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
+
+    @Override
+    public String getModuleName() {
+        return "netvirt-providers-impl";
+    }
+
+    @Override
+    public String getInstanceName() {
+        return "netvirt-providers-default";
+    }
+
+    @Override
+    public MavenUrlReference getFeatureRepo() {
+        return maven()
+                .groupId("org.opendaylight.netvirt")
+                .artifactId("features-netvirt")
+                .classifier("features")
+                .type("xml")
+                .versionAsInProject();
+    }
+
+    @Override
+    public String getFeatureName() {
+        return "odl-ovsdb-openstack-it";
+    }
+
+    @Configuration
+    @Override
+    public Option[] config() {
+        Option[] parentOptions = super.config();
+        Option[] propertiesOptions = getPropertiesOptions();
+        Option[] otherOptions = getOtherOptions();
+        Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
+        System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
+        System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
+        System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
+                otherOptions.length);
+        return options;
+    }
+
+    private Option[] getOtherOptions() {
+        return new Option[] {
+                wrappedBundle(
+                        mavenBundle("org.opendaylight.netvirt", "utils.mdsal-openflow")
+                                .version(asInProject())
+                                .type("jar")),
+                wrappedBundle(
+                        mavenBundle("org.opendaylight.netvirt", "utils.config")
+                                .version(asInProject())
+                                .type("jar")),
+                configureConsole().startLocalConsole(),
+                vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
+                keepRuntimeFolder()
+        };
+    }
+
+    public Option[] getPropertiesOptions() {
+        return new Option[] {
+                propagateSystemProperties(NetvirtITConstants.SERVER_IPADDRESS,
+                        NetvirtITConstants.SERVER_PORT, NetvirtITConstants.CONNECTION_TYPE,
+                        NetvirtITConstants.CONTROLLER_IPADDRESS,
+                        NetvirtITConstants.USERSPACE_ENABLED)
+        };
+    }
+
+    @Override
+    public Option getLoggingOption() {
+        return composite(
+                //editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                //        "log4j.logger.org.opendaylight.controller",
+                //        LogLevelOption.LogLevel.TRACE.name()),
+                editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb",
+                        LogLevelOption.LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        logConfiguration(NetvirtIT.class),
+                        LogLevelOption.LogLevel.INFO.name()),
+                editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb.lib",
+                        LogLevelOption.LogLevel.INFO.name()),
+                editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.openflowjava",
+                        LogLevelOption.LogLevel.INFO.name()),
+                editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.openflowplugin",
+                        LogLevelOption.LogLevel.INFO.name()),
+                super.getLoggingOption());
+    }
+
+    protected String usage() {
+        return "Integration Test needs a valid connection configuration as follows :\n"
+                + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
+                + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
+    }
+
+    private void getProperties() {
+        Properties props = System.getProperties();
+        addressStr = props.getProperty(NetvirtITConstants.SERVER_IPADDRESS);
+        portStr = props.getProperty(NetvirtITConstants.SERVER_PORT, NetvirtITConstants.DEFAULT_SERVER_PORT);
+        connectionType = props.getProperty(NetvirtITConstants.CONNECTION_TYPE, "active");
+        controllerStr = props.getProperty(NetvirtITConstants.CONTROLLER_IPADDRESS, "0.0.0.0");
+        String userSpaceEnabled = props.getProperty(NetvirtITConstants.USERSPACE_ENABLED, "no");
+        LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
+                "userspace.enabled: {}",
+                connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
+        if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_ACTIVE)) {
+            if (addressStr == null) {
+                fail(usage());
+            }
+        }
+    }
+
+    @Before
+    @Override
+    public void setup() throws InterruptedException {
+        if (setup.get()) {
+            LOG.info("Skipping setUp, already initialized");
+            return;
+        }
+
+        try {
+            super.setup();
+        } catch (Exception e) {
+            LOG.warn("Failed to setup test", e);
+            fail("Failed to setup test: " + e);
+        }
+
+        getProperties();
+
+        if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_ACTIVE)) {
+            if (addressStr == null) {
+                fail(usage());
+            }
+        }
+
+        dataBroker = NetvirtItUtils.getDatabroker(getProviderContext());
+        itUtils = new OvsdbItUtils(dataBroker);
+        nvItUtils = new NetvirtItUtils(dataBroker);
+        mdsalUtils = new MdsalUtils(dataBroker);
+        assertNotNull("mdsalUtils should not be null", mdsalUtils);
+        assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
+        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        assertNotNull("southbound should not be null", southbound);
+        southboundUtils = new SouthboundUtils(mdsalUtils);
+        pipelineOrchestrator =
+                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+        assertNotNull("pipelineOrchestrator should not be null", pipelineOrchestrator);
+        setup.set(true);
+    }
+
+    private BindingAwareBroker.ProviderContext getProviderContext() {
+        BindingAwareBroker.ProviderContext providerContext = null;
+        for (int i=0; i < 60; i++) {
+            providerContext = getSession();
+            if (providerContext != null) {
+                break;
+            } else {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.warn("Interrupted while waiting for provider context", e);
+                }
+            }
+        }
+        assertNotNull("providercontext should not be null", providerContext);
+        /* One more second to let the provider finish initialization */
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            LOG.warn("Interrupted while waiting for other provider", e);
+        }
+        return providerContext;
+    }
+
+    private Boolean getNetvirtTopology() {
+        LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
+        Boolean found = false;
+        final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
+        InstanceIdentifier<Topology> path =
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+        for (int i = 0; i < 60; i++) {
+            Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+            if (topology != null) {
+                LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
+                found = true;
+                break;
+            } else {
+                LOG.info("getNetvirtTopology: still looking ({})...", i);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.warn("Interrupted while waiting for {}", NETVIRT_TOPOLOGY_ID, e);
+                }
+            }
+        }
+        return found;
+    }
+
+    /**
+     * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
+     * 6640. This test will wait for incoming connections for {@link NetvirtITConstants#CONNECTION_INIT_TIMEOUT} ms.
+     *
+     * @throws InterruptedException
+     */
+    @Ignore
+    @Test
+    public void testPassiveNode() throws InterruptedException {
+        if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_PASSIVE)) {
+            //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
+            Thread.sleep(NetvirtITConstants.CONNECTION_INIT_TIMEOUT);
+        }
+    }
+
+    private Node connectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
+        LOG.info("connectOvsdbNode enter");
+        Assert.assertTrue(southboundUtils.addOvsdbNode(connectionInfo));
+        Node node = southboundUtils.getOvsdbNode(connectionInfo);
+        Assert.assertNotNull("Should find OVSDB node after connect", node);
+        LOG.info("Connected to {}", SouthboundUtils.connectionInfoToString(connectionInfo));
+        return node;
+    }
+
+    private boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
+        LOG.info("disconnectOvsdbNode enter");
+        Assert.assertTrue(southboundUtils.deleteOvsdbNode(connectionInfo));
+        Node node = southboundUtils.getOvsdbNode(connectionInfo);
+        Assert.assertNull("Should not find OVSDB node after disconnect", node);
+        LOG.info("Disconnected from {}", SouthboundUtils.connectionInfoToString(connectionInfo));
+        return true;
+    }
+
+    // This is an extra test for local testing and testNetVirt covers this is more detail
+    @Ignore
+    @Test
+    public void testAddDeleteOvsdbNode() throws InterruptedException {
+        LOG.info("testAddDeleteOvsdbNode enter");
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        Node ovsdbNode = connectOvsdbNode(connectionInfo);
+        assertNotNull("connection failed", ovsdbNode);
+        LOG.info("testNetVirt: should be connected: {}", ovsdbNode.getNodeId());
+
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", itUtils.isControllerConnected(connectionInfo));
+
+        Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
+        Thread.sleep(1000);
+        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        LOG.info("testAddDeleteOvsdbNode exit");
+    }
+
+    // TODO add tests for when L3 is enabled and check for br-ex
+
+    // This is an extra test for local testing and testNetVirt covers this is more detail
+    @Ignore
+    @Test
+    public void testAddDeleteOvsdbNodeWithTableOffset() throws InterruptedException {
+        LOG.info("testAddDeleteOvsdbNodeWithTableOffset enter");
+        NetvirtProvidersProvider.setTableOffset((short)1);
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        Node ovsdbNode = connectOvsdbNode(connectionInfo);
+        assertNotNull("connection failed", ovsdbNode);
+        LOG.info("testNetVirt: should be connected: {}", ovsdbNode.getNodeId());
+
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", itUtils.isControllerConnected(connectionInfo));
+
+        // Verify the pipeline flows were installed
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
+        assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
+        assertNotEquals("datapathId was not found", datapathId, 0);
+
+        List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
+        List<Service> staticPipelineFound = Lists.newArrayList();
+        for (Service service : pipelineOrchestrator.getServiceRegistry().keySet()) {
+            if (staticPipeline.contains(service)) {
+                staticPipelineFound.add(service);
+            }
+            String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(service);
+            nvItUtils.verifyFlow(datapathId, flowId, pipelineOrchestrator.getTable(service));
+        }
+        assertEquals("did not find all expected flows in static pipeline",
+                staticPipeline.size(), staticPipelineFound.size());
+
+        String flowId = "TableOffset_" + pipelineOrchestrator.getTable(Service.CLASSIFIER);
+        nvItUtils.verifyFlow(datapathId, flowId, Service.CLASSIFIER.getTable());
+
+        Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
+        Thread.sleep(1000);
+        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        LOG.info("testAddDeleteOvsdbNodeWithTableOffset exit");
+    }
+
+    @Ignore
+    @Test
+    public void testOpenVSwitchOtherConfig() throws InterruptedException {
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        Node ovsdbNode = connectOvsdbNode(connectionInfo);
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+        Assert.assertNotNull(ovsdbNodeAugmentation);
+        List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
+        if (otherConfigsList != null) {
+            for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
+                if (otherConfig.getOtherConfigKey().equals("local_ip")) {
+                    LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
+                    break;
+                } else {
+                    LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
+                }
+            }
+        } else {
+            LOG.info("other_config is not present");
+        }
+        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+    }
+
+    /**
+     * Test for basic southbound events to netvirt.
+     * <pre>The test will:
+     * - connect to an OVSDB node and verify it is added to operational
+     * - then verify that br-int was created on the node and stored in operational
+     * - a port is then added to the bridge to verify that it is ignored by netvirt
+     * - remove the bridge
+     * - remove the node and verify it is not in operational
+     * </pre>
+     * @throws InterruptedException
+     */
+    @Test
+    public void testNetVirt() throws InterruptedException {
+        LOG.info("testNetVirt: starting test");
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        NodeInfo nodeInfo = itUtils.createNodeInfo(connectionInfo, null);
+        nodeInfo.connect();
+        LOG.info("testNetVirt: should be connected: {}", nodeInfo.ovsdbNode.getNodeId());
+
+        List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
+        List<Service> staticPipelineFound = Lists.newArrayList();
+        for (Service service : pipelineOrchestrator.getServiceRegistry().keySet()) {
+            if (staticPipeline.contains(service)) {
+                staticPipelineFound.add(service);
+            }
+            String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(service);
+            nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(service));
+        }
+        assertEquals("did not find all expected flows in static pipeline",
+                staticPipeline.size(), staticPipelineFound.size());
+
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, NetvirtITConstants.PORT_NAME, "internal", null, null, 0L);
+        Thread.sleep(1000);
+        OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                southbound.getTerminationPointOfBridge(nodeInfo.bridgeNode, NetvirtITConstants.PORT_NAME);
+        Assert.assertNotNull("Did not find " + NetvirtITConstants.PORT_NAME, ovsdbTerminationPointAugmentation);
+
+        nodeInfo.disconnect();
+    }
+
+    @Test
+    public void testNetVirtFixedSG() throws InterruptedException {
+        final Version minSGOvsVersion = Version.fromString("1.10.2");
+        final String portName = "sg1";
+        final String networkId = "521e29d6-67b8-4b3c-8633-027d21195111";
+        final String tenantId = "521e29d6-67b8-4b3c-8633-027d21195100";
+        final String subnetId = "521e29d6-67b8-4b3c-8633-027d21195112";
+        final String portId = "521e29d6-67b8-4b3c-8633-027d21195113";
+        final String dhcpPortId ="521e29d6-67b8-4b3c-8633-027d21195115";
+
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        NodeInfo nodeInfo = itUtils.createNodeInfo(connectionInfo, null);
+        nodeInfo.connect();
+        LOG.info("testNetVirtFixedSG: should be connected: {}", nodeInfo.ovsdbNode.getNodeId());
+
+        //TBD: This should be a utility function
+        // Verify the minimum version required for this test
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = nodeInfo.ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+        Assert.assertNotNull(ovsdbNodeAugmentation);
+        assertNotNull(ovsdbNodeAugmentation.getOvsVersion());
+        String ovsVersion = ovsdbNodeAugmentation.getOvsVersion();
+        Version version = Version.fromString(ovsVersion);
+        if (version.compareTo(minSGOvsVersion) < 0) {
+            LOG.warn("{} minimum version is required", minSGOvsVersion);
+            Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo,
+                    NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
+            Thread.sleep(1000);
+            Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+            return;
+        }
+
+        //TBD: Use NeutronNetItUtil
+        NeutronNetwork nn = neutronUtils.createNeutronNetwork(networkId, tenantId,
+                NetworkHandler.NETWORK_TYPE_VXLAN, "100");
+        NeutronSubnet ns = neutronUtils.createNeutronSubnet(subnetId, tenantId, networkId, "10.0.0.0/24");
+        NeutronPort nport = neutronUtils.createNeutronPort(networkId, subnetId, portId,
+                "compute", "10.0.0.10", "f6:00:00:0f:00:01");
+        NeutronPort dhcp = neutronUtils.createNeutronPort(networkId, subnetId, dhcpPortId,
+                "dhcp", "10.0.0.1", "f6:00:00:0f:00:02");
+
+        Thread.sleep(1000);
+        Map<String, String> externalIds = Maps.newHashMap();
+        externalIds.put("attached-mac", "f6:00:00:0f:00:01");
+        externalIds.put("iface-id", portId);
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, portName, "internal", null, externalIds, 3L);
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vm1", "internal", null, null, 0L);
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vm2", "internal", null, null, 0L);
+        Map<String, String> options = Maps.newHashMap();
+        options.put("key", "flow");
+        options.put("remote_ip", "192.168.120.32");
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vx", "vxlan", options, null, 4L);
+        Thread.sleep(1000);
+
+        String flowId = "Egress_DHCP_Client"  + "_Permit_";
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+
+        testDefaultSG(nport, nodeInfo.datapathId, nn, tenantId, portId);
+        Thread.sleep(1000);
+
+        assertTrue(neutronUtils.removeNeutronPort(dhcp.getID()));
+        assertTrue(neutronUtils.removeNeutronPort(nport.getID()));
+        assertTrue(neutronUtils.removeNeutronSubnet(ns.getID()));
+        assertTrue(neutronUtils.removeNeutronNetwork(nn.getID()));
+
+        nodeInfo.disconnect();
+    }
+
+    private void testDefaultSG(NeutronPort nport, long datapathId, NeutronNetwork nn, String tenantId, String portId)
+            throws InterruptedException {
+        INeutronSecurityGroupCRUD ineutronSecurityGroupCRUD =
+                (INeutronSecurityGroupCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityGroupCRUD.class, this);
+        assertNotNull("Could not find ineutronSecurityGroupCRUD Service", ineutronSecurityGroupCRUD);
+        INeutronSecurityRuleCRUD ineutronSecurityRuleCRUD =
+                (INeutronSecurityRuleCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityRuleCRUD.class, this);
+        assertNotNull("Could not find ineutronSecurityRuleCRUD Service", ineutronSecurityRuleCRUD);
+
+        NeutronSecurityGroup neutronSG = new NeutronSecurityGroup();
+        neutronSG.setSecurityGroupDescription("testig defaultSG-IT");
+        neutronSG.setSecurityGroupName("DefaultSG");
+        neutronSG.setSecurityGroupUUID("d3329053-bae5-4bf4-a2d1-7330f11ba5db");
+        neutronSG.setTenantID(tenantId);
+
+        List<NeutronSecurityRule> nsrs = new ArrayList<>();
+        NeutronSecurityRule nsrIN = new NeutronSecurityRule();
+        nsrIN.setSecurityRemoteGroupID(null);
+        nsrIN.setSecurityRuleDirection("ingress");
+        nsrIN.setSecurityRuleEthertype("IPv4");
+        nsrIN.setSecurityRuleGroupID("d3329053-bae5-4bf4-a2d1-7330f11ba5db");
+        nsrIN.setSecurityRuleProtocol("TCP");
+        nsrIN.setSecurityRuleRemoteIpPrefix("10.0.0.0/24");
+        nsrIN.setSecurityRuleUUID("823faaf7-175d-4f01-a271-0bf56fb1e7e6");
+        nsrIN.setTenantID(tenantId);
+
+        NeutronSecurityRule nsrEG = new NeutronSecurityRule();
+        nsrEG.setSecurityRemoteGroupID(null);
+        nsrEG.setSecurityRuleDirection("egress");
+        nsrEG.setSecurityRuleEthertype("IPv4");
+        nsrEG.setSecurityRuleGroupID("d3329053-bae5-4bf4-a2d1-7330f11ba5db");
+        nsrEG.setSecurityRuleProtocol("TCP");
+        nsrEG.setSecurityRuleRemoteIpPrefix("10.0.0.0/24");
+        nsrEG.setSecurityRuleUUID("823faaf7-175d-4f01-a271-0bf56fb1e7e1");
+        nsrEG.setTenantID(tenantId);
+
+        nsrs.add(nsrIN);
+        nsrs.add(nsrEG);
+
+        neutronSG.setSecurityRules(nsrs);
+        ineutronSecurityRuleCRUD.addNeutronSecurityRule(nsrIN);
+        ineutronSecurityRuleCRUD.addNeutronSecurityRule(nsrEG);
+        ineutronSecurityGroupCRUD.add(neutronSG);
+
+        List<NeutronSecurityGroup> sgs = new ArrayList<>();
+        sgs.add(neutronSG);
+        nport.setSecurityGroups(sgs);
+
+        INeutronPortCRUD iNeutronPortCRUD =
+                (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+        iNeutronPortCRUD.update(portId, nport);
+
+        LOG.info("Neutron ports have been added");
+        Thread.sleep(10000);
+        String flowId = "Egress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_";
+        nvItUtils.verifyFlow(datapathId, flowId, pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+
+        flowId = "Ingress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_";
+        nvItUtils.verifyFlow(datapathId, flowId, pipelineOrchestrator.getTable(Service.INGRESS_ACL));
+
+        ineutronSecurityGroupCRUD.remove(neutronSG.getID());
+        ineutronSecurityRuleCRUD.removeNeutronSecurityRule(nsrEG.getID());
+        ineutronSecurityRuleCRUD.removeNeutronSecurityRule(nsrIN.getID());
+    }
+
+    /**
+     * Test a basic neutron use case. This test constructs a Neutron network, subnet, dhcp port, and two "vm" ports
+     * and validates that the correct flows are installed on OVS.
+     * @throws InterruptedException if we're interrupted while waiting for some mdsal operation to complete
+     */
+    @Test
+    public void testNeutronNet() throws InterruptedException {
+        LOG.warn("testNetWithTwoVms: starting test");
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        NodeInfo nodeInfo = itUtils.createNodeInfo(connectionInfo, null);
+        nodeInfo.connect();
+        LOG.warn("testNetWithTwoVms: should be connected: {}", nodeInfo.ovsdbNode.getNodeId());
+
+        // Create the objects
+        NeutronNetItUtil net = new NeutronNetItUtil(southboundUtils, UUID.randomUUID().toString());
+        net.create();
+        net.createPort(nodeInfo.bridgeNode, "dhcp", "network:dhcp");
+        net.createPort(nodeInfo.bridgeNode, "vm1");
+        net.createPort(nodeInfo.bridgeNode, "vm2");
+
+
+        // Check flows created for all ports
+        for (int i = 1; i <= net.neutronPorts.size(); i++) {
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "DropFilter_"  + i,
+                                                                pipelineOrchestrator.getTable(Service.CLASSIFIER));
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "LocalMac_" + net.segId + "_" + i + "_" + net.macFor(i),
+                                                                pipelineOrchestrator.getTable(Service.CLASSIFIER));
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "ArpResponder_" + net.segId + "_"  + net.ipFor(i),
+                                                                pipelineOrchestrator.getTable(Service.ARP_RESPONDER));
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "UcastOut_" + net.segId + "_" + i + "_"  + net.macFor(i),
+                                                                pipelineOrchestrator.getTable(Service.L2_FORWARDING));
+        }
+
+        // Check flows created for vm ports only
+        for (int i = 2; i <= net.neutronPorts.size(); i++) {
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "Ingress_ARP_" + net.segId + "_" + i + "_",
+                                                                pipelineOrchestrator.getTable(Service.INGRESS_ACL));
+
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_Allow_VM_IP_MAC_" + i + net.macFor(i) + "_Permit_",
+                    pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_ARP_" + net.segId + "_" + i + "_",
+                    pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCP_Server_" + i + "_DROP_",
+                    pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+            nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCPv6_Server_" + i + "_DROP_",
+                    pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+        }
+
+        // Check ingress/egress acl flows for DHCP
+        nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCP_Client_Permit_",
+                pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+        nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCPv6_Client_Permit_",
+                pipelineOrchestrator.getTable(Service.EGRESS_ACL));
+        nvItUtils.verifyFlow(nodeInfo.datapathId, "Ingress_DHCPv6_Server" + net.segId + "_"
+                                    + net.macFor(1) + "_Permit_", pipelineOrchestrator.getTable(Service.INGRESS_ACL));
+        nvItUtils.verifyFlow(nodeInfo.datapathId, "Ingress_DHCP_Server" + net.segId + "_"
+                + net.macFor(1) + "_Permit_", pipelineOrchestrator.getTable(Service.INGRESS_ACL));
+
+        // Check l2 broadcast flows
+        nvItUtils.verifyFlow(nodeInfo.datapathId, "TunnelFloodOut_" + net.segId,
+                                                pipelineOrchestrator.getTable(Service.L2_FORWARDING));
+        nvItUtils.verifyFlow(nodeInfo.datapathId, "BcastOut_" + net.segId,
+                                                pipelineOrchestrator.getTable(Service.L2_FORWARDING));
+
+        //TBD Figure out why this does not work:
+        //nvItUtils.verifyFlow(nodeInfo.datapathId, "TunnelMiss_" + net.segId,
+        //        pipelineOrchestrator.getTable(Service.L2_FORWARDING));
+
+        net.destroy();
+        nodeInfo.disconnect();
+    }
+
+}
diff --git a/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtITConstants.java b/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtITConstants.java
new file mode 100644 (file)
index 0000000..4665b1d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.it;
+
+/**
+ * Constants for SouthboundIT
+ */
+public final class NetvirtITConstants {
+    private NetvirtITConstants() {
+        throw new AssertionError("This class should not be instantiated.");
+    }
+
+    public static final String ORG_OPS4J_PAX_LOGGING_CFG = "etc/org.ops4j.pax.logging.cfg";
+    public static final String CUSTOM_PROPERTIES = "etc/custom.properties";
+    public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
+    public static final String SERVER_PORT = "ovsdbserver.port";
+    public static final String CONTROLLER_IPADDRESS = "ovsdb.controller.address";
+    public static final String USERSPACE_ENABLED = "ovsdb.userspace.enabled";
+    public static final String SERVER_EXTRAS = "ovsdbserver.extras";
+    public static final String CONNECTION_TYPE = "ovsdbserver.connection";
+    public static final String CONNECTION_TYPE_ACTIVE = "active";
+    public static final String CONNECTION_TYPE_PASSIVE = "passive";
+    public static final int CONNECTION_INIT_TIMEOUT = 10000;
+    public static final String DEFAULT_SERVER_IPADDRESS = "127.0.0.1";
+    public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String DEFAULT_OPENFLOW_PORT = "6653";
+    public static final String DEFAULT_SERVER_EXTRAS = "false";
+    public static final String BRIDGE_NAME = "brtest";
+    public static final String PORT_NAME = "porttest";
+    public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+    public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
+}
diff --git a/openstack/net-virt-providers/pom.xml b/openstack/net-virt-providers/pom.xml
new file mode 100644 (file)
index 0000000..f610e05
--- /dev/null
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-providers</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <properties>
+    <liblldp.version>0.11.0-SNAPSHOT</liblldp.version>
+    <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+    <sonar.jacoco.itReportPath>../net-virt-it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.netvirt</groupId>
+      <artifactId>openstack.net-virt</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netvirt</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-api</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netvirt</groupId>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-base</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-api</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>opendaylight-l2-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-topology</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>liblldp</artifactId>
+      <version>${liblldp.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar-plugins.java</groupId>
+      <artifactId>sonar-jacoco-listeners</artifactId>
+      <version>${sonar-jacoco-listeners.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-support</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-reflect</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>utils.config,utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+            <Export-Package>
+              org.opendaylight.netvirt.openstack.netvirt.providers,
+              org.opendaylight.netvirt.openstack.netvirt.providers.openflow13,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+         <excludes>
+            <exclude>**/services/*Test.java</exclude>
+          </excludes>
+          <properties>
+            <property>
+              <name>listener</name>
+              <value>org.sonar.java.jacoco.JUnitListener</value>
+            </property>
+          </properties>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/openstack/net-virt-providers/src/main/config/default-config.xml b/openstack/net-virt-providers/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..50c4d77
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<snapshot>
+  <required-capabilities>
+    <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:southbound:impl?module=southbound-impl&amp;revision=2014-12-10</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:impl?module=netvirt-impl&amp;revision=2015-05-13</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl?module=netvirt-providers-impl&amp;revision=2015-05-13</capability>
+  </required-capabilities>
+  <configuration>
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl">prefix:netvirt-providers-impl</type>
+          <name>netvirt-providers-default</name>
+          <table-offset>0</table-offset>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+          <clustering-entity-ownership-service>
+            <type xmlns:ns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">ns:entity-ownership-service</type>
+            <name>entity-ownership-service</name>
+          </clustering-entity-ownership-service>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigActivator.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigActivator.java
new file mode 100644 (file)
index 0000000..1d83566
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2015, 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.openstack.netvirt.providers;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ClassifierProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IcmpEchoProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L2RewriteProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.OF13Provider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.ArpResponderService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.ClassifierService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.EgressAclService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.IcmpEchoResponderService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.InboundNatService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.IngressAclService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.L2ForwardingService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.L2RewriteService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.L3ForwardingService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.LoadBalancerService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.OutboundNatService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.RoutingService;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp.GatewayMacResolverService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.netvirt.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestratorImpl;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+public class ConfigActivator implements BundleActivator {
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigActivator.class);
+    private List<ServiceRegistration<?>> registrations = new ArrayList<>();
+    private ProviderContext providerContext;
+
+    public ConfigActivator(ProviderContext providerContext) {
+        this.providerContext = providerContext;
+    }
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        LOG.info("ConfigActivator start:");
+
+        NetvirtProvidersConfigImpl netvirtProvidersConfig =
+                new NetvirtProvidersConfigImpl(providerContext.getSALService(DataBroker.class),
+                        NetvirtProvidersProvider.getTableOffset());
+        registerService(context,
+                new String[] {NetvirtProvidersConfigImpl.class.getName()},
+                null, netvirtProvidersConfig);
+
+        PipelineOrchestratorImpl pipelineOrchestrator = new PipelineOrchestratorImpl();
+        registerService(context,
+                new String[] {PipelineOrchestrator.class.getName(),NodeCacheListener.class.getName()},
+                null, pipelineOrchestrator);
+
+        Dictionary<String, Object> of13ProviderProperties = new Hashtable<>();
+        of13ProviderProperties.put(Constants.SOUTHBOUND_PROTOCOL_PROPERTY, "ovsdb");
+        of13ProviderProperties.put(Constants.OPENFLOW_VERSION_PROPERTY, Constants.OPENFLOW13);
+        final OF13Provider of13Provider = new OF13Provider();
+        registerService(context,
+                new String[] {NetworkingProvider.class.getName()},
+                of13ProviderProperties, of13Provider);
+
+        ClassifierService classifierService = new ClassifierService();
+        registerService(context, ClassifierProvider.class.getName(),
+                classifierService, Service.CLASSIFIER);
+
+        ArpResponderService arpResponderService = new ArpResponderService();
+        registerService(context, ArpProvider.class.getName(),
+                arpResponderService, Service.ARP_RESPONDER);
+
+        InboundNatService inboundNatService = new InboundNatService();
+        registerService(context, InboundNatProvider.class.getName(),
+                inboundNatService, Service.INBOUND_NAT);
+
+        IngressAclService ingressAclService = new IngressAclService();
+        registerService(context, IngressAclProvider.class.getName(),
+                ingressAclService, Service.INGRESS_ACL);
+
+        LoadBalancerService loadBalancerService = new LoadBalancerService();
+        registerService(context, LoadBalancerProvider.class.getName(),
+                loadBalancerService, Service.LOAD_BALANCER);
+
+        RoutingService routingService = new RoutingService();
+        registerService(context, RoutingProvider.class.getName(),
+                routingService, Service.ROUTING);
+
+        L3ForwardingService l3ForwardingService = new L3ForwardingService();
+        registerService(context, L3ForwardingProvider.class.getName(),
+                l3ForwardingService, Service.L3_FORWARDING);
+
+        L2RewriteService l2RewriteService = new L2RewriteService();
+        registerService(context, L2RewriteProvider.class.getName(),
+                l2RewriteService, Service.L2_REWRITE);
+
+        L2ForwardingService l2ForwardingService = new L2ForwardingService();
+        registerService(context, L2ForwardingProvider.class.getName(),
+                l2ForwardingService, Service.L2_FORWARDING);
+
+        EgressAclService egressAclService = new EgressAclService();
+        registerService(context, EgressAclProvider.class.getName(),
+                egressAclService, Service.EGRESS_ACL);
+
+        OutboundNatService outboundNatService = new OutboundNatService();
+        registerService(context, OutboundNatProvider.class.getName(),
+                outboundNatService, Service.OUTBOUND_NAT);
+
+        final GatewayMacResolverService gatewayMacResolverService = new GatewayMacResolverService();
+        registerService(context, GatewayMacResolver.class.getName(),
+                gatewayMacResolverService, Service.GATEWAY_RESOLVER);
+        getNotificationProviderService().registerNotificationListener(gatewayMacResolverService);
+
+        IcmpEchoResponderService icmpEchoResponderService = new IcmpEchoResponderService();
+        registerService(context, IcmpEchoProvider.class.getName(),
+                                            icmpEchoResponderService, Service.ICMP_ECHO);
+
+        netvirtProvidersConfig.setDependencies(context, null);
+        pipelineOrchestrator.setDependencies(context, null);
+        outboundNatService.setDependencies(context, null);
+        egressAclService.setDependencies(context, null);
+        l2ForwardingService.setDependencies(context, null);
+        l2RewriteService.setDependencies(context, null);
+        l3ForwardingService.setDependencies(context, null);
+        routingService.setDependencies(context, null);
+        loadBalancerService.setDependencies(context, null);
+        ingressAclService.setDependencies(context, null);
+        inboundNatService.setDependencies(context, null);
+        arpResponderService.setDependencies(context, null);
+        classifierService.setDependencies(context, null);
+        of13Provider.setDependencies(context, null);
+        gatewayMacResolverService.setDependencies(context, null);
+        icmpEchoResponderService.setDependencies(context, null);
+
+        @SuppressWarnings("unchecked")
+        ServiceTracker networkingProviderManagerTracker = new ServiceTracker(context,
+                NetworkingProviderManager.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService NetworkingProviderManager");
+                NetworkingProviderManager service =
+                        (NetworkingProviderManager) context.getService(reference);
+                if (service != null) {
+                    of13Provider.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        networkingProviderManagerTracker.open();
+
+        @SuppressWarnings("unchecked")
+        ServiceTracker ConfigurationServiceTracker = new ServiceTracker(context,
+                ConfigurationService.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService ConfigurationService");
+                ConfigurationService service =
+                        (ConfigurationService) context.getService(reference);
+                if (service != null) {
+                    gatewayMacResolverService.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        ConfigurationServiceTracker.open();
+
+        @SuppressWarnings("unchecked")
+        ServiceTracker NodeCacheManagerTracker = new ServiceTracker(context,
+                NodeCacheManager.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService NodeCacheManager");
+                NodeCacheManager service =
+                        (NodeCacheManager) context.getService(reference);
+                if (service != null) {
+                    gatewayMacResolverService.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        NodeCacheManagerTracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        LOG.info("ConfigActivator stop");
+        // ServiceTrackers and services are already released when bundle stops,
+        // so we don't need to close the trackers or unregister the services
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String[] interfaces,
+                                                   Dictionary<String, Object> properties, Object impl) {
+        ServiceRegistration<?> serviceRegistration = bundleContext.registerService(interfaces, impl, properties);
+        if (serviceRegistration != null) {
+            registrations.add(serviceRegistration);
+        }
+        return serviceRegistration;
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String interfaceClassName,
+                                                   Object impl, Object serviceProperty) {
+        Dictionary<String, Object> properties = new Hashtable<>();
+        properties.put(AbstractServiceInstance.SERVICE_PROPERTY, serviceProperty);
+        properties.put(Constants.PROVIDER_NAME_PROPERTY, OF13Provider.NAME);
+        return registerService(bundleContext,
+                new String[] {AbstractServiceInstance.class.getName(), interfaceClassName},
+                properties, impl);
+    }
+
+    private NotificationProviderService getNotificationProviderService(){
+        return this.providerContext.getSALService(NotificationProviderService.class);
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigInterface.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigInterface.java
new file mode 100644 (file)
index 0000000..a19685e
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.providers;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public interface ConfigInterface {
+    void setDependencies(BundleContext bundleContext, ServiceReference serviceReference);
+    void setDependencies(Object impl);
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersConfigImpl.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersConfigImpl.java
new file mode 100644 (file)
index 0000000..f158f1f
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 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.openstack.netvirt.providers;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.*;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtProvidersConfigImpl implements AutoCloseable, ConfigInterface, DataChangeListener {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtProvidersConfigImpl.class);
+    private final DataBroker dataBroker;
+    private final ListenerRegistration<DataChangeListener> registration;
+    private final ExecutorService executorService = Executors.newFixedThreadPool(1);
+    private final MdsalUtils mdsalUtils;
+
+    public NetvirtProvidersConfigImpl(final DataBroker dataBroker, final short tableOffset) {
+        this.dataBroker = dataBroker;
+        mdsalUtils = new MdsalUtils(dataBroker);
+
+        InstanceIdentifier<NetvirtProvidersConfig> path =
+                InstanceIdentifier.builder(NetvirtProvidersConfig.class).build();
+        registration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this,
+                AsyncDataBroker.DataChangeScope.SUBTREE);
+
+        NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder = new NetvirtProvidersConfigBuilder();
+        NetvirtProvidersConfig netvirtProvidersConfig =
+                mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+        if (netvirtProvidersConfig != null) {
+            netvirtProvidersConfigBuilder = new NetvirtProvidersConfigBuilder(netvirtProvidersConfig);
+        }
+        if (netvirtProvidersConfigBuilder.getTableOffset() == null) {
+            netvirtProvidersConfigBuilder.setTableOffset(tableOffset);
+        }
+        boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, path,
+                netvirtProvidersConfigBuilder.build());
+
+        LOG.info("NetvirtProvidersConfigImpl: dataBroker= {}, registration= {}, tableOffset= {}, result= {}",
+                dataBroker, registration, tableOffset, result);
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+        executorService.shutdown();
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+        executorService.submit(new Runnable() {
+
+            @Override
+            public void run() {
+                LOG.info("onDataChanged: {}", asyncDataChangeEvent);
+                processConfigCreate(asyncDataChangeEvent);
+                processConfigUpdate(asyncDataChangeEvent);
+            }
+        });
+    }
+
+    private void processConfigCreate(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : changes.getCreatedData().entrySet()) {
+            if (entry.getValue() instanceof NetvirtProvidersConfig) {
+                NetvirtProvidersConfig netvirtProvidersConfig = (NetvirtProvidersConfig) entry.getValue();
+                applyConfig(netvirtProvidersConfig);
+            }
+        }
+    }
+
+    private void processConfigUpdate(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : changes.getUpdatedData().entrySet()) {
+            if (entry.getValue() instanceof NetvirtProvidersConfig) {
+                LOG.info("processConfigUpdate: {}", entry);
+                NetvirtProvidersConfig netvirtProvidersConfig = (NetvirtProvidersConfig) entry.getValue();
+                applyConfig(netvirtProvidersConfig);
+            }
+        }
+    }
+
+    private void applyConfig(NetvirtProvidersConfig netvirtProvidersConfig) {
+        LOG.info("processConfigUpdate: {}", netvirtProvidersConfig);
+        if (netvirtProvidersConfig.getTableOffset() != null) {
+            NetvirtProvidersProvider.setTableOffset(netvirtProvidersConfig.getTableOffset());
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersProvider.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersProvider.java
new file mode 100644 (file)
index 0000000..da04466
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers;
+
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class NetvirtProvidersProvider implements BindingAwareProvider, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtProvidersProvider.class);
+
+    private BundleContext bundleContext = null;
+    private static DataBroker dataBroker = null;
+    private ConfigActivator activator;
+    private static ProviderContext providerContext = null;
+    private static EntityOwnershipService entityOwnershipService;
+    private ProviderEntityListener providerEntityListener = null;
+    private static AtomicBoolean hasProviderEntityOwnership = new AtomicBoolean(false);
+    private static short tableOffset;
+    private NetvirtProvidersConfigImpl netvirtProvidersConfig = null;
+
+    public NetvirtProvidersProvider(BundleContext bundleContext, EntityOwnershipService eos, short tableOffset) {
+        LOG.info("NetvirtProvidersProvider: bundleContext: {}", bundleContext);
+        this.bundleContext = bundleContext;
+            entityOwnershipService = eos;
+        setTableOffset(tableOffset);
+    }
+
+    public static DataBroker getDataBroker() {
+        return dataBroker;
+    }
+
+    public static ProviderContext getProviderContext() {
+        return providerContext;
+    }
+
+    public static boolean isMasterProviderInstance() {
+        return hasProviderEntityOwnership.get();
+    }
+
+    public static void setTableOffset(short tableOffset) {
+        try {
+            new TableId((short) (tableOffset + Service.L2_FORWARDING.getTable()));
+        } catch (IllegalArgumentException e) {
+            LOG.warn("Invalid table offset: {}", tableOffset, e);
+            return;
+        }
+
+        LOG.info("setTableOffset: changing from {} to {}",
+                NetvirtProvidersProvider.tableOffset, tableOffset);
+        NetvirtProvidersProvider.tableOffset = tableOffset;
+    }
+
+    public static short getTableOffset() {
+        return tableOffset;
+    }
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("NetvirtProvidersProvider closed");
+        activator.stop(bundleContext);
+        providerEntityListener.close();
+    }
+
+    @Override
+    public void onSessionInitiated(ProviderContext providerContextRef) {
+        dataBroker = providerContextRef.getSALService(DataBroker.class);
+        providerContext = providerContextRef;
+        LOG.info("NetvirtProvidersProvider: onSessionInitiated dataBroker: {}", dataBroker);
+        providerEntityListener = new ProviderEntityListener(this, entityOwnershipService);
+        this.activator = new ConfigActivator(providerContextRef);
+        try {
+            activator.start(bundleContext);
+        } catch (Exception e) {
+            LOG.warn("Failed to start Netvirt: ", e);
+        }
+    }
+
+    private void handleOwnershipChange(EntityOwnershipChange ownershipChange) {
+        if (ownershipChange.isOwner()) {
+            LOG.info("*This* instance of OVSDB netvirt provider is a MASTER instance");
+            hasProviderEntityOwnership.set(true);
+        } else {
+            LOG.info("*This* instance of OVSDB netvirt provider is a SLAVE instance");
+            hasProviderEntityOwnership.set(false);
+        }
+    }
+
+    private class ProviderEntityListener implements EntityOwnershipListener {
+        private NetvirtProvidersProvider provider;
+        private EntityOwnershipListenerRegistration listenerRegistration;
+        private EntityOwnershipCandidateRegistration candidateRegistration;
+
+        ProviderEntityListener(NetvirtProvidersProvider provider,
+                               EntityOwnershipService entityOwnershipService) {
+            this.provider = provider;
+            this.listenerRegistration =
+                    entityOwnershipService.registerListener(Constants.NETVIRT_OWNER_ENTITY_TYPE, this);
+
+            //register instance entity to get the ownership of the netvirt provider
+            Entity instanceEntity = new Entity(
+                    Constants.NETVIRT_OWNER_ENTITY_TYPE, Constants.NETVIRT_OWNER_ENTITY_TYPE);
+            try {
+                this.candidateRegistration = entityOwnershipService.registerCandidate(instanceEntity);
+            } catch (CandidateAlreadyRegisteredException e) {
+                LOG.warn("OVSDB Netvirt Provider instance entity {} was already "
+                        + "registered for ownership", instanceEntity, e);
+            }
+        }
+
+        public void close() {
+            this.listenerRegistration.close();
+            this.candidateRegistration.close();
+        }
+
+        @Override
+        public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+            provider.handleOwnershipChange(ownershipChange);
+        }
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java
new file mode 100644 (file)
index 0000000..2d23a4c
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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;
+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.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.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.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.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Any ServiceInstance class that extends AbstractServiceInstance to be a part of the pipeline
+ * have 2 basic requirements : <br>
+ * 1. Program a default pipeline flow to take any unmatched traffic to the next table in the pipeline. <br>
+ * 2. Get Pipeline Instructions from AbstractServiceInstance (using getMutablePipelineInstructionBuilder) and
+ *    use it in any matching flows that needs to be further processed by next service in the pipeline.
+ *
+ */
+public abstract class AbstractServiceInstance {
+    public static final String SERVICE_PROPERTY ="serviceProperty";
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractServiceInstance.class);
+    public static final String OPENFLOW = "openflow:";
+    private DataBroker dataBroker = null;
+    // OSGi Services that we are dependent on.
+    private volatile PipelineOrchestrator orchestrator;
+    private volatile Southbound southbound;
+
+    // Concrete Service that this AbstractServiceInstance represents
+    private Service service;
+
+    public AbstractServiceInstance (Service service) {
+        this.service = service;
+        this.dataBroker = NetvirtProvidersProvider.getDataBroker();
+    }
+
+    protected void setDependencies(final ServiceReference ref, AbstractServiceInstance serviceInstance) {
+        this.orchestrator =
+                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, serviceInstance);
+        orchestrator.registerService(ref, serviceInstance);
+        this.southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, serviceInstance);
+    }
+
+    public boolean isBridgeInPipeline (Node node){
+        String bridgeName = southbound.getBridgeName(node);
+        return bridgeName != null && Constants.INTEGRATION_BRIDGE.equals(bridgeName);
+    }
+
+    /**
+     * Return the offset adjusted table for this {@link Service}
+     * @return The table id
+     */
+    public short getTable() {
+        return (short)(orchestrator.getTableOffset() + service.getTable());
+    }
+
+    /**
+     * Return the offset adjusted table for the given {@link Service}
+     * @param service Identifies the openflow {@link Service}
+     * @return The table id
+     */
+    public short getTable(Service service) {
+        return (short)(orchestrator.getTableOffset() + service.getTable());
+    }
+
+    public Service getService() {
+        return service;
+    }
+
+    public void setService(Service service) {
+        this.service = service;
+    }
+
+    public NodeBuilder createNodeBuilder(String nodeId) {
+        NodeBuilder builder = new NodeBuilder();
+        builder.setId(new NodeId(nodeId));
+        builder.setKey(new NodeKey(builder.getId()));
+        return builder;
+    }
+
+    private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+                        nodeBuilder.getKey())
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flowBuilder.getTableId()))
+                .child(Flow.class, flowBuilder.getKey()).build();
+    }
+
+    private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
+    createNodePath(NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+                        nodeBuilder.getKey()).build();
+    }
+
+    /**
+     * This method returns the required Pipeline Instructions to by used by any matching flows that need
+     * to be further processed by next service in the pipeline.
+     *
+     * Important to note that this is a convenience method which returns a mutable instructionBuilder which
+     * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
+     * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
+     */
+    protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
+        Service nextService = orchestrator.getNextServiceInPipeline(service);
+        if (nextService != null) {
+            return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(),
+                    orchestrator.getTable(nextService));
+        } else {
+            return InstructionUtils.createDropInstructions(new InstructionBuilder());
+        }
+    }
+
+    protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        if (NetvirtProvidersProvider.isMasterProviderInstance()) {
+            LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
+                    flowBuilder.build(), nodeBuilder.build());
+            WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
+            //modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
+            //        nodeBuilder.build(), true /*createMissingParents*/);
+            modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
+                    flowBuilder.build(), true /*createMissingParents*/);
+            CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+            try {
+                commitFuture.checkedGet();  // TODO: Make it async (See bug 1362)
+                LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
+            } catch (Exception e) {
+                LOG.error("Failed to write flow {}", flowBuilder.getFlowName(), e);
+                modification.cancel();
+            }
+        }
+    }
+
+    protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        if (NetvirtProvidersProvider.isMasterProviderInstance()) {
+            WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
+            modification.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
+
+            CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+            try {
+                commitFuture.get();  // TODO: Make it async (See bug 1362)
+                LOG.debug("Transaction success for deletion of Flow {}", flowBuilder.getFlowName());
+            } catch (Exception e) {
+                LOG.error("Failed to remove flow {}", flowBuilder.getFlowName(), e);
+                modification.cancel();
+            }
+        }
+    }
+
+    public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
+        try {
+            Optional<Flow> data =
+                    readTx.read(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            LOG.error("Failed to get flow {}", flowBuilder.getFlowName(), e);
+        }
+
+        LOG.debug("Cannot find data for Flow {}", flowBuilder.getFlowName());
+        return null;
+    }
+
+    public org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
+    getOpenFlowNode(String nodeId) {
+
+        ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
+        try {
+            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> data =
+                    readTx.read(LogicalDatastoreType.OPERATIONAL, createNodePath(createNodeBuilder(nodeId))).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            LOG.error("Failed to get openflow node {}", nodeId, e);
+        }
+
+        LOG.debug("Cannot find data for Node {}", nodeId);
+        return null;
+    }
+
+    private long getDpid(Node node) {
+        long dpid = southbound.getDataPathId(node);
+        if (dpid == 0) {
+            LOG.warn("getDpid: dpid not found: {}", node);
+        }
+        return dpid;
+    }
+
+    /**
+     * Program Default Pipeline Flow.
+     *
+     * @param node on which the default pipeline flow is programmed.
+     */
+    protected void programDefaultPipelineRule(Node node) {
+        if (!isBridgeInPipeline(node)) {
+            //LOG.trace("Bridge is not in pipeline {} ", node);
+            return;
+        }
+        MatchBuilder matchBuilder = new MatchBuilder();
+        FlowBuilder flowBuilder = new FlowBuilder();
+        long dpid = getDpid(node);
+        if (dpid == 0L) {
+            LOG.info("could not find dpid: {}", node.getNodeId());
+            return;
+        }
+        String nodeName = OPENFLOW + getDpid(node);
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+
+        // Create the OF Actions and Instructions
+        InstructionsBuilder isb = new InstructionsBuilder();
+
+        // Instructions List Stores Individual Instructions
+        List<Instruction> instructions = Lists.newArrayList();
+
+        // Call the InstructionBuilder Methods Containing Actions
+        InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+        ib.setOrder(0);
+        ib.setKey(new InstructionKey(0));
+        instructions.add(ib.build());
+
+        // Add InstructionBuilder to the Instruction(s)Builder List
+        isb.setInstruction(instructions);
+
+        // Add InstructionsBuilder to FlowBuilder
+        flowBuilder.setInstructions(isb.build());
+
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + getTable();
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setMatch(matchBuilder.build());
+        flowBuilder.setPriority(0);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        writeFlow(flowBuilder, nodeBuilder);
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13Provider.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13Provider.java
new file mode 100644 (file)
index 0000000..356be18
--- /dev/null
@@ -0,0 +1,2003 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt.providers.openflow13;
+
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.MdsalHelper;
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.ClassifierProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
+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.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
+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.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.inventory.rev130819.tables.table.FlowBuilder;
+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.ApplyActionsCase;
+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.apply.actions._case.ApplyActionsBuilder;
+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.group.types.rev131018.BucketId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+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.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.CheckedFuture;
+
+
+/**
+ * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
+ *
+ * @author Madhu Venugopal
+ * @author Brent Salisbury
+ * @author Dave Tucker
+ * @author Sam Hague
+ */
+// Methods' parameters in this class follow the same pattern to avoid confusion between same-typed parameters
+// The patterns need to be preserved even though not all parameters are used in all methods
+@SuppressWarnings("UnusedParameters")
+public class OF13Provider implements ConfigInterface, NetworkingProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(OF13Provider.class);
+    private static final short TABLE_0_DEFAULT_INGRESS = 0;
+    private static final short TABLE_1_ISOLATE_TENANT = 10;
+    private static final short TABLE_2_LOCAL_FORWARD = 20;
+    private static Long groupId = 1L;
+    private DataBroker dataBroker = null;
+
+    private volatile ConfigurationService configurationService;
+    private volatile BridgeConfigurationManager bridgeConfigurationManager;
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile SecurityServicesManager securityServicesManager;
+    private volatile ClassifierProvider classifierProvider;
+    private volatile IngressAclProvider ingressAclProvider;
+    private volatile EgressAclProvider egressAclProvider;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile L2ForwardingProvider l2ForwardingProvider;
+
+    public static final String NAME = "OF13Provider";
+    private volatile BundleContext bundleContext;
+    private volatile Southbound southbound;
+
+    private Set<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId>
+                    intBridgesWithoutVmPorts = new HashSet<>();
+
+    public OF13Provider() {
+        this.dataBroker = NetvirtProvidersProvider.getDataBroker();
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public boolean supportsServices() {
+        return true;
+    }
+
+    @Override
+    public boolean hasPerTenantTunneling() {
+        return false;
+    }
+
+    // The method is tested for in OF13ProviderTest
+    @SuppressWarnings("unused")
+    private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
+        InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
+        if (srcTunnelEndPoint == null) {
+            LOG.error("Tunnel Endpoint not configured for Node {}", node);
+            return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
+        }
+
+        if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
+            LOG.error("{} is not Overlay ready", node);
+            return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
+        }
+
+        if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
+            LOG.debug("{} has no VM corresponding to segment {}", node, tunnelKey);
+            return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
+        }
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    private String getTunnelName(String tunnelType, InetAddress dst) {
+        return tunnelType+"-"+dst.getHostAddress();
+    }
+
+    private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
+        String tunnelBridgeName = configurationService.getIntegrationBridgeName();
+        String portName = getTunnelName(tunnelType, dst);
+        LOG.info("addTunnelPort enter: portName: {}", portName);
+        if (southbound.extractTerminationPointAugmentation(node, portName) != null
+                || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
+            LOG.info("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
+            return true;
+        }
+
+        Map<String, String> options = Maps.newHashMap();
+        options.put("key", "flow");
+        options.put("local_ip", src.getHostAddress());
+        options.put("remote_ip", dst.getHostAddress());
+
+        if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
+            LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
+            return false;
+        }
+
+            LOG.info("addTunnelPort exit: portName: {}", portName);
+        return true;
+    }
+
+    /* delete port from ovsdb port table */
+    private boolean deletePort(Node node, String bridgeName, String portName) {
+        // TODO SB_MIGRATION
+        // might need to convert from ovsdb node to bridge node
+        return southbound.deleteTerminationPoint(node, portName);
+    }
+
+    private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
+        String tunnelBridgeName = configurationService.getIntegrationBridgeName();
+        String portName = getTunnelName(tunnelType, dst);
+        return deletePort(node, tunnelBridgeName, portName);
+    }
+
+    private boolean deletePhysicalPort(Node node, String phyIntfName) {
+        String intBridgeName = configurationService.getIntegrationBridgeName();
+        return deletePort(node, intBridgeName, phyIntfName);
+    }
+
+    private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
+                                         String attachedMac, long localPort) {
+        /*
+         * Table(0) Rule #3
+         * ----------------
+         * Match: VM sMac and Local Ingress Port
+         * Action:Action: Set Tunnel ID and GOTO Local Table (5)
+         */
+
+        handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
+                segmentationId, localPort, attachedMac, true);
+
+        /*
+         * Table(0) Rule #4
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
+
+        handleDropSrcIface(dpid, localPort, true);
+
+        /*
+         * Table(2) Rule #1
+         * ----------------
+         * Match: Match TunID and Destination DL/dMAC Addr
+         * Action: Output Port
+         * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+         */
+
+        handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
+
+        /*
+         * Table(2) Rule #2
+         * ----------------
+         * Match: Tunnel ID and dMAC (::::FF:FF)
+         * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:2,3,4,5
+         */
+
+        handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
+        handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
+
+        /*
+         * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
+         */
+        /*
+         * Table(1) Rule #3
+         * ----------------
+         * Match:  Any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         * -------------------------------------------
+         * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
+         */
+
+        handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
+
+        /*
+         * Table(2) Rule #3
+         * ----------------
+         * Match: Any Remaining Flows w/a TunID
+         * Action: Drop w/ a low priority
+         * table=2,priority=8192,tun_id=0x5 actions=drop
+         */
+
+        handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
+    }
+
+    private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
+        /*
+         * Table(0) Rule #3
+         * ----------------
+         * Match: VM sMac and Local Ingress Port
+         * Action:Action: Set Tunnel ID and GOTO Local Table (5)
+         */
+
+        handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
+
+        /*
+         * Table(0) Rule #4
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
+
+        handleDropSrcIface(dpid, localPort, false);
+
+        /*
+         * Table(2) Rule #1
+         * ----------------
+         * Match: Match TunID and Destination DL/dMAC Addr
+         * Action: Output Port
+         * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+         */
+
+        handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
+
+        /*
+         * Table(2) Rule #2
+         * ----------------
+         * Match: Tunnel ID and dMAC (::::FF:FF)
+         * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:2,3,4,5
+         */
+
+        handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
+        handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
+    }
+
+    private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
+        /*
+         * Table(0) Rule #2
+         * ----------------
+         * Match: Ingress Port, Tunnel ID
+         * Action: GOTO Local Table (20)
+         */
+
+        handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
+         * Action: Flood to selected destination TEPs
+         * -------------------------------------------
+         * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10,output:11,goto_table:2
+         */
+
+        handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
+
+    }
+
+    private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
+        /*
+         * Table(1) Rule #1
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         * -------------------------------------------
+         * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+         * actions=output:11,goto_table:2
+         */
+
+        handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
+    }
+
+    private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
+        /*
+         * Table(1) Rule #1
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         * -------------------------------------------
+         * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+         * actions=output:11,goto_table:2
+         */
+
+        handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
+    }
+
+    /* Remove tunnel rules if last node in this tenant network */
+    private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
+        /*
+         * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
+         */
+        /*
+         * Table(1) Rule #3
+         * ----------------
+         * Match:  Any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         * -------------------------------------------
+         * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
+         */
+
+        handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
+
+        /*
+         * Table(2) Rule #3
+         * ----------------
+         * Match: Any Remaining Flows w/a TunID
+         * Action: Drop w/ a low priority
+         * table=2,priority=8192,tun_id=0x5 actions=drop
+         */
+
+        handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
+
+        /*
+         * Table(0) Rule #2
+         * ----------------
+         * Match: Ingress Port, Tunnel ID
+         * Action: GOTO Local Table (10)
+         */
+
+        handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
+         * Action: Flood to selected destination TEPs
+         * -------------------------------------------
+         * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10,output:11,goto_table:2
+         */
+
+        handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
+    }
+
+    private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
+        /*
+         * Table(0) Rule #1
+         * ----------------
+         * Tag traffic coming from the local port and vm srcmac
+         * Match: VM sMac and Local Ingress Port
+         * Action: Set VLAN ID and GOTO Local Table 1
+         */
+
+        handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
+                TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
+                attachedMac, true);
+
+        /*
+         * Table(0) Rule #3
+         * ----------------
+         * Drop all other traffic coming from the local port
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
+
+        handleDropSrcIface(dpid, localPort, true);
+
+        /*
+         * Table(2) Rule #1
+         * ----------------
+         * Forward unicast traffic destined to the local port after stripping tag
+         * Match: Match VLAN ID and Destination DL/dMAC Addr
+         * Action: strip vlan, output to local port
+         * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
+         */
+
+        handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                localPort, attachedMac, true);
+
+        /*
+         * Table(2) Rule #2
+         * ----------------
+         * Match: VLAN ID and dMAC (::::FF:FF)
+         * Action: strip vlan, output to all local ports in this vlan
+         * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions= strip_vlan, output:2,3,4,5
+         */
+
+        //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+        //        localPort, ethPort, true);
+        //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+        //        segmentationId, localPort, ethport, true);
+
+        /*
+         * Table(2) Rule #3
+         * ----------------
+         * Match: Any Remaining Flows w/a VLAN ID
+         * Action: Drop w/ a low priority
+         * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
+         */
+
+        //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+        //        true);
+    }
+
+    private void removeLocalVlanRules(Node node, Long dpid,
+                                      String segmentationId, String attachedMac, long localPort) {
+        /*
+         * Table(0) Rule #1
+         * ----------------
+         * Match: VM sMac and Local Ingress Port
+         * Action: Set VLAN ID and GOTO Local Table 1
+         */
+
+        handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
+                TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
+                attachedMac, false);
+
+        /*
+         * Table(0) Rule #3
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
+
+        handleDropSrcIface(dpid, localPort, false);
+
+        /*
+         * Table(2) Rule #1
+         * ----------------
+         * Match: Match VLAN ID and Destination DL/dMAC Addr
+         * Action: strip vlan, output to local port
+         * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
+         */
+
+        handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                localPort, attachedMac, false);
+
+        /*
+         * Table(2) Rule #2
+         * ----------------
+         * Match: VLAN ID and dMAC (::::FF:FF)
+         * Action: strip vlan, output to all local ports in this vlan
+         * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions= strip_vlan, output:2,3,4,5
+         */
+
+        //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+        //        localPort, ethPort, false);
+        //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+        //        segmentationId, localPort, false);
+
+    }
+
+    private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
+                                              long localPort, long ethPort) {
+        /*
+         * Table(0) Rule #2
+         * ----------------
+         * Match: Ingress port = physical interface, Vlan ID
+         * Action: GOTO Local Table 2
+         */
+
+        handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
+                segmentationId, ethPort, true);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+         * Action: Flood to local and remote VLAN members
+         * -------------------------------------------
+         * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10 (eth port),goto_table:2
+         * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
+         */
+
+        handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+         * Action: Flood to local and remote VLAN members
+         * -------------------------------------------
+         * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10 (eth port),goto_table:2
+         */
+
+        //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+        //        segmentationId, ethPort, true);
+    }
+
+    private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
+                                              String attachedMac, long ethPort) {
+        /*
+         * Table(1) Rule #1
+         * ----------------
+         * Match: Destination MAC is local VM MAC and vlan id
+         * Action: go to table 2
+         * -------------------------------------------
+         * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+         * actions=goto_table:2
+         */
+
+        //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+        //        segmentationId, ethPort, attachedMac, true);
+
+        /*
+         * Table(1) Rule #3
+         * ----------------
+         * Match:  VLAN ID
+         * Action: Go to table 2
+         * -------------------------------------------
+         * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
+         * table=110,priority=8192,dl_vlan=2001 actions=output:2
+         */
+
+        handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
+    }
+
+    private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
+                                             String attachedMac, long localPort, long ethPort) {
+        /*
+         * Table(1) Rule #1
+         * ----------------
+         * Match: Destination MAC is local VM MAC and vlan id
+         * Action: go to table 2
+         * -------------------------------------------
+         * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+         * actions=goto_table:2
+         */
+
+        //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+        //        segmentationId, ethPort, attachedMac, false);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+         * Action: Flood to local and remote VLAN members
+         * -------------------------------------------
+         * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10 (eth port),goto_table:2
+         * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
+         */
+
+        handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
+    }
+
+    private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
+        /*
+         * Table(2) Rule #3
+         * ----------------
+         * Match: Any Remaining Flows w/a VLAN ID
+         * Action: Drop w/ a low priority
+         * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
+         */
+
+        //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
+
+        /*
+         * Table(0) Rule #2
+         * ----------------
+         * Match: Ingress port = physical interface, Vlan ID
+         * Action: GOTO Local Table 2
+         */
+
+        handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+         * Action: Flood to local and remote VLAN members
+         * -------------------------------------------
+         * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10 (eth port),goto_table:2
+         * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
+         */
+
+        //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
+
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+         * Action: Flood to local and remote VLAN members
+         * -------------------------------------------
+         * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10 (eth port),goto_table:2
+         */
+
+        //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+        //        segmentationId, ethPort, false);
+
+        /*
+         * Table(1) Rule #3
+         * ----------------
+         * Match:  VLAN ID
+         * Action: Go to table 2
+         * -------------------------------------------
+         * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
+         * table=110,priority=8192,dl_vlan=2001 actions=output:2
+         */
+
+        handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
+    }
+
+    private long getDpid(Node node) {
+        long dpid = southbound.getDataPathId(node);
+        if (dpid == 0) {
+            LOG.warn("getDpid: dpid not found: {}", node);
+        }
+        return dpid;
+    }
+
+    private long getIntegrationBridgeOFDPID(Node node) {
+        long dpid = 0L;
+        if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
+            dpid = getDpid(node);
+        }
+        return dpid;
+    }
+
+    /**
+     * Returns true is the network if of type GRE or VXLAN
+     *
+     * @param networkType The type of the network
+     * @return returns true if the network is a tunnel
+     */
+    private boolean isTunnel(String networkType)
+    {
+        return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
+                (NetworkHandler.NETWORK_TYPE_VXLAN));
+    }
+
+    /**
+     * Returns true if the network is of type vlan.
+     *
+     * @param networkType The type of the network
+     * @return returns true if the network is a vlan
+     */
+    private boolean isVlan(String networkType)
+    {
+        return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
+    }
+
+    private void programLocalRules(String networkType, String segmentationId, Node node,
+                                    OvsdbTerminationPointAugmentation intf) {
+        LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
+                node.getNodeId(), intf.getName(), networkType, segmentationId);
+        try {
+            long dpid = getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
+                        node);
+                return;
+            }
+
+            long localPort = southbound.getOFPort(intf);
+            if (localPort == 0) {
+                LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}",
+                         intf.getName(), node.getNodeId());
+                return;
+            }
+
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.warn("No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            /* Program local rules based on network type */
+            if (isVlan(networkType)) {
+                LOG.debug("Program local vlan rules for interface {}", intf.getName());
+                programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
+            }
+            if ((isTunnel(networkType) || isVlan(networkType))) {
+                programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
+            }
+            if (isTunnel(networkType)) {
+                LOG.debug("Program local bridge rules for interface {}, "
+                                + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
+                        intf.getName(), dpid, segmentationId, attachedMac, localPort);
+                programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
+            }
+        } catch (Exception e) {
+            LOG.error("Exception in programming Local Rules for {} on {}", intf, node, e);
+        }
+    }
+
+    private void removeLocalRules(String networkType, String segmentationId, Node node,
+                                   OvsdbTerminationPointAugmentation intf) {
+        LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
+                node.getNodeId(), intf.getName(), networkType, segmentationId);
+        try {
+            long dpid = getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+
+            long localPort = southbound.getOFPort(intf);
+            if (localPort == 0) {
+                LOG.info("removeLocalRules: could not find ofPort");
+                return;
+            }
+
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.warn("No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            /* Program local rules based on network type */
+            if (isVlan(networkType)) {
+                LOG.debug("Remove local vlan rules for interface {}", intf.getName());
+                removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
+            } else if (isTunnel(networkType)) {
+                LOG.debug("Remove local bridge rules for interface {}", intf.getName());
+                removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
+            }
+            if (isTunnel(networkType) || isVlan(networkType)) {
+                programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
+            }
+        } catch (Exception e) {
+            LOG.error("Exception in removing Local Rules for {} on {}", intf, node, e);
+        }
+    }
+
+    private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
+                                     OvsdbTerminationPointAugmentation intf, boolean local) {
+        LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
+                        + "segmentationId: {}, dstAddr: {}",
+                node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
+        try {
+            long dpid = getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+
+            long localPort = southbound.getOFPort(intf);
+            if (localPort == 0) {
+                LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
+                return;
+            }
+
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
+            if (tunnelPort != null){
+                long tunnelOFPort = southbound.getOFPort(tunnelPort);
+                if (tunnelOFPort == 0) {
+                    LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
+                            tunnelPort.getName(), tunnelOFPort, node);
+                    return;
+                }
+                LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
+                        tunnelPort.getName(), tunnelOFPort, node);
+
+                if (!local) {
+                    LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
+                            node.getNodeId().getValue(), intf.getName());
+                    programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
+                            tunnelOFPort, localPort);
+                } else {
+                    LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
+                            node.getNodeId().getValue(), intf.getName());
+                    programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
+                            tunnelOFPort, localPort);
+                }
+            }
+        } catch (Exception e) {
+            LOG.warn("Failed to program tunnel rules, node {}, intf {}", node, intf, e);
+        }
+    }
+
+    private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
+                                    OvsdbTerminationPointAugmentation intf,
+                                    boolean local, boolean isLastInstanceOnNode) {
+        LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
+                        + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
+                node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
+        try {
+            long dpid = getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+
+            long localPort = southbound.getOFPort(intf);
+            if (localPort == 0) {
+                LOG.info("removeTunnelRules: could not find ofPort");
+                return;
+            }
+
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
+            for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
+                if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
+                    long tunnelOFPort = southbound.getOFPort(tunIntf);
+                    if (tunnelOFPort == 0) {
+                        LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
+                                tunIntf.getName(), tunnelOFPort, node);
+                        return;
+                    }
+                    LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
+                            tunIntf.getName(), tunnelOFPort, node);
+
+                    if (!local) {
+                        removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
+                                tunnelOFPort, localPort);
+                    }
+                    if (local && isLastInstanceOnNode) {
+                        removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
+                    }
+                    return;
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Failed to remove tunnel rules, node {}, intf {}", node, intf, e);
+        }
+    }
+
+    private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
+        LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
+                node.getNodeId(), network.getNetworkUUID(), intf.getName());
+        long dpid = getIntegrationBridgeOFDPID(node);
+        if (dpid == 0L) {
+            LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
+            return;
+        }
+
+        long localPort = southbound.getOFPort(intf);
+        if (localPort == 0) {
+            LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
+            return;
+        }
+
+        String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+        if (attachedMac == null) {
+            LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
+            return;
+        }
+
+        String phyIfName =
+                bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
+        long ethOFPort = southbound.getOFPort(node, phyIfName);
+        if (ethOFPort == 0) {
+            LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
+            return;
+        }
+        LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
+                phyIfName, ethOFPort, node);
+        // TODO: add logic to only add rule on remote nodes
+        programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
+                attachedMac, ethOFPort);
+        programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
+                attachedMac, localPort, ethOFPort);
+    }
+
+    private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
+                                  boolean isLastInstanceOnNode) {
+        LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
+                node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
+        long dpid = getIntegrationBridgeOFDPID(node);
+        if (dpid == 0L) {
+            LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
+            return;
+        }
+
+        long localPort = southbound.getOFPort(intf);
+        if (localPort == 0) {
+            LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
+            return;
+        }
+
+        String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+        if (attachedMac == null) {
+            LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
+            return;
+        }
+
+        String phyIfName =
+                bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
+        long ethOFPort = southbound.getOFPort(node, phyIfName);
+        if (ethOFPort == 0) {
+            LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
+            return;
+        }
+        LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
+                phyIfName, ethOFPort, node);
+
+        removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
+                attachedMac, localPort, ethOFPort);
+        if (isLastInstanceOnNode) {
+            removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
+        }
+    }
+
+    private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
+                                                Long dpid,long localPort, String segmentationId,
+                                                boolean write) {
+
+        LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
+        boolean isPortSecurityEnabled = securityServicesManager.isPortSecurityEnabled(intf);
+        if (!isPortSecurityEnabled) {
+            LOG.info("Port security is not enabled" + intf);
+            return;
+        }
+        NeutronPort dhcpPort = securityServicesManager.getDhcpServerPort(intf);
+        List<Neutron_IPs> srcAddressList = null;
+        if (null != dhcpPort) {
+            srcAddressList = securityServicesManager.getIpAddressList(intf);
+            if (null == srcAddressList) {
+                LOG.warn("programLocalRules: No Ip address assigned {}", intf);
+                return;
+            }
+            ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
+                                                         attachedMac, write);
+            egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
+                                                        srcAddressList, write);
+            /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
+            /* TODO SB_MIGRATION */
+
+            LOG.debug("Neutron port has a Port Security Group");
+            // Retrieve the security group from the Neutron Port and apply the rules
+            List<NeutronSecurityGroup> securityGroupListInPort = securityServicesManager
+                    .getSecurityGroupInPortList(intf);
+            String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
+                                                                           Constants.EXTERNAL_ID_INTERFACE_ID);
+            for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
+                ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
+                                                            securityGroupInPort, neutronPortId, write);
+                egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
+                                                           securityGroupInPort, neutronPortId, write);
+            }
+
+        } else {
+            LOG.warn("programLocalRules: No DCHP port seen in  network of {}", intf);
+        }
+    }
+
+    /*
+     * The function is for the new compute node joining the existing network.
+     * When a new VM is instantiated in the new compute node, neutron port add
+     * event is generated. This event is processed only for that node. So,
+     * loop through all the ports of the same network and install unicast mac
+     * flow for the VM's created on the TEP of the destination node in src node.
+     * This function will be executed even for any new VM creation in an existing
+     * network. If a cache is maintained to optimize the below flow addition, it will
+     * work only for one unstack and restack. For the next unstack and restack,
+     * it will not work since the cache would have been already deleted.
+     */
+    private void programTunnelRulesInNewNode(NeutronNetwork network,
+                                             String networkType, String segmentationId,
+                                             InetAddress src, InetAddress dst,
+                                             Node srcBridgeNode, Node dstBridgeNode,
+                                             OvsdbTerminationPointAugmentation intf){
+        LOG.debug("programTunnelRulesInNewNode: network {} networkType {} segId {} src {} dst {} srcBridgeNode {} dstBridgeNode {} intf {}",
+                    network.getNetworkName(), networkType, segmentationId, src.getHostAddress(),
+                    dst.getHostAddress(), srcBridgeNode, dstBridgeNode, intf);
+        try {
+            long localPort = southbound.getOFPort(intf);
+            if (localPort != 0)
+            {
+                LOG.debug("Interface update details {}", intf);
+
+                /*
+                 * When a network is added and the TEP destination is not present in a
+                 * node C1, tunnelin and broadcast rules will not be programmed, since
+                 * OF port is not created. So, when a new node C2 joins and create a new
+                 * VM, the tunnelin and broadcast rule will not be present in C1.
+                 * So, handling it in the case below to make ping work.
+                 */
+                if (securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
+                    programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
+                }
+
+                /*
+                 * FIX for 4208 - loop through all the ports and add the VM's
+                 * unicast mac rule of the destination node in the source node.
+                 * When a new node is added, it needs to configure the VM unicast mac
+                 * flow rules which were created before it was joined to an existing
+                 * network.
+                 */
+                List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
+                for (OvsdbTerminationPointAugmentation port : ports) {
+
+                    NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
+                    if (neutronNetwork != null) {
+                        String netType = neutronNetwork.getProviderNetworkType();
+                        String segId = neutronNetwork.getProviderSegmentationID();
+                        InetAddress dstAddr = configurationService.getTunnelEndPoint(dstBridgeNode);
+
+                        if (segId != null && netType != null && dstAddr != null) {
+                            programTunnelRules(netType, segId, dstAddr, srcBridgeNode, port, false);
+                        }
+                    }
+
+                    if (network == tenantNetworkManager.getTenantNetwork(port)){
+                        programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
+                    }
+                    else{
+                        LOG.trace("Port {} is not part of network {}", port, network);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Exception during handlingNeutron network add", e);
+        }
+    }
+
+    private boolean bridgeHasVmPort(Node bridgeNode) {
+        String intBridgeName = configurationService.getIntegrationBridgeName();
+        String extBridgeName = configurationService.getExternalBridgeName();
+        List<TerminationPoint> terminationPoints = bridgeNode.getTerminationPoint();
+        if (terminationPoints == null) return false;
+
+        for (TerminationPoint tp : terminationPoints) {
+            String tpName = tp.getTpId().getValue();
+            if (tpName != null && !tpName.equals(intBridgeName) && !tpName.equals(extBridgeName)) {
+                OvsdbTerminationPointAugmentation tpAug = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if (tpAug != null && southbound.getOFPort(tpAug) != 0) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode, OvsdbTerminationPointAugmentation intf) {
+        LOG.debug("handleInterfaceUpdate: network: {} srcNode: {}, intf: {}",
+                    network.getProviderSegmentationID(), srcNode.getNodeId(), intf.getName());
+        Preconditions.checkNotNull(nodeCacheManager);
+
+        org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId srcNodeId =
+                srcNode.getNodeId();
+        Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
+                nodeCacheManager.getOvsdbNodes();
+
+        nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
+        String networkType = network.getProviderNetworkType();
+        String segmentationId = network.getProviderSegmentationID();
+        Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
+
+        programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
+
+        if (isVlan(networkType)) {
+            programVlanRules(network, srcNode, intf);
+        } else if (isTunnel(networkType)){
+
+            boolean sourceTunnelStatus = false;
+            boolean destTunnelStatus = false;
+            for (Node dstNode : nodes.values()) {
+                InetAddress src = configurationService.getTunnelEndPoint(srcNode);
+                InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
+                if ((src != null) && (dst != null)) {
+                    sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
+
+                    Node dstBridgeNode = southbound.getBridgeNode(dstNode,
+                            configurationService.getIntegrationBridgeName());
+
+                    if (dstBridgeNode != null){
+                        destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
+                    }
+
+                    if (sourceTunnelStatus) {
+                        programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
+                    }
+                    if (destTunnelStatus) {
+                        programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
+
+                        if (srcNodeId != null && intBridgesWithoutVmPorts.contains(srcNodeId)) {
+                            programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
+                                    srcBridgeNode, dstBridgeNode, intf);
+                            intBridgesWithoutVmPorts.remove(srcNodeId);
+                        }
+                    }
+                } else {
+                    LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
+                                    + "Check source {} or destination {}",
+                            src != null ? src.getHostAddress() : "null",
+                            dst != null ? dst.getHostAddress() : "null");
+                }
+            }
+        }
+
+        if (srcNodeId != null && !bridgeHasVmPort(srcNode)) {
+            intBridgesWithoutVmPorts.add(srcNodeId);
+        }
+
+        return true;
+    }
+
+    private void triggerInterfaceUpdates(Node node) {
+        LOG.debug("enter triggerInterfaceUpdates for {}", node.getNodeId());
+        List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
+        if (ports != null && !ports.isEmpty()) {
+            for (OvsdbTerminationPointAugmentation port : ports) {
+                NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
+                if (neutronNetwork != null) {
+                    LOG.warn("Trigger Interface update for {}", port);
+                    handleInterfaceUpdate(neutronNetwork, node, port);
+                }
+            }
+        } else {
+            LOG.warn("triggerInterfaceUpdates: tps are null");
+        }
+        LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
+    }
+
+    @Override
+    public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
+                                         OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
+        Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
+                nodeCacheManager.getOvsdbNodes();
+        nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
+
+        LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
+        List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
+        if (southbound.isTunnel(intf)) {
+            // Delete tunnel port
+            try {
+                InetAddress src = InetAddress.getByName(
+                        southbound.getOptionsValue(intf.getOptions(), "local_ip"));
+                InetAddress dst = InetAddress.getByName(
+                        southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
+                deleteTunnelPort(srcNode,
+                        MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
+                        src, dst);
+            } catch (Exception e) {
+                LOG.error("handleInterfaceDelete: failed to delete tunnel port", e);
+            }
+        } else if (phyIfName.contains(intf.getName())) {
+            deletePhysicalPort(srcNode, intf.getName());
+        } else {
+            // delete all other interfaces
+            removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
+                    srcNode, intf);
+
+            if (isVlan(network.getProviderNetworkType())) {
+                removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
+            } else if (isTunnel(network.getProviderNetworkType())) {
+
+                for (Node dstNode : nodes.values()) {
+                    InetAddress src = configurationService.getTunnelEndPoint(srcNode);
+                    InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
+                    if ((src != null) && (dst != null)) {
+                        LOG.info("Remove tunnel rules for interface "
+                                + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
+                        removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
+                                dst, srcNode, intf, true, isLastInstanceOnNode);
+                        Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
+                        if (dstBridgeNode != null){
+                            LOG.info("Remove tunnel rules for interface "
+                                    + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
+                            removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
+                                    src, dstBridgeNode, intf, false, isLastInstanceOnNode);
+                        }
+                    } else {
+                        LOG.warn("Tunnel end-point configuration missing. Please configure it in "
+                                        + "OpenVSwitch Table. "
+                                        + "Check source {} or destination {}",
+                                src != null ? src.getHostAddress() : "null",
+                                dst != null ? dst.getHostAddress() : "null");
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void initializeFlowRules(Node node) {
+        initializeFlowRules(node, configurationService.getIntegrationBridgeName());
+        initializeFlowRules(node, configurationService.getExternalBridgeName());
+        triggerInterfaceUpdates(node);
+    }
+
+    private void initializeFlowRules(Node node, String bridgeName) {
+        Long dpid = southbound.getDataPathId(node);
+        String datapathId = southbound.getDatapathId(node);
+        LOG.info("initializeFlowRules: bridgeName: {}, dpid: {} - {}",
+                bridgeName, dpid, datapathId);
+
+        if (dpid == 0L) {
+            LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
+            return;
+        }
+
+        /*
+         * Table(0) Rule #1
+         * ----------------
+         * Match: LLDP (0x88CCL)
+         * Action: Packet_In to Controller Reserved Port
+         */
+
+        writeLLDPRule(dpid);
+
+        if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
+                NetvirtProvidersProvider.getTableOffset() != 0) {
+            classifierProvider.programGotoTable(dpid,true);
+        }
+
+        if (bridgeName.equals(configurationService.getExternalBridgeName())) {
+            writeNormalRule(dpid);
+        }
+    }
+
+    /*
+     * Create an LLDP Flow Rule to encapsulate into
+     * a packet_in that is sent to the controller
+     * for topology handling.
+     * Match: Ethertype 0x88CCL
+     * Action: Punt to Controller in a Packet_In msg
+     */
+
+    private void writeLLDPRule(Long dpidLong) {
+        classifierProvider.programLLDPPuntRule(dpidLong);
+    }
+
+    /*
+     * Create a NORMAL Table Miss Flow Rule
+     * Match: any
+     * Action: forward to NORMAL pipeline
+     */
+
+    private void writeNormalRule(Long dpidLong) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "NORMAL";
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Create the OF Actions and Instructions
+        InstructionBuilder ib = new InstructionBuilder();
+        InstructionsBuilder isb = new InstructionsBuilder();
+
+        // Instructions List Stores Individual Instructions
+        List<Instruction> instructions = Lists.newArrayList();
+
+        // Call the InstructionBuilder Methods Containing Actions
+        InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
+        ib.setOrder(0);
+        ib.setKey(new InstructionKey(0));
+        instructions.add(ib.build());
+
+        // Add InstructionBuilder to the Instruction(s)Builder List
+        isb.setInstruction(instructions);
+
+        // Add InstructionsBuilder to FlowBuilder
+        flowBuilder.setInstructions(isb.build());
+        writeFlow(flowBuilder, nodeBuilder);
+    }
+
+    /*
+     * (Table:0) Ingress Tunnel Traffic
+     * Match: OpenFlow InPort and Tunnel ID
+     * Action: GOTO Local Table (10)
+     * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
+     */
+
+    private void handleTunnelIn(Long dpidLong, Short writeTable,
+            Short goToTableId, String segmentationId,
+            Long ofPort, boolean write) {
+        classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
+    }
+
+    /*
+     * (Table:0) Ingress VLAN Traffic
+     * Match: OpenFlow InPort and vlan ID
+     * Action: GOTO Local Table (20)
+     * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
+     */
+
+    private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
+            String segmentationId,  Long ethPort, boolean write) {
+        classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
+    }
+
+    /*
+     * (Table:0) Egress VM Traffic Towards TEP
+     * Match: Destination Ethernet Addr and OpenFlow InPort
+     * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+     * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
+     * actions=set_field:5->tun_id,goto_table=1"
+     */
+
+    private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
+            String segmentationId, Long inPort, String attachedMac,
+            boolean write) {
+        classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
+    }
+
+    /*
+     * (Table:0) Egress VM Traffic Towards TEP
+     * Match: Source Ethernet Addr and OpenFlow InPort
+     * Instruction: Set VLANID and GOTO Table Egress (n)
+     * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
+     * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
+     */
+
+    private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
+            Short goToTableId, String segmentationId,
+            Long inPort, String attachedMac,
+            boolean write) {
+        classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
+    }
+
+    /*
+     * (Table:0) Drop frames source from a VM that do not
+     * match the associated MAC address of the local VM.
+     * Match: Low priority anything not matching the VM SMAC
+     * Instruction: Drop
+     * table=0,priority=16384,in_port=1 actions=drop"
+     */
+
+    private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
+        classifierProvider.programDropSrcIface(dpidLong, inPort, write);
+    }
+
+    /*
+     * (Table:1) Egress Tunnel Traffic
+     * Match: Destination Ethernet Addr and Local InPort
+     * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+     * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+     * actions=output:10,goto_table:2"
+     */
+    private void handleTunnelOut(Long dpidLong, Short writeTable,
+            Short goToTableId, String segmentationId,
+            Long OFPortOut, String attachedMac,
+            boolean write) {
+        l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
+    }
+
+    /*
+     * (Table:1) Egress VLAN Traffic
+     * Match: Destination Ethernet Addr and VLAN id
+     * Instruction: GOTO Table Table 2
+     * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+     * actions= goto_table:2"
+     */
+    // TODO This method is referenced from commented code above (which needs to be checked)
+    @SuppressWarnings("unused")
+    private void handleVlanOut(Long dpidLong, Short writeTable,
+            Short goToTableId, String segmentationId,
+            Long ethPort, String attachedMac, boolean write) {
+        l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
+    }
+
+    /*
+     * (Table:1) Egress Tunnel Traffic
+     * Match: Destination Ethernet Addr and Local InPort
+     * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+     * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:10,output:11,goto_table:2
+     */
+
+    private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
+            Short localTable, String segmentationId,
+            Long OFPortOut, boolean write) {
+        l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
+    }
+
+    /*
+     * (Table:1) Egress VLAN Traffic
+     * Match: Destination Ethernet Addr and VLAN id
+     * Instruction: GOTO table 2 and Output port eth interface
+     * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:eth1,goto_table:2
+     */
+    // TODO This method is referenced from commented code above (which needs to be checked)
+    @SuppressWarnings("unused")
+    private void handleVlanFloodOut(Long dpidLong, Short writeTable,
+            Short localTable, String segmentationId,
+            Long localPort, Long ethPort, boolean write) {
+        //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
+    }
+
+    /*
+     * (Table:1) Table Drain w/ Catch All
+     * Match: Tunnel ID
+     * Action: GOTO Local Table (10)
+     * table=2,priority=8192,tun_id=0x5 actions=drop
+     */
+
+    private void handleTunnelMiss(Long dpidLong, Short writeTable,
+            Short goToTableId, String segmentationId,
+            boolean write) {
+        l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
+    }
+
+
+    /*
+     * (Table:1) Table Drain w/ Catch All
+     * Match: Vlan ID
+     * Action: Output port eth interface
+     * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
+     * table=110,priority=8192,dl_vlan=2001 actions=output:2
+     */
+
+    private void handleVlanMiss(Long dpidLong, Short writeTable,
+            Short goToTableId, String segmentationId,
+            Long ethPort, boolean write) {
+        l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
+    }
+
+    /*
+     * (Table:1) Local Broadcast Flood
+     * Match: Tunnel ID and dMAC
+     * Action: Output Port
+     * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+     */
+
+    private void handleLocalUcastOut(Long dpidLong, Short writeTable,
+            String segmentationId, Long localPort,
+            String attachedMac, boolean write) {
+        l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
+    }
+
+    /*
+     * (Table:2) Local VLAN unicast
+     * Match: VLAN ID and dMAC
+     * Action: Output Port
+     * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+     */
+
+    private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
+            String segmentationId, Long localPort,
+            String attachedMac, boolean write) {
+        l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
+    }
+
+    /*
+     * (Table:2) Local Broadcast Flood
+     * Match: Tunnel ID and dMAC (::::FF:FF)
+     * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:2,3,4,5
+     */
+
+    private void handleLocalBcastOut(Long dpidLong, Short writeTable,
+            String segmentationId, Long localPort,
+            boolean write) {
+        l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
+    }
+
+    /*
+     * (Table:2) Local VLAN Broadcast Flood
+     * Match: vlan ID and dMAC (::::FF:FF)
+     * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=strip_vlan, output:2,3,4,5
+     * table=110,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
+     */
+
+    private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
+                                         Long localPort, Long ethPort, boolean write) {
+        l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
+    }
+
+    /*
+     * (Table:1) Local Table Miss
+     * Match: Any Remaining Flows w/a TunID
+     * Action: Drop w/ a low priority
+     * table=2,priority=8192,tun_id=0x5 actions=drop
+     */
+
+    private void handleLocalTableMiss(Long dpidLong, Short writeTable,
+            String segmentationId, boolean write) {
+        l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
+    }
+
+    /*
+     * (Table:1) Local Table Miss
+     * Match: Any Remaining Flows w/a VLAN ID
+     * Action: Drop w/ a low priority
+     * table=2,priority=8192,vlan_id=0x5 actions=drop
+     */
+    // TODO This method is referenced from commented code above (which needs to be checked)
+    @SuppressWarnings("unused")
+    private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
+            String segmentationId, boolean write) {
+        l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
+    }
+
+    private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
+        InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
+                        new GroupKey(groupBuilder.getGroupId())).build();
+        ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
+        try {
+            Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            LOG.error("Failed to get group {}", groupBuilder.getGroupName(), e);
+        }
+
+        LOG.debug("Cannot find data for Group {}", groupBuilder.getGroupName());
+        return null;
+    }
+
+    private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
+        if (NetvirtProvidersProvider.isMasterProviderInstance()) {
+            ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
+            InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                    .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
+                            new GroupKey(groupBuilder.getGroupId())).build();
+            modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
+
+            CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+            try {
+                commitFuture.get();  // TODO: Make it async (See bug 1362)
+                LOG.debug("Transaction success for write of Group {}", groupBuilder.getGroupName());
+            } catch (InterruptedException|ExecutionException e) {
+                LOG.error("Failed to write group {}", groupBuilder.getGroupName(), e);
+            }
+        }
+    }
+
+    private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
+        if (NetvirtProvidersProvider.isMasterProviderInstance()) {
+            WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
+            InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                    .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
+                            new GroupKey(groupBuilder.getGroupId())).build();
+            modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
+            CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+
+            try {
+                commitFuture.get();  // TODO: Make it async (See bug 1362)
+                LOG.debug("Transaction success for deletion of Group {}", groupBuilder.getGroupName());
+            } catch (InterruptedException|ExecutionException e) {
+                LOG.error("Failed to remove group {}", groupBuilder.getGroupName(), e);
+            }
+        }
+    }
+
+    private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        if (NetvirtProvidersProvider.isMasterProviderInstance()){
+            ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
+            InstanceIdentifier<Flow> path1 =
+                    InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                                    .rev130819.nodes.Node.class,
+                            nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
+                            new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
+
+            //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
+            modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
+                    true);//createMissingParents
+
+
+            CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+            try {
+                commitFuture.get();  // TODO: Make it async (See bug 1362)
+                LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
+            } catch (InterruptedException|ExecutionException e) {
+                LOG.error("Failed to write flows {}", flowBuilder.getFlowName(), e);
+            }
+        }
+    }
+
+    /**
+     * Create Output Port Group Instruction
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
+    @SuppressWarnings("unused")
+    protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
+            InstructionBuilder ib,
+            Long dpidLong, Long port ,
+            List<Instruction> instructions) {
+        NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
+        LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = Lists.newArrayList();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                }
+            }
+        }
+
+        GroupBuilder groupBuilder = new GroupBuilder();
+        Group group = null;
+
+        /* Create output action for this port*/
+        OutputActionBuilder oab = new OutputActionBuilder();
+        oab.setOutputNodeConnector(ncid);
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+        LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
+        boolean addNew = true;
+        boolean groupActionAdded = false;
+
+        /* Find the group action and get the group */
+        for (Action action : actionList) {
+            if (action.getAction() instanceof GroupActionCase) {
+                groupActionAdded = true;
+                GroupActionCase groupAction = (GroupActionCase) action.getAction();
+                Long id = groupAction.getGroupAction().getGroupId();
+                String groupName = groupAction.getGroupAction().getGroup();
+                GroupKey key = new GroupKey(new GroupId(id));
+
+                groupBuilder.setGroupId(new GroupId(id));
+                groupBuilder.setGroupName(groupName);
+                groupBuilder.setGroupType(GroupTypes.GroupAll);
+                groupBuilder.setKey(key);
+                group = getGroup(groupBuilder, nodeBuilder);
+                LOG.debug("createOutputGroupInstructions: group {}", group);
+                break;
+            }
+        }
+
+        LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
+        if (groupActionAdded) {
+            /* modify the action bucket in group */
+            groupBuilder = new GroupBuilder(group);
+            Buckets buckets = groupBuilder.getBuckets();
+            for (Bucket bucket : buckets.getBucket()) {
+                List<Action> bucketActions = bucket.getAction();
+                LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
+                for (Action action : bucketActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        OutputActionCase opAction = (OutputActionCase)action.getAction();
+                        /* If output port action already in the action list of one of the buckets, skip */
+                        if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+                            addNew = false;
+                            break;
+                        }
+                    }
+                }
+            }
+            LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
+            if (addNew && !buckets.getBucket().isEmpty()) {
+                /* the new output action is not in the bucket, add to bucket */
+                Bucket bucket = buckets.getBucket().get(0);
+                List<Action> bucketActionList = Lists.newArrayList();
+                bucketActionList.addAll(bucket.getAction());
+                /* set order for new action and add to action list */
+                ab.setOrder(bucketActionList.size());
+                ab.setKey(new ActionKey(bucketActionList.size()));
+                bucketActionList.add(ab.build());
+
+                /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
+                BucketsBuilder bucketsBuilder = new BucketsBuilder();
+                List<Bucket> bucketList = Lists.newArrayList();
+                BucketBuilder bucketBuilder = new BucketBuilder();
+                bucketBuilder.setBucketId(new BucketId((long) 1));
+                bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
+                bucketBuilder.setAction(bucketActionList);
+                bucketList.add(bucketBuilder.build());
+                bucketsBuilder.setBucket(bucketList);
+                groupBuilder.setBuckets(bucketsBuilder.build());
+                LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
+            }
+        } else {
+            /* create group */
+            groupBuilder = new GroupBuilder();
+            groupBuilder.setGroupType(GroupTypes.GroupAll);
+            groupBuilder.setGroupId(new GroupId(groupId));
+            groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
+            groupBuilder.setGroupName("Output port group " + groupId);
+            groupBuilder.setBarrier(false);
+
+            BucketsBuilder bucketBuilder = new BucketsBuilder();
+            List<Bucket> bucketList = Lists.newArrayList();
+            BucketBuilder bucket = new BucketBuilder();
+            bucket.setBucketId(new BucketId((long) 1));
+            bucket.setKey(new BucketKey(new BucketId((long) 1)));
+
+            /* put output action to the bucket */
+            List<Action> bucketActionList = Lists.newArrayList();
+            /* set order for new action and add to action list */
+            ab.setOrder(bucketActionList.size());
+            ab.setKey(new ActionKey(bucketActionList.size()));
+            bucketActionList.add(ab.build());
+
+            bucket.setAction(bucketActionList);
+            bucketList.add(bucket.build());
+            bucketBuilder.setBucket(bucketList);
+            groupBuilder.setBuckets(bucketBuilder.build());
+
+            /* Add new group action */
+            GroupActionBuilder groupActionB = new GroupActionBuilder();
+            groupActionB.setGroupId(groupId);
+            groupActionB.setGroup("Output port group " + groupId);
+            ab = new ActionBuilder();
+            ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            groupId++;
+        }
+        LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
+        LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
+
+        if (addNew) {
+            /* rewrite the group to group table */
+            writeGroup(groupBuilder, nodeBuilder);
+        }
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Remove Output Port from action list in group bucket
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
+    @SuppressWarnings("unused")
+    protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
+            Long dpidLong, Long port , List<Instruction> instructions) {
+
+        NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
+        LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = Lists.newArrayList();
+        ActionBuilder ab;
+
+        List<Action> existingActions;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                    break;
+                }
+            }
+        }
+
+        GroupBuilder groupBuilder = new GroupBuilder();
+        Group group = null;
+        boolean groupActionAdded = false;
+        /* Find the group action and get the group */
+        for (Action action : actionList) {
+            if (action.getAction() instanceof GroupActionCase) {
+                groupActionAdded = true;
+                GroupActionCase groupAction = (GroupActionCase) action.getAction();
+                Long id = groupAction.getGroupAction().getGroupId();
+                String groupName = groupAction.getGroupAction().getGroup();
+                GroupKey key = new GroupKey(new GroupId(id));
+
+                groupBuilder.setGroupId(new GroupId(id));
+                groupBuilder.setGroupName(groupName);
+                groupBuilder.setGroupType(GroupTypes.GroupAll);
+                groupBuilder.setKey(key);
+                group = getGroup(groupBuilder, nodeBuilder);
+                break;
+            }
+        }
+
+        if (groupActionAdded) {
+            /* modify the action bucket in group */
+            groupBuilder = new GroupBuilder(group);
+            Buckets buckets = groupBuilder.getBuckets();
+            List<Action> bucketActions = Lists.newArrayList();
+            for (Bucket bucket : buckets.getBucket()) {
+                int index = 0;
+                boolean isPortDeleted = false;
+                bucketActions = bucket.getAction();
+                for (Action action : bucketActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        OutputActionCase opAction = (OutputActionCase)action.getAction();
+                        if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+                            /* Find the output port in action list and remove */
+                            index = bucketActions.indexOf(action);
+                            bucketActions.remove(action);
+                            isPortDeleted = true;
+                            break;
+                        }
+                    }
+                }
+                if (isPortDeleted && !bucketActions.isEmpty()) {
+                    for (int i = index; i< bucketActions.size(); i++) {
+                        Action action = bucketActions.get(i);
+                        if (action.getOrder() != i) {
+                            /* Shift the action order */
+                            ab = new ActionBuilder();
+                            ab.setAction(action.getAction());
+                            ab.setOrder(i);
+                            ab.setKey(new ActionKey(i));
+                            Action actionNewOrder = ab.build();
+                            bucketActions.remove(action);
+                            bucketActions.add(i, actionNewOrder);
+                        }
+                    }
+
+                } else if (bucketActions.isEmpty()) {
+                    /* remove bucket with empty action list */
+                    buckets.getBucket().remove(bucket);
+                    break;
+                }
+            }
+            if (!buckets.getBucket().isEmpty()) {
+                /* rewrite the group to group table */
+                /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
+                BucketsBuilder bucketsBuilder = new BucketsBuilder();
+                List<Bucket> bucketList = Lists.newArrayList();
+                BucketBuilder bucketBuilder = new BucketBuilder();
+                bucketBuilder.setBucketId(new BucketId((long) 1));
+                bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
+                bucketBuilder.setAction(bucketActions);
+                bucketList.add(bucketBuilder.build());
+                bucketsBuilder.setBucket(bucketList);
+                groupBuilder.setBuckets(bucketsBuilder.build());
+                LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
+
+                writeGroup(groupBuilder, nodeBuilder);
+                ApplyActionsBuilder aab = new ApplyActionsBuilder();
+                aab.setAction(actionList);
+                ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+                return false;
+            } else {
+                /* remove group with empty bucket. return true to delete flow */
+                removeGroup(groupBuilder, nodeBuilder);
+                return true;
+            }
+        } else {
+            /* no group for port list. flow can be removed */
+            return true;
+        }
+    }
+
+    @Override
+    public void initializeOFFlowRules(Node openflowNode) {
+        String bridgeName = southbound.getBridgeName(openflowNode);
+        LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
+        if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
+            initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
+            triggerInterfaceUpdates(openflowNode);
+        } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
+            initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
+            LOG.info("initializeOFFlowRules after writeFlow: bridgeName: {}", bridgeName);
+            triggerInterfaceUpdates(openflowNode);
+            LOG.info("initializeOFFlowRules after triggerUpdates: bridgeName: {}", bridgeName);
+        }
+    }
+
+    public static NodeBuilder createNodeBuilder(String nodeId) {
+        NodeBuilder builder = new NodeBuilder();
+        builder.setId(new NodeId(nodeId));
+        builder.setKey(new NodeKey(builder.getId()));
+        return builder;
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        this.bundleContext = bundleContext;
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
+        bridgeConfigurationManager =
+                (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        classifierProvider =
+                (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
+        ingressAclProvider =
+                (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
+        egressAclProvider =
+                (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
+        l2ForwardingProvider =
+                (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof NetworkingProviderManager) {
+            NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
+            networkingProviderManager.providerAdded(
+                    bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);
+        }
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestrator.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestrator.java
new file mode 100644 (file)
index 0000000..4aa17dc
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13;
+
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A PipelineOrchestrator provides the necessary orchestration logic to allow multiple network services
+ * to share a common OpenFlow 1.3 based multi-table pipeline.
+ *
+ * @author Dave Tucker
+ * @author Madhu Venugopal
+ */
+public interface PipelineOrchestrator {
+    Service getNextServiceInPipeline(Service service);
+    AbstractServiceInstance getServiceInstance(Service service);
+    Map<Service, AbstractServiceInstance> getServiceRegistry();
+    short getTableOffset();
+    short getTable(Service service);
+    List<Service> getStaticPipeline();
+    void enqueue(Node node);
+    void registerService(final ServiceReference ref, AbstractServiceInstance serviceInstance);
+    void unregisterService(final ServiceReference ref);
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java
new file mode 100644 (file)
index 0000000..302b36a
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListener, PipelineOrchestrator {
+    private static final Logger LOG = LoggerFactory.getLogger(PipelineOrchestratorImpl.class);
+
+    /**
+     * Return the current table offset
+     * @return The table offset
+     */
+    @Override
+    public short getTableOffset() {
+        return NetvirtProvidersProvider.getTableOffset();
+    }
+
+    /**
+     * Return the offset adjusted table for the given {@link Service}
+     * @param service Identifies the openflow {@link Service}
+     * @return The table id
+     */
+    @Override
+    public short getTable(Service service) {
+        return (short)(getTableOffset() + service.getTable());
+    }
+
+    public List<Service> getStaticPipeline() {
+        return staticPipeline;
+    }
+
+    private List<Service> staticPipeline = Lists.newArrayList(
+            Service.CLASSIFIER,
+            Service.ARP_RESPONDER,
+            Service.INBOUND_NAT,
+            Service.EGRESS_ACL,
+            Service.LOAD_BALANCER,
+            Service.ROUTING,
+            Service.L3_FORWARDING,
+            Service.L2_REWRITE,
+            Service.INGRESS_ACL,
+            Service.OUTBOUND_NAT,
+            Service.L2_FORWARDING
+    );
+
+    public Map<Service, AbstractServiceInstance> getServiceRegistry() {
+        return serviceRegistry;
+    }
+
+    Map<Service, AbstractServiceInstance> serviceRegistry = Maps.newConcurrentMap();
+    private volatile BlockingQueue<Node> queue;
+    private ExecutorService eventHandler;
+    private Southbound southbound;
+
+    public PipelineOrchestratorImpl() {
+        eventHandler = Executors.newSingleThreadExecutor();
+        this.queue = new LinkedBlockingQueue<>();
+        LOG.info("PipelineOrchestratorImpl constructor");
+        start();
+    }
+
+    public void registerService(final ServiceReference ref, AbstractServiceInstance serviceInstance){
+        Service service = (Service)ref.getProperty(AbstractServiceInstance.SERVICE_PROPERTY);
+        LOG.info("registerService {} - {}", serviceInstance, service);
+        serviceRegistry.put(service, serviceInstance);
+        // insert the service if not already there. The list is ordered based of table ID.
+        if (!staticPipeline.contains(service) && !isTableInPipeline(service.getTable())) {
+            staticPipeline.add(service);
+            Collections.sort(staticPipeline, Service.insertComparator);
+        }
+        LOG.info("registerService: {}", staticPipeline);
+    }
+
+    private boolean isTableInPipeline (short tableId) {
+        boolean found = false;
+        for (Service service : staticPipeline) {
+            if (service.getTable() == tableId) {
+                found = true;
+                break;
+            }
+        }
+        return found;
+    }
+
+    public void unregisterService(final ServiceReference ref) {
+        serviceRegistry.remove(ref.getProperty(AbstractServiceInstance.SERVICE_PROPERTY));
+    }
+    @Override
+    public Service getNextServiceInPipeline(Service service) {
+        int index = staticPipeline.indexOf(service);
+        if (index >= staticPipeline.size() - 1) {
+            return null;
+        }
+        return staticPipeline.get(index + 1);
+    }
+
+    @Override
+    public AbstractServiceInstance getServiceInstance(Service service) {
+        if (service == null) {
+            return null;
+        }
+        return serviceRegistry.get(service);
+    }
+
+    public final void start() {
+        eventHandler.submit(new Runnable()  {
+            @Override
+            public void run() {
+                try {
+                    while (true) {
+                        Node node = queue.take();
+                        LOG.info(">>>>> dequeue: {}", node);
+                        if (southbound.getBridge(node) != null) {
+                            for (Service service : staticPipeline) {
+                                AbstractServiceInstance serviceInstance = getServiceInstance(service);
+                                if (serviceInstance != null) {
+                                    serviceInstance.programDefaultPipelineRule(node);
+                                }
+                            }
+                            // TODO: might need a flow to go from table 0 to the pipeline
+                        }
+                    }
+                } catch (Exception e) {
+                    LOG.warn("Processing interrupted, terminating ", e);
+                }
+
+                while (!queue.isEmpty()) {
+                    queue.poll();
+                }
+                queue = null;
+            }
+        });
+    }
+
+    public void stop() {
+        queue.clear();
+        eventHandler.shutdownNow();
+    }
+
+    @Override
+    public void enqueue(Node node) {
+        LOG.info(">>>>> enqueue: {}", node);
+        try {
+            queue.put(node);
+        } catch (InterruptedException e) {
+            LOG.warn("Failed to enqueue operation {}", node, e);
+        }
+    }
+
+    @Override
+    public void notifyNode(Node node, Action action) {
+        if (action == Action.ADD) {
+            enqueue(node);
+        } else {
+            LOG.info("update ignored: {}", node);
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        NodeCacheManager nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        nodeCacheManager.cacheListenerAdded(
+                bundleContext.getServiceReference(PipelineOrchestrator.class.getName()), this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/Service.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/Service.java
new file mode 100644 (file)
index 0000000..50dafd7
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014 - 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.openstack.netvirt.providers.openflow13;
+
+import java.util.Comparator;
+
+public enum Service {
+
+    CLASSIFIER ((short) 0, "Classifier"),
+    GATEWAY_RESOLVER((short) 0, "External Network Gateway Resolver"),
+    DIRECTOR ((short) 10, "Director"),
+    SFC_CLASSIFIER ((short) 10, "SFC Classifier"),
+    ARP_RESPONDER ((short) 20, "Distributed ARP Responder"),
+    INBOUND_NAT ((short) 30, "DNAT for inbound floating-ip traffic"),
+    EGRESS_ACL ((short) 40, "Egress Acces-control"),
+    LOAD_BALANCER ((short) 50, "Distributed LBaaS"),
+    ROUTING ((short) 60, "Distributed Virtual Routing (DVR)"),
+    ICMP_ECHO ((short) 70, "Distributed ICMP Echo Responder"),
+    L3_FORWARDING ((short) 70, "Layer 3 forwarding/lookup service"),
+    L2_REWRITE ((short) 80, "Layer2 rewrite service"),
+    INGRESS_ACL ((short) 90, "Ingress Acces-control"),
+    OUTBOUND_NAT ((short) 100, "DNAT for outbound floating-ip traffic"),
+    L2_FORWARDING ((short) 110, "Layer2 mac,vlan based forwarding");
+
+    short table;
+    String description;
+
+    Service(short table, String description)  {
+        this.table = table;
+        this.description = description;
+    }
+
+    public short getTable() {
+        return table;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public static Comparator<Service> insertComparator = new Comparator<Service>() {
+
+        @Override
+        public int compare(Service service1, Service service2) {
+            return service1.getTable() - service2.getTable();
+        }
+    };
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ArpResponderService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ArpResponderService.java
new file mode 100644 (file)
index 0000000..eee4df3
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.tables.table.FlowBuilder;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class ArpResponderService extends AbstractServiceInstance implements ArpProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(ArpResponderService.class);
+
+    public ArpResponderService() {
+        super(Service.ARP_RESPONDER);
+    }
+
+    public ArpResponderService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public Status programStaticArpEntry(Long dpid, String segmentationId, String macAddressStr,
+                                        InetAddress ipAddress, Action action) {
+        if (ipAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 case
+            LOG.debug("ipv6 address case is not implemented yet. dpid {} segmentationId {} macAddressStr, "
+                    + "ipAddress {} action {}",
+                    dpid, segmentationId, macAddressStr, ipAddress, action);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "ArpResponder_" + segmentationId + "_" + ipAddress.getHostAddress();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(1024);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(Constants.ARP_ETHERTYPE));
+        MatchUtils.createArpDstIpv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress.getHostAddress()));
+
+        if (segmentationId != null) {
+            final Long inPort = MatchUtils.parseExplicitOFPort(segmentationId);
+            if (inPort != null) {
+                MatchUtils.createInPortMatch(matchBuilder, dpid, inPort);
+            } else {
+                MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+            }
+        }
+
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList = Lists.newArrayList();
+
+            // Move Eth Src to Eth Dst
+            ab.setAction(ActionUtils.nxMoveEthSrcToEthDstAction());
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            // Set Eth Src
+            MacAddress macAddress = new MacAddress(macAddressStr);
+            ab.setAction(ActionUtils.setDlSrcAction(macAddress));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Set ARP OP
+            ab.setAction(ActionUtils.nxLoadArpOpAction(BigInteger.valueOf(0x02L)));
+            ab.setOrder(2);
+            ab.setKey(new ActionKey(2));
+            actionList.add(ab.build());
+
+            // Move ARP SHA to ARP THA
+            ab.setAction(ActionUtils.nxMoveArpShaToArpThaAction());
+            ab.setOrder(3);
+            ab.setKey(new ActionKey(3));
+            actionList.add(ab.build());
+
+            // Move ARP SPA to ARP TPA
+            ab.setAction(ActionUtils.nxMoveArpSpaToArpTpaAction());
+            ab.setOrder(4);
+            ab.setKey(new ActionKey(4));
+            actionList.add(ab.build());
+
+            // Load Mac to ARP SHA
+            ab.setAction(ActionUtils.nxLoadArpShaAction(macAddress));
+            ab.setOrder(5);
+            ab.setKey(new ActionKey(5));
+            actionList.add(ab.build());
+
+            // Load IP to ARP SPA
+            ab.setAction(ActionUtils.nxLoadArpSpaAction(ipAddress.getHostAddress()));
+            ab.setOrder(6);
+            ab.setKey(new ActionKey(6));
+            actionList.add(ab.build());
+
+            // Output of InPort
+            ab.setAction(ActionUtils.outputAction(FlowUtils.getSpecialNodeConnectorId(dpid, "INPORT")));
+            ab.setOrder(7);
+            ab.setKey(new ActionKey(7));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(ArpProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ClassifierService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ClassifierService.java
new file mode 100644 (file)
index 0000000..4e4d88f
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.ClassifierProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.tables.table.FlowBuilder;
+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.ApplyActionsCase;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+
+import com.google.common.collect.Lists;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class ClassifierService extends AbstractServiceInstance implements ClassifierProvider, ConfigInterface {
+    public final static long REG_VALUE_FROM_LOCAL = 0x1L;
+    public final static long REG_VALUE_FROM_REMOTE = 0x2L;
+    public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg0.class;
+
+    public ClassifierService() {
+        super(Service.CLASSIFIER);
+    }
+
+    public ClassifierService(Service service) {
+        super(service);
+    }
+
+    /*
+     * (Table:Classifier) Egress VM Traffic Towards TEP
+     * Match: Destination Ethernet Addr and OpenFlow InPort
+     * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+     * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
+     * actions=set_field:5->tun_id,goto_table=<next-table>"
+     */
+    @Override
+    public void programLocalInPort(Long dpidLong, String segmentationId, Long inPort, String attachedMac,
+                                   boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "LocalMac_" + segmentationId + "_" + inPort + "_" + attachedMac;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(attachedMac));
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            InstructionUtils.createSetTunnelIdInstructions(ib, new BigInteger(segmentationId));
+            ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
+            List<Action> actionList = aac.getApplyActions().getAction();
+
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
+                    BigInteger.valueOf(REG_VALUE_FROM_LOCAL)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+
+            actionList.add(ab.build());
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Next service GOTO Instructions Need to be appended to the List
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:Classifier) Egress VM Traffic Towards TEP
+     * Match: Source Ethernet Addr and OpenFlow InPort
+     * Instruction: Set VLANID and GOTO Table Egress (n)
+     * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
+     * actions=push_vlan, set_field:5->vlan_id,goto_table=<Next-Table>"
+     * table=0,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:70:2f:c2 actions=push_vlan:0x8100,set_field:6097->vlan_vid,goto_table:20
+     */
+    @Override
+    public void programLocalInPortSetVlan(Long dpidLong, String segmentationId, Long inPort, String attachedMac,
+                                          boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "LocalMac_" + segmentationId + "_" + inPort + "_" + attachedMac;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(attachedMac));
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort);
+        // openflowplugin requires a vlan match to add a vlan
+        MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(0), false);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            // Set VLAN ID Instruction
+            InstructionUtils.createSetVlanInstructions(ib, new VlanId(Integer.valueOf(segmentationId)));
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Next service GOTO Instructions Need to be appended to the List
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:Classifier) Drop frames source from a VM that do not
+     * match the associated MAC address of the local VM.
+     * Match: Low priority anything not matching the VM SMAC
+     * Instruction: Drop
+     * table=0,priority=16384,in_port=1 actions=drop"
+     */
+    @Override
+    public void programDropSrcIface(Long dpidLong, Long inPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "DropFilter_" + inPort;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(8192);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            // Call the InstructionBuilder Methods Containing Actions
+            InstructionUtils.createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:0) Ingress Tunnel Traffic
+     * Match: OpenFlow InPort and Tunnel ID
+     * Action: GOTO Local Table (10)
+     * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
+     */
+    @Override
+    public void programTunnelIn(Long dpidLong, String segmentationId, Long ofPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "TunnelIn_" + segmentationId + "_" + ofPort;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            List<Action> actionList = Lists.newArrayList();
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
+                    BigInteger.valueOf(REG_VALUE_FROM_REMOTE)));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            // Call the InstructionBuilder Methods Containing Actions
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Append the default pipeline after the first classification
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:0) Ingress VLAN Traffic
+     * Match: OpenFlow InPort and vlan ID
+     * Action: GOTO Local Table (20)
+     * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
+     * table=0,in_port=2,dl_vlan=2001 actions=goto_table:20
+     */
+    @Override
+    public void programVlanIn(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "VlanIn_" + segmentationId + "_" + ethPort;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, ethPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            // Append the default pipeline after the first classification
+            InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * Create an LLDP Flow Rule to encapsulate into
+     * a packet_in that is sent to the controller
+     * for topology handling.
+     * Match: Ethertype 0x88CCL
+     * Action: Punt to Controller in a Packet_In msg
+     */
+    @Override
+    public void programLLDPPuntRule(Long dpidLong) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "LLDP";
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable());
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(0x88CCL));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Create the OF Actions and Instructions
+        InstructionBuilder ib = new InstructionBuilder();
+        InstructionsBuilder isb = new InstructionsBuilder();
+
+        // Instructions List Stores Individual Instructions
+        List<Instruction> instructions = Lists.newArrayList();
+
+        // Call the InstructionBuilder Methods Containing Actions
+        InstructionUtils.createSendToControllerInstructions(FlowUtils.getNodeName(dpidLong), ib);
+        ib.setOrder(0);
+        ib.setKey(new InstructionKey(0));
+        instructions.add(ib.build());
+
+        // Add InstructionBuilder to the Instruction(s)Builder List
+        isb.setInstruction(instructions);
+
+        // Add InstructionsBuilder to FlowBuilder
+        flowBuilder.setInstructions(isb.build());
+
+        writeFlow(flowBuilder, nodeBuilder);
+    }
+
+    @Override
+    public void programGotoTable(Long dpidLong, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "TableOffset_" + getTable();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable())
+                .setPriority(6);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib =
+                    InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(ClassifierProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclService.java
new file mode 100644 (file)
index 0000000..e7ac0c2
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * Copyright (c) 2014 - 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.openstack.netvirt.providers.openflow13.services;
+
+import com.google.common.collect.Lists;
+
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.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.nodes.NodeBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Map;
+
+public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EgressAclService.class);
+    private volatile SecurityServicesManager securityServicesManager;
+    private volatile SecurityGroupCacheManger securityGroupCacheManger;
+    private static final int DHCP_SOURCE_PORT = 67;
+    private static final int DHCP_DESTINATION_PORT = 68;
+    private static final int DHCPV6_SOURCE_PORT = 547;
+    private static final int DHCPV6_DESTINATION_PORT = 546;
+    private static final String HOST_MASK = "/32";
+    private static final String V6_HOST_MASK = "/128";
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
+
+    public EgressAclService() {
+        super(Service.EGRESS_ACL);
+    }
+
+    public EgressAclService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac, long localPort,
+                                       NeutronSecurityGroup securityGroup, String portUuid, boolean write) {
+
+        LOG.trace("programPortSecurityGroup: neutronSecurityGroup: {} ", securityGroup);
+        if (securityGroup == null || securityGroup.getSecurityRules() == null) {
+            return;
+        }
+
+        List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
+        /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
+        for (NeutronSecurityRule portSecurityRule : portSecurityList) {
+
+            /**
+             * Neutron Port Security Acl "egress" and "IPv4"
+             * Check that the base conditions for flow based Port Security are true:
+             * Port Security Rule Direction ("egress") and Protocol ("IPv4")
+             * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
+             * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
+             *
+             */
+
+            if (portSecurityRule == null
+                    || portSecurityRule.getSecurityRuleEthertype() == null
+                    || portSecurityRule.getSecurityRuleDirection() == null) {
+                continue;
+            }
+
+            if (NeutronSecurityRule.DIRECTION_EGRESS.equals(portSecurityRule.getSecurityRuleDirection())) {
+                LOG.debug("programPortSecurityGroup: Acl Rule matching IP and ingress is: {} ", portSecurityRule);
+                if (null != portSecurityRule.getSecurityRemoteGroupID()) {
+                    //Remote Security group is selected
+                    List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
+                            .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
+                    if (null != remoteSrcAddressList) {
+                        for (Neutron_IPs vmIp :remoteSrcAddressList ) {
+
+                            programPortSecurityRule(dpid, segmentationId, attachedMac,
+                                                    localPort, portSecurityRule, vmIp, write);
+                        }
+                        if (write) {
+                            securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
+                        } else {
+                            securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
+                                                                     portUuid);
+                        }
+                    }
+                } else {
+                    programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
+                                            portSecurityRule, null, write);
+                }
+                if (write) {
+                    securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
+                } else {
+                    securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
+                                        long localPort, NeutronSecurityRule portSecurityRule,
+                                        Neutron_IPs vmIp, boolean write) {
+        String securityRuleEtherType = portSecurityRule.getSecurityRuleEthertype();
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(securityRuleEtherType);
+        if (!isIpv6 && !NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRuleEtherType)) {
+            LOG.debug("programPortSecurityRule: SecurityRuleEthertype {} does not match IPv4/v6.",
+                      securityRuleEtherType);
+            return;
+        }
+
+        if (null == portSecurityRule.getSecurityRuleProtocol()) {
+            /* TODO Rework on the priority values */
+            egressAclIp(dpid, isIpv6, segmentationId, attachedMac,
+                          write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+        } else {
+            String ipaddress = null;
+            if (null != vmIp) {
+                ipaddress = vmIp.getIpAddress();
+                try {
+                    InetAddress address = InetAddress.getByName(ipaddress);
+                    if ((isIpv6 && (address instanceof Inet4Address)) || (!isIpv6 && address instanceof Inet6Address)) {
+                        LOG.debug("programPortSecurityRule: Remote vmIP {} does not match with "
+                                + "SecurityRuleEthertype {}.", ipaddress, securityRuleEtherType);
+                        return;
+                    }
+                } catch (UnknownHostException e) {
+                    LOG.warn("Invalid IP address {}", ipaddress, e);
+                    return;
+                }
+            }
+
+            switch (portSecurityRule.getSecurityRuleProtocol()) {
+                case MatchUtils.TCP:
+                    LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
+                    egressAclTcp(dpid, segmentationId, attachedMac,
+                             portSecurityRule,ipaddress, write,
+                             Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+                case MatchUtils.UDP:
+                    LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
+                    egressAclUdp(dpid, segmentationId, attachedMac,
+                             portSecurityRule, ipaddress, write,
+                             Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+                case MatchUtils.ICMP:
+                case MatchUtils.ICMPV6:
+                    LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
+                    egressAclIcmp(dpid, segmentationId, attachedMac,
+                              portSecurityRule, ipaddress,write,
+                              Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+                default:
+                    LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other "
+                            + "protocol = ", portSecurityRule.getSecurityRuleProtocol());
+                    egressOtherProtocolAclHandler(dpid, segmentationId, attachedMac,
+                                              portSecurityRule, ipaddress, write,
+                                              Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+            }
+        }
+    }
+
+    private void egressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String srcMac,
+                                               NeutronSecurityRule portSecurityRule, String dstAddress,
+                                               boolean write, Integer priority) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_Other_" + segmentationId + "_" + srcMac + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
+
+        short proto = 0;
+        try {
+            Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
+            proto = protocol.shortValue();
+            flowId = flowId + proto;
+        } catch (NumberFormatException e) {
+            LOG.error("Protocol vlaue conversion failure", e);
+        }
+        matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
+
+        if (null != dstAddress) {
+            flowId = flowId + dstAddress;
+            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
+                                                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
+
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
+                    new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
+        }
+        flowId = flowId + "_Permit";
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, priority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    @Override
+    public void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac,
+                                          long localPort, List<Neutron_IPs> srcAddressList, boolean write) {
+
+        egressAclDhcpAllowClientTrafficFromVm(dpid, write, localPort,
+                                              Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
+        egressAclDhcpv6AllowClientTrafficFromVm(dpid, write, localPort,
+                                                Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
+        programArpRule(dpid, segmentationId, localPort, attachedMac, write);
+        if (securityServicesManager.isConntrackEnabled()) {
+            programEgressAclFixedConntrackRule(dpid, segmentationId, localPort, attachedMac, write);
+        }
+        // add rule to drop the DHCP server traffic originating from the vm.
+        egressAclDhcpDropServerTrafficfromVm(dpid, localPort, write,
+                                             Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
+        egressAclDhcpv6DropServerTrafficfromVm(dpid, localPort, write,
+                                               Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
+        //Adds rule to check legitimate ip/mac pair for each packet from the vm
+        for (Neutron_IPs srcAddress : srcAddressList) {
+            try {
+                InetAddress address = InetAddress.getByName(srcAddress.getIpAddress());
+                if (address instanceof Inet4Address) {
+                    String addressWithPrefix = srcAddress.getIpAddress() + HOST_MASK;
+                    egressAclAllowTrafficFromVmIpMacPair(dpid, localPort, attachedMac, addressWithPrefix,
+                                                         Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
+                } else if (address instanceof Inet6Address) {
+                    String addressWithPrefix = srcAddress.getIpAddress() + V6_HOST_MASK;
+                    egressAclAllowTrafficFromVmIpV6MacPair(dpid, localPort, attachedMac, addressWithPrefix,
+                                                           Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
+                }
+            } catch (UnknownHostException e) {
+                LOG.warn("Invalid IP address {}", srcAddress.getIpAddress(), e);
+            }
+        }
+
+    }
+
+    private void programArpRule(Long dpid, String segmentationId, long localPort, String attachedMac, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_ARP_" + segmentationId + "_" + localPort + "_";
+        MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
+        MatchUtils.addArpMacMatch(matchBuilder, attachedMac, null);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
+                                                              matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programEgressAclFixedConntrackRule(Long dpid,
+                                             String segmentationId, long localPort, String attachMac, boolean write) {
+        try {
+            programConntrackUntrackRule(dpid, segmentationId, localPort,attachMac,
+                                        Constants.CT_STATE_UNTRACKED_PRIORITY, write );
+            programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort,
+                                               Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
+            programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort,
+                                               Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
+            programConntrackNewDropRule(dpid, segmentationId, localPort,
+                                        Constants.CT_STATE_NEW_PRIORITY_DROP, write );
+            programConntrackInvDropRule(dpid, segmentationId, localPort,
+                                        Constants.CT_STATE_NEW_PRIORITY_DROP, write );
+            LOG.info("programEgressAclFixedConntrackRule :  default connection tracking rule are added.");
+        } catch (Exception e) {
+            LOG.error("Failed to add default conntrack rules : " , e);
+        }
+    }
+
+    private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
+                                             long localPort, String attachMac, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Egress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder, attachMac, null,MatchUtils.ETHERTYPE_IPV4);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
+                                             MatchUtils.UNTRACKED_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addInstructionWithConntrackRecirc(flowBuilder);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
+                                                    long localPort,Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Egress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
+                                             MatchUtils.TRACKED_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
+                                                    long localPort,Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Egress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
+                                             MatchUtils.TRACKED_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
+                                             long localPort, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        String flowName = "Egress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
+                                             MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, true);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
+                                             long localPort, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Egress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
+                                             MatchUtils.TRACKED_INV_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, true);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Allows IPv4/v6 packet egress from the src mac address.
+     * @param dpidLong the dpid
+     * @param isIpv6 whether the rule is for ipv6
+     * @param segmentationId the segementation id
+     * @param srcMac the src mac address
+     * @param write add or remove
+     * @param protoPortMatchPriority the protocol match priority.
+     */
+    private void egressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String srcMac,
+                               boolean write, Integer protoPortMatchPriority ) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_IP" + segmentationId + "_" + srcMac + "_Permit_";
+        if (isIpv6) {
+            matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
+        } else {
+            matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
+        }
+        addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Creates a egress match with src macaddress. If dest address is specified
+     * destination specific match will be created. Otherwise a match with a
+     * CIDR will be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param srcMac the source mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param dstAddress the destination IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priroty
+     */
+    private void egressAclTcp(Long dpidLong, String segmentationId, String srcMac,
+                              NeutronSecurityRule portSecurityRule, String dstAddress,
+                              boolean write, Integer protoPortMatchPriority) {
+        boolean portRange = false;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
+        if (isIpv6) {
+            matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
+        } else {
+            matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
+        }
+
+        /* Custom TCP Match */
+        if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
+            matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
+                                                     portSecurityRule.getSecurityRulePortMin());
+        } else {
+            /* All TCP Match */
+            if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
+                            + portSecurityRule.getSecurityRulePortMax() + "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+            } else {
+                portRange = true;
+            }
+        }
+        if (null != dstAddress) {
+            flowId = flowId + dstAddress;
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
+                        MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+                        MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
+            }
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
+                        new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+                        new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
+            }
+        }
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
+                                                  0, port, portMaskMap.get(port));
+                addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+                FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
+                                                                      matchBuilder, getTable());
+                addInstructionWithConntrackCommit(flowBuilder, false);
+                syncFlow(flowBuilder ,nodeBuilder, write);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+            FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
+                                                                  matchBuilder, getTable());
+            addInstructionWithConntrackCommit(flowBuilder, false);
+            syncFlow(flowBuilder ,nodeBuilder, write);
+        }
+    }
+
+    private void egressAclIcmp(Long dpidLong, String segmentationId, String srcMac,
+            NeutronSecurityRule portSecurityRule, String dstAddress,
+            boolean write, Integer protoPortMatchPriority) {
+
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
+        if (isIpv6) {
+            egressAclIcmpV6(dpidLong, segmentationId, srcMac, portSecurityRule, dstAddress, write,
+                            protoPortMatchPriority);
+        } else {
+            egressAclIcmpV4(dpidLong, segmentationId, srcMac, portSecurityRule, dstAddress, write,
+                            protoPortMatchPriority);
+        }
+    }
+
+    /**
+     * Creates a icmp egress match with src macaddress. If dest address is specified
+     * destination specific match will be created. Otherwise a match with a
+     * CIDR will be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param srcMac the source mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param dstAddress the source IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priority
+     */
+    private void egressAclIcmpV4(Long dpidLong, String segmentationId, String srcMac,
+                                 NeutronSecurityRule portSecurityRule, String dstAddress,
+                                 boolean write, Integer protoPortMatchPriority) {
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
+        /*Custom ICMP Match */
+        if (portSecurityRule.getSecurityRulePortMin() != null
+                && portSecurityRule.getSecurityRulePortMax() != null) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
+                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
+                    portSecurityRule.getSecurityRulePortMin().shortValue(),
+                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        } else {
+            /* All ICMP Match */ // We are getting from neutron NULL for both min and max
+            flowId = flowId + "all" + "_" ;
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
+        }
+        if (null != dstAddress) {
+            flowId = flowId + dstAddress;
+            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+                    MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+                    new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
+            }
+        }
+        flowId = flowId + "_Permit";
+        addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Creates a icmpv6 egress match with src macaddress. If dest address is specified
+     * destination specific match will be created. Otherwise a match with a
+     * CIDR will be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param srcMac the source mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param dstAddress the source IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priority
+     */
+    private void egressAclIcmpV6(Long dpidLong, String segmentationId, String srcMac,
+                                 NeutronSecurityRule portSecurityRule, String dstAddress,
+                                 boolean write, Integer protoPortMatchPriority) {
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
+        matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
+
+        /*Custom ICMP Match */
+        if (portSecurityRule.getSecurityRulePortMin() != null
+                && portSecurityRule.getSecurityRulePortMax() != null) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
+                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+            matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
+                    portSecurityRule.getSecurityRulePortMin().shortValue(),
+                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        } else {
+            /* All ICMP Match */ // We are getting from neutron NULL for both min and max
+            flowId = flowId + "all" + "_" ;
+            matchBuilder = MatchUtils.createICMPv6Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
+        }
+        if (null != dstAddress) {
+            flowId = flowId + dstAddress;
+            matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
+                    MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
+                    new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
+        }
+        flowId = flowId + "_Permit";
+        addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Creates a egress match with src macaddress. If dest address is specified
+     * destination specific match will be created. Otherwise a match with a
+     * CIDR will be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param srcMac the source mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param dstAddress the source IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priroty
+     */
+    private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
+                              NeutronSecurityRule portSecurityRule, String dstAddress,
+                              boolean write, Integer protoPortMatchPriority) {
+        boolean portRange = false;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
+        if (isIpv6) {
+            matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
+        } else {
+            matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
+        }
+
+        /* Custom UDP Match */
+        if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
+            matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
+                                                     portSecurityRule.getSecurityRulePortMin());
+        } else {
+            /* All UDP Match */
+            if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
+                    + portSecurityRule.getSecurityRulePortMax() + "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+            } else {
+                portRange = true;
+            }
+        }
+        if (null != dstAddress) {
+            flowId = flowId + dstAddress;
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
+                        MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+                        MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
+            }
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder, null,
+                        new Ipv6Prefix(portSecurityRule
+                                       .getSecurityRuleRemoteIpPrefix()));
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
+                        new Ipv4Prefix(portSecurityRule
+                                       .getSecurityRuleRemoteIpPrefix()));
+            }
+        }
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
+                                                  0, port, portMaskMap.get(port));
+                addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+                FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
+                                                                      matchBuilder, getTable());
+                addInstructionWithConntrackCommit(flowBuilder, false);
+                syncFlow(flowBuilder ,nodeBuilder, write);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+            FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
+                                                                  matchBuilder, getTable());
+            addInstructionWithConntrackCommit(flowBuilder, false);
+            syncFlow(flowBuilder ,nodeBuilder, write);
+        }
+    }
+
+    /**
+     * Adds flow to allow any DHCP client traffic.
+     *
+     * @param dpidLong the dpid
+     * @param write whether to write or delete the flow
+     * @param localPort the local port.
+     * @param priority the priority
+     */
+    private void egressAclDhcpAllowClientTrafficFromVm(Long dpidLong,
+                                                       boolean write, long localPort, Integer priority) {
+        String flowName = "Egress_DHCP_Client"  + "_Permit_";
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Adds flow to allow any DHCP IPv6 client traffic.
+     *
+     * @param dpidLong the dpid
+     * @param write whether to write or delete the flow
+     * @param localPort the local port
+     * @param priority the priority
+     */
+    private void egressAclDhcpv6AllowClientTrafficFromVm(Long dpidLong,
+                                                         boolean write, long localPort, Integer priority) {
+        String flowName = "Egress_DHCPv6_Client"  + "_Permit_";
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        MatchUtils.createDhcpv6Match(matchBuilder, DHCPV6_DESTINATION_PORT, DHCPV6_SOURCE_PORT);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Adds rule to prevent DHCP spoofing by the vm attached to the port.
+     *
+     * @param dpidLong the dpid
+     * @param localPort the local port
+     * @param write is write or delete
+     * @param priority  the priority
+     */
+    private void egressAclDhcpDropServerTrafficfromVm(Long dpidLong, long localPort,
+                                                      boolean write, Integer priority) {
+        String flowName = "Egress_DHCP_Server" + "_" + localPort + "_DROP_";
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, true);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Adds rule to prevent DHCPv6 spoofing by the vm attached to the port.
+     *
+     * @param dpidLong the dpid
+     * @param localPort the local port
+     * @param write is write or delete
+     * @param priority  the priority
+     */
+    private void egressAclDhcpv6DropServerTrafficfromVm(Long dpidLong, long localPort,
+                                                        boolean write, Integer priority) {
+
+        String flowName = "Egress_DHCPv6_Server" + "_" + localPort + "_DROP_";
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        MatchUtils.createDhcpv6Match(matchBuilder, DHCPV6_SOURCE_PORT, DHCPV6_DESTINATION_PORT);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, true);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Adds rule to check legitimate ip/mac pair for each packet from the vm.
+     *
+     * @param dpidLong the dpid
+     * @param localPort the local port
+     * @param srcIp the vm ip address
+     * @param attachedMac the vm mac address
+     * @param priority  the priority
+     * @param write is write or delete
+     */
+    private void egressAclAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
+                                                      String attachedMac, String srcIp,
+                                                      Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
+        String flowName = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Adds rule to check legitimate ip/mac pair for each packet from the vm.
+     *
+     * @param dpidLong the dpid
+     * @param localPort the local port
+     * @param srcIp the vm ip address
+     * @param attachedMac the vm mac address
+     * @param priority  the priority
+     * @param write is write or delete
+     */
+    private void egressAclAllowTrafficFromVmIpV6MacPair(Long dpidLong, long localPort,
+                                                        String attachedMac, String srcIp,
+                                                        Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createSrcL3Ipv6MatchWithMac(matchBuilder, new Ipv6Prefix(srcIp),new MacAddress(attachedMac));
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
+        String flowName = "Egress_Allow_VM_IPv6_MAC" + "_" + localPort + attachedMac + "_Permit_";
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
+        if (securityServicesManager.isConntrackEnabled()) {
+            MatchUtils.addCtState(matchBuilder, state, mask );
+        }
+
+    }
+
+    private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
+        InstructionBuilder instructionBuilder = null;
+        if (securityServicesManager.isConntrackEnabled()) {
+            Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
+            instructionBuilder = InstructionUtils
+                    .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
+        }
+        return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
+    }
+
+    private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
+        InstructionBuilder instructionBuilder = null;
+        if (securityServicesManager.isConntrackEnabled()) {
+            Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
+
+            instructionBuilder = InstructionUtils
+                    .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
+            List<Instruction> instructionsList = Lists.newArrayList();
+            instructionsList.add(instructionBuilder.build());
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructionsList);
+            flowBuilder.setInstructions(isb.build());
+        }
+        return flowBuilder;
+    }
+
+    private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder ,
+                                                InstructionBuilder instructionBuilder,boolean isDrop) {
+        InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
+        List<Instruction> instructionsList = Lists.newArrayList();
+        instructionsList.add(pipeLineIndstructionBuilder.build());
+        if (null != instructionBuilder) {
+            instructionsList.add(instructionBuilder.build());
+        }
+        InstructionsBuilder isb = new InstructionsBuilder();
+        isb.setInstruction(instructionsList);
+        flowBuilder.setInstructions(isb.build());
+        return flowBuilder;
+    }
+
+    private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
+        InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+        if (drop) {
+            InstructionUtils.createDropInstructions(ib);
+        }
+        ib.setOrder(0);
+        List<Instruction> instructionsList = Lists.newArrayList();
+        ib.setKey(new InstructionKey(0));
+        instructionsList.add(ib.build());
+        return ib;
+    }
+    /**
+     * Add or remove flow to the node.
+     * @param flowBuilder the flow builder
+     * @param nodeBuilder the node builder
+     * @param write whether it is a write
+     */
+    private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
+                          boolean write) {
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
+        securityGroupCacheManger =
+                (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IcmpEchoResponderService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IcmpEchoResponderService.java
new file mode 100644 (file)
index 0000000..2925c8d
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 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.openstack.netvirt.providers.openflow13.services;
+
+import com.google.common.collect.Lists;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.IcmpEchoProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.action.types.rev131112.address.address.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+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.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfEthDstCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCaseBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.List;
+
+/**
+ * @author Josh Hershberg (jhershbe@redhat.com)
+ */
+public class IcmpEchoResponderService extends AbstractServiceInstance implements IcmpEchoProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(IcmpEchoResponderService.class);
+    public static final Class<? extends NxmNxReg> SRC_MAC_4_HIGH_BYTES_FIELD = NxmNxReg4.class;
+    public static final Class<? extends NxmNxReg> SRC_MAC_2_LOW_BYTES_FIELD = NxmNxReg5.class;
+
+    public IcmpEchoResponderService() {
+        super(Service.ICMP_ECHO);
+    }
+
+    public IcmpEchoResponderService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public Status programIcmpEchoEntry(Long dpid, String segmentationId, String macAddressStr, InetAddress ipAddress, Action action) {
+
+        if (segmentationId == null) return new Status(StatusCode.BADREQUEST);
+
+        if (ipAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 case
+            LOG.debug("ipv6 address case is not implemented yet. dpid {} segmentationId {} macAddressStr, ipAddress {} action {}",
+                    dpid, segmentationId, macAddressStr, ipAddress, action);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
+
+        MacAddress macAddress = new MacAddress(macAddressStr);
+
+        programEntry(dpid, segmentationId, macAddress, ipAddress, true, action);
+        programEntry(dpid, segmentationId, macAddress, ipAddress, false, action);
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    private Status programEntry(long dpid, String segmentationId, MacAddress macAddress, InetAddress ipAddress, boolean isRouted, Action action) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = (isRouted ? "RoutedIcmpEchoResponder_" : "LanIcmpEchoResponder_")
+                + segmentationId + "_" + ipAddress.getHostAddress();
+
+        //The non-routed flow has an extra match condition and it must therefor be of a higher
+        //prio to make sure we get a "best match" kind of logic between the two
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(isRouted ? 2048 : 2049);
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+
+        // Match ICMP echo requests, type=8, code=0
+        MatchUtils.createICMPv4Match(matchBuilder, (short) 8, (short) 0);
+        MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress.getHostAddress()));
+
+        if (!isRouted) {
+            //packets that have been "routed" in table 60 (DVR) will have their src MAC in nxm_nx_reg4 and nxm_nx_reg5
+            //here we check that nxm_nx_reg4 is empty to check whether the packet has *not* been router since its
+            //destination is on the same LAN
+            MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(SRC_MAC_4_HIGH_BYTES_FIELD, 0x0L));
+        }
+
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList = Lists.newArrayList();
+
+            if (isRouted) {
+                ab.setAction(
+                            ActionUtils.nxMoveRegAction(
+                            new SrcNxRegCaseBuilder().setNxReg(SRC_MAC_4_HIGH_BYTES_FIELD).build(),
+                            new DstOfEthDstCaseBuilder().setOfEthDst(true).build(),
+                            0, 0, 31, false));
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+
+                ab.setAction(
+                            ActionUtils.nxMoveRegAction(
+                            new SrcNxRegCaseBuilder().setNxReg(SRC_MAC_2_LOW_BYTES_FIELD).build(),
+                            new DstOfEthDstCaseBuilder().setOfEthDst(true).build(),
+                            0, 32, 47, false));
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+            } else {
+                ab.setAction(ActionUtils.nxMoveEthSrcToEthDstAction());
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+            }
+
+            // Set Eth Src
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Move Ip Src to Ip Dst
+            ab.setAction(ActionUtils.nxMoveIpSrcToIpDstAction());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Set Ip Src
+            ab.setAction(ActionUtils.setNwSrcAction(new Ipv4Builder().setIpv4Address(
+                    MatchUtils.iPv4PrefixFromIPv4Address(ipAddress.getHostAddress())).build()));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Set the ICMP type to 0 (echo reply)
+            ab.setAction(ActionUtils.setIcmpTypeAction((byte)0));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Output of InPort
+            ab.setAction(ActionUtils.outputAction(new NodeConnectorId(
+                                                    nodeBuilder.getId().getValue() + ":INPORT")));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(IcmpEchoProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/InboundNatService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/InboundNatService.java
new file mode 100644 (file)
index 0000000..accfe7a
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.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.nodes.NodeBuilder;
+
+import com.google.common.collect.Lists;
+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.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InboundNatService extends AbstractServiceInstance implements ConfigInterface, InboundNatProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(InboundNatService.class);
+    public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg3.class;
+
+    public InboundNatService() {
+        super(Service.INBOUND_NAT);
+    }
+
+    public InboundNatService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public Status programIpRewriteRule(Long dpid, Long inPort, String destSegId, InetAddress matchAddress,
+                                       InetAddress rewriteAddress, Action action) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "InboundNAT_" + inPort + "_" + destSegId + "_" + matchAddress.getHostAddress();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(1024);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpid, inPort);
+        MatchUtils.createDstL3IPv4Match(matchBuilder,
+                MatchUtils.iPv4PrefixFromIPv4Address(matchAddress.getHostAddress()));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+
+            // Set register to indicate that rewrite took place
+            ActionBuilder actionBuilder = new ActionBuilder();
+            actionBuilder.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
+                    new BigInteger(destSegId)));
+
+            // Set Dest IP address and set REG_FIELD
+            InstructionUtils.createNwDstInstructions(ib,
+                    MatchUtils.iPv4PrefixFromIPv4Address(rewriteAddress.getHostAddress()), actionBuilder);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Goto Next Table
+            ib = getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public Status programIpRewriteExclusion(Long dpid, String segmentationId, String excludedCidr,
+                                            Action action) {
+        String ipAddress = excludedCidr.substring(0, excludedCidr.indexOf("/"));
+        InetAddress inetAddress;
+        try {
+            inetAddress = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+            return new Status(StatusCode.BADREQUEST);
+        }
+        if (inetAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 cidr case
+            LOG.debug("ipv6 cidr is not implemented yet. cidr {}",
+                    excludedCidr);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "InboundNATExclusion_" + segmentationId + "_" + excludedCidr;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(1024);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+
+        MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(excludedCidr));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib;
+
+            // Goto Next Table
+            ib = getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(InboundNatProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclService.java
new file mode 100644 (file)
index 0000000..ce9155c
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 2014 - 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.openstack.netvirt.providers.openflow13.services;
+
+import com.google.common.collect.Lists;
+
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.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.nodes.NodeBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Map;
+
+public class IngressAclService extends AbstractServiceInstance implements IngressAclProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
+    private volatile SecurityServicesManager securityServicesManager;
+    private volatile SecurityGroupCacheManger securityGroupCacheManger;
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
+
+    public IngressAclService() {
+        super(Service.INGRESS_ACL);
+    }
+
+    public IngressAclService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac,
+                                       long localPort, NeutronSecurityGroup securityGroup,
+                                       String portUuid, boolean write) {
+
+        LOG.trace("programPortSecurityGroup neutronSecurityGroup: {} ", securityGroup);
+        if (securityGroup == null || securityGroup.getSecurityRules() == null) {
+            return;
+        }
+
+        List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
+        /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
+        for (NeutronSecurityRule portSecurityRule : portSecurityList) {
+
+            /**
+             * Neutron Port Security Acl "ingress" and "IPv4"
+             * Check that the base conditions for flow based Port Security are true:
+             * Port Security Rule Direction ("ingress") and Protocol ("IPv4")
+             * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
+             * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
+             *
+             */
+
+            if (portSecurityRule == null
+                    || portSecurityRule.getSecurityRuleEthertype() == null
+                    || portSecurityRule.getSecurityRuleDirection() == null) {
+                continue;
+            }
+
+            if (NeutronSecurityRule.DIRECTION_INGRESS.equals(portSecurityRule.getSecurityRuleDirection())) {
+                LOG.debug("programPortSecurityGroup: Rule matching IP and ingress is: {} ", portSecurityRule);
+                if (null != portSecurityRule.getSecurityRemoteGroupID()) {
+                    //Remote Security group is selected
+                    List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
+                            .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
+                    if (null != remoteSrcAddressList) {
+                        for (Neutron_IPs vmIp :remoteSrcAddressList ) {
+                            programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
+                                                    portSecurityRule, vmIp, write);
+                        }
+                        if (write) {
+                            securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
+                        } else {
+                            securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
+                                                                     portUuid);
+                        }
+                    }
+                } else {
+                    programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
+                                            portSecurityRule, null, write);
+                }
+                if (write) {
+                    securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
+                } else {
+                    securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
+                                        long localPort, NeutronSecurityRule portSecurityRule,
+                                        Neutron_IPs vmIp, boolean write) {
+        String securityRuleEtherType = portSecurityRule.getSecurityRuleEthertype();
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(securityRuleEtherType);
+        if (!isIpv6 && !NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRuleEtherType)) {
+            LOG.debug("programPortSecurityRule: SecurityRuleEthertype {} does not match IPv4/v6.",
+                      securityRuleEtherType);
+            return;
+        }
+
+        if (null == portSecurityRule.getSecurityRuleProtocol()) {
+            ingressAclIp(dpid, isIpv6, segmentationId, attachedMac,
+                         write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+        } else {
+            String ipaddress = null;
+            if (null != vmIp) {
+                ipaddress = vmIp.getIpAddress();
+                try {
+                    InetAddress address = InetAddress.getByName(vmIp.getIpAddress());
+                    if ((isIpv6 && (address instanceof Inet4Address)) || (!isIpv6 && address instanceof Inet6Address)) {
+                        LOG.debug("programPortSecurityRule: Remote vmIP {} does not match "
+                                + "with SecurityRuleEthertype {}.", ipaddress, securityRuleEtherType);
+                        return;
+                    }
+                } catch (UnknownHostException e) {
+                    LOG.warn("Invalid IP address {}", ipaddress, e);
+                    return;
+                }
+            }
+
+            switch (portSecurityRule.getSecurityRuleProtocol()) {
+                case MatchUtils.TCP:
+                    LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
+                    ingressAclTcp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
+                              write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+                case MatchUtils.UDP:
+                    LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
+                    ingressAclUdp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
+                                write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+                case MatchUtils.ICMP:
+                case MatchUtils.ICMPV6:
+                    LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
+                    ingressAclIcmp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
+                                 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+                default:
+                    LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other "
+                            + "protocol = ", portSecurityRule.getSecurityRuleProtocol());
+                    ingressOtherProtocolAclHandler(dpid, segmentationId, attachedMac, portSecurityRule,
+                              null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    break;
+            }
+        }
+    }
+
+    private void ingressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String dstMac,
+          NeutronSecurityRule portSecurityRule, String srcAddress,
+          boolean write, Integer protoPortMatchPriority) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_Other_" + segmentationId + "_" + dstMac + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
+        short proto = 0;
+        try {
+            Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
+            proto = protocol.shortValue();
+            flowId = flowId + proto;
+        } catch (NumberFormatException e) {
+            LOG.error("Protocol vlaue conversion failure", e);
+        }
+        matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
+        if (null != srcAddress) {
+            flowId = flowId + srcAddress;
+            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                                                        MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                                           new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
+        }
+        flowId = flowId + "_Permit";
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
+                                                              matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    @Override
+    public void programFixedSecurityGroup(Long dpid, String segmentationId, String dhcpMacAddress,
+                                        long localPort, String attachMac, boolean write) {
+
+        ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress, attachMac,
+                                         write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
+        ingressAclDhcpv6AllowServerTraffic(dpid, segmentationId,dhcpMacAddress, attachMac,
+                                           write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
+
+        if (securityServicesManager.isConntrackEnabled()) {
+            programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
+        }
+        programArpRule(dpid, segmentationId, localPort, attachMac, write);
+    }
+
+    private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
+        MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
+        MatchUtils.addArpMacMatch(matchBuilder, null, attachMac);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
+                                                              matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programIngressAclFixedConntrackRule(Long dpid,
+           String segmentationId, String attachMac, long localPort, boolean write) {
+        try {
+            String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
+            programConntrackUntrackRule(dpid, segmentationId, localPort, attachMac,
+                                        Constants.CT_STATE_UNTRACKED_PRIORITY, write );
+            programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort, attachMac,
+                                        Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
+            programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort, attachMac,
+                                               Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
+            programConntrackInvDropRule(dpid, segmentationId, localPort, attachMac,
+                                        Constants.CT_STATE_NEW_PRIORITY_DROP, write );
+            programConntrackNewDropRule(dpid, segmentationId, localPort, attachMac,
+                                             Constants.CT_STATE_NEW_PRIORITY_DROP, write );
+            LOG.info("programIngressAclFixedConntrackRule :  default connection tracking rule are added.");
+        } catch (Exception e) {
+            LOG.error("Failed to add default conntrack rules : " , e);
+        }
+    }
+
+    private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
+                                             long localPort, String attachMac, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
+                                             MatchUtils.UNTRACKED_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addInstructionWithConntrackRecirc(flowBuilder);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
+                                                  long localPort, String attachMac,Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
+                                             MatchUtils.TRACKED_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
+                                                    long localPort, String attachMac,Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Ingress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
+                                             MatchUtils.TRACKED_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
+                                             long localPort, String attachMac, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,0x0800L);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
+                                             MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, true);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
+                                             long localPort, String attachMac, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowName = "Ingress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac, MatchUtils.ETHERTYPE_IPV4);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
+                                             MatchUtils.TRACKED_INV_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, true);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Allows an IPv4/v6 packet ingress to the destination mac address.
+     * @param dpidLong the dpid
+     * @param isIpv6 indicates whether this is an Ipv
+     * @param segmentationId the segementation id
+     * @param dstMac the destination mac address
+     * @param write add or remove
+     * @param protoPortMatchPriority the protocol match priority.
+     */
+    private void ingressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String dstMac,
+                              boolean write, Integer protoPortMatchPriority ) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
+        if (isIpv6) {
+            matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
+        } else {
+            matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
+        }
+        addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Creates a ingress match to the dst macaddress. If src address is specified
+     * source specific match will be created. Otherwise a match with a CIDR will
+     * be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dstMac the destination mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param srcAddress the destination IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priroty
+     */
+    private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
+                               NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
+                               Integer protoPortMatchPriority ) {
+        boolean portRange = false;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
+        if (isIpv6) {
+            matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
+        } else {
+            matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
+        }
+
+        /* Custom TCP Match*/
+        if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
+            matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
+                                                     portSecurityRule.getSecurityRulePortMin());
+        } else {
+            /* All TCP Match */
+            if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
+                    + portSecurityRule.getSecurityRulePortMax() + "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+            } else {
+                portRange = true;
+            }
+        }
+        if (null != srcAddress) {
+            flowId = flowId + srcAddress;
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
+                        MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                        MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
+            }
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
+                        new Ipv6Prefix(portSecurityRule
+                                       .getSecurityRuleRemoteIpPrefix()),null);
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                        new Ipv4Prefix(portSecurityRule
+                                       .getSecurityRuleRemoteIpPrefix()),null);
+            }
+        }
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
+                                                  0, port, portMaskMap.get(port));
+                addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+                FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
+                                                                      matchBuilder, getTable());
+                addInstructionWithConntrackCommit(flowBuilder, false);
+                syncFlow(flowBuilder ,nodeBuilder, write);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+            FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
+                                                                  matchBuilder, getTable());
+            addInstructionWithConntrackCommit(flowBuilder, false);
+            syncFlow(flowBuilder ,nodeBuilder, write);
+        }
+    }
+
+    /**
+     * Creates a ingress match to the dst macaddress. If src address is specified
+     * source specific match will be created. Otherwise a match with a CIDR will
+     * be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dstMac the destination mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param srcAddress the destination IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priroty
+     */
+    private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
+                               NeutronSecurityRule portSecurityRule, String srcAddress,
+                               boolean write, Integer protoPortMatchPriority ) {
+        boolean portRange = false;
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
+        if (isIpv6)  {
+            matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
+        } else {
+            matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
+        }
+
+        /* Custom UDP Match */
+        if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
+            matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
+                                                     portSecurityRule.getSecurityRulePortMin());
+        } else {
+            /* All UDP Match */
+            if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
+                    + portSecurityRule.getSecurityRulePortMax() + "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+            } else {
+                portRange = true;
+            }
+        }
+        if (null != srcAddress) {
+            flowId = flowId + srcAddress;
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
+                        MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                        MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
+            }
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            if (isIpv6) {
+                matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
+                        new Ipv6Prefix(portSecurityRule
+                                       .getSecurityRuleRemoteIpPrefix()),null);
+            } else {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                        new Ipv4Prefix(portSecurityRule
+                                       .getSecurityRuleRemoteIpPrefix()),null);
+            }
+        }
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
+                                                   0, port, portMaskMap.get(port));
+                addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+                FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
+                                                                      matchBuilder, getTable());
+                addInstructionWithConntrackCommit(flowBuilder, false);
+                syncFlow(flowBuilder ,nodeBuilder, write);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+            FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
+                                                                  matchBuilder, getTable());
+            addInstructionWithConntrackCommit(flowBuilder, false);
+            syncFlow(flowBuilder ,nodeBuilder, write);
+        }
+    }
+
+    private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
+            NeutronSecurityRule portSecurityRule, String srcAddress,
+            boolean write, Integer protoPortMatchPriority) {
+
+        boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
+        if (isIpv6) {
+            ingressAclIcmpV6(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
+                             write, protoPortMatchPriority);
+        } else {
+            ingressAclIcmpV4(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
+                             write, protoPortMatchPriority);
+        }
+    }
+
+    /**
+     * Creates a ingress icmp match to the dst macaddress. If src address is specified
+     * source specific match will be created. Otherwise a match with a CIDR will
+     * be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dstMac the destination mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param srcAddress the destination IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priority
+     */
+    private void ingressAclIcmpV4(Long dpidLong, String segmentationId, String dstMac,
+                                  NeutronSecurityRule portSecurityRule, String srcAddress,
+                                  boolean write, Integer protoPortMatchPriority) {
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
+
+        /* Custom ICMP Match */
+        if (portSecurityRule.getSecurityRulePortMin() != null
+                && portSecurityRule.getSecurityRulePortMax() != null) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
+                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
+                    portSecurityRule.getSecurityRulePortMin().shortValue(),
+                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        } else {
+            /* All ICMP Match */
+            flowId = flowId + "all" + "_";
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
+        }
+        if (null != srcAddress) {
+            flowId = flowId + srcAddress;
+            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                   MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                                         new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
+            }
+        }
+        flowId = flowId + "_Permit";
+        addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Creates a ingress icmpv6 match to the dst macaddress. If src address is specified
+     * source specific match will be created. Otherwise a match with a CIDR will
+     * be created.
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dstMac the destination mac address.
+     * @param portSecurityRule the security rule in the SG
+     * @param srcAddress the destination IP address
+     * @param write add or delete
+     * @param protoPortMatchPriority the protocol match priority
+     */
+    private void ingressAclIcmpV6(Long dpidLong, String segmentationId, String dstMac,
+                                  NeutronSecurityRule portSecurityRule, String srcAddress,
+                                  boolean write, Integer protoPortMatchPriority) {
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
+        matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
+
+        /* Custom ICMP Match */
+        if (portSecurityRule.getSecurityRulePortMin() != null
+                && portSecurityRule.getSecurityRulePortMax() != null) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
+                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+            matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
+                    portSecurityRule.getSecurityRulePortMin().shortValue(),
+                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        } else {
+            /* All ICMP Match */
+            flowId = flowId + "all" + "_";
+            matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
+        }
+        if (null != srcAddress) {
+            flowId = flowId + srcAddress;
+            matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
+                    MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
+        } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+            flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+            matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
+                    new Ipv6Prefix(portSecurityRule
+                                   .getSecurityRuleRemoteIpPrefix()),null);
+        }
+        addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        flowId = flowId + "_Permit";
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addInstructionWithConntrackCommit(flowBuilder, false);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
+     *
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dhcpMacAddress the DHCP server mac address
+     * @param attachMac the mac address of  the port
+     * @param write is write or delete
+     * @param protoPortMatchPriority the priority
+     */
+    private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
+                                                  String attachMac, boolean write, Integer protoPortMatchPriority) {
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,dhcpMacAddress,attachMac,
+                                                             MatchUtils.ETHERTYPE_IPV4);
+        MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 67, 68);
+        String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    /**
+     * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
+     *
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dhcpMacAddress the DHCP server mac address
+     * @param attachMac the mac address of  the port
+     * @param write is write or delete
+     * @param protoPortMatchPriority the priority
+     */
+    private void ingressAclDhcpv6AllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
+                                                    String attachMac, boolean write, Integer protoPortMatchPriority) {
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,dhcpMacAddress,attachMac,
+                                                             MatchUtils.ETHERTYPE_IPV6);
+        MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 547, 546);
+        String flowId = "Ingress_DHCPv6_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
+        FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
+        addPipelineInstruction(flowBuilder, null, false);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        syncFlow(flowBuilder ,nodeBuilder, write);
+    }
+
+    private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
+        if (securityServicesManager.isConntrackEnabled()) {
+            MatchUtils.addCtState(matchBuilder, state, mask );
+        }
+
+    }
+
+    private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
+        InstructionBuilder instructionBuilder = null;
+        if (securityServicesManager.isConntrackEnabled()) {
+            Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
+            instructionBuilder = InstructionUtils
+                    .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
+        }
+        return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
+    }
+
+    private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
+        InstructionBuilder instructionBuilder = null;
+        if (securityServicesManager.isConntrackEnabled()) {
+            Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
+            instructionBuilder = InstructionUtils
+                    .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
+            List<Instruction> instructionsList = Lists.newArrayList();
+            instructionsList.add(instructionBuilder.build());
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructionsList);
+            flowBuilder.setInstructions(isb.build());
+        }
+        return flowBuilder;
+    }
+
+    private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder , InstructionBuilder instructionBuilder,
+                                                boolean isDrop) {
+        InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
+        List<Instruction> instructionsList = Lists.newArrayList();
+        instructionsList.add(pipeLineIndstructionBuilder.build());
+        if (null != instructionBuilder) {
+            instructionsList.add(instructionBuilder.build());
+        }
+        InstructionsBuilder isb = new InstructionsBuilder();
+        isb.setInstruction(instructionsList);
+        flowBuilder.setInstructions(isb.build());
+        return flowBuilder;
+    }
+
+    private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
+        InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+        if (drop) {
+            InstructionUtils.createDropInstructions(ib);
+        }
+        ib.setOrder(0);
+        List<Instruction> instructionsList = Lists.newArrayList();
+        ib.setKey(new InstructionKey(0));
+        instructionsList.add(ib.build());
+        return ib;
+    }
+    /**
+     * Add or remove flow to the node.
+     * @param flowBuilder the flow builder
+     * @param nodeBuilder the node builder
+     * @param write whether it is a write
+     */
+    private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
+                          boolean write) {
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
+        securityGroupCacheManger =
+                (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2ForwardingService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2ForwardingService.java
new file mode 100644 (file)
index 0000000..40d119d
--- /dev/null
@@ -0,0 +1,859 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
+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.Flow;
+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.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.ApplyActionsCase;
+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.apply.actions._case.ApplyActions;
+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.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.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class L2ForwardingService extends AbstractServiceInstance implements ConfigInterface, L2ForwardingProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(L2ForwardingService.class);
+    public L2ForwardingService() {
+        super(Service.L2_FORWARDING);
+    }
+
+    public L2ForwardingService(Service service) {
+        super(service);
+    }
+
+    /*
+     * (Table:L2Forwarding) Local Unicast
+     * Match: Tunnel ID and dMAC
+     * Action: Output Port
+     * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 goto:<next-table>
+     */
+    @Override
+    public void programLocalUcastOut(Long dpidLong, String segmentationId,
+            Long localPort, String attachedMac, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "UcastOut_" + segmentationId + "_" + localPort + "_" + attachedMac;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        if (write) {
+            // Set the Output Port/Iface
+            Instruction setOutputPortInstruction =
+                    InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, localPort)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(0))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, setOutputPortInstruction);
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:2) Local VLAN unicast
+     * Match: VLAN ID and dMAC
+     * Action: Output Port
+     * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+     * table=110,dl_vlan=2001,dl_dst=fa:16:3e:a3:3b:cc actions=pop_vlan,output:1
+     */
+
+    @Override
+    public void programLocalVlanUcastOut (Long dpidLong, String segmentationId, Long localPort, String attachedMac, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "VlanUcastOut_" + segmentationId + "_" + localPort + "_" + attachedMac;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        if (write) {
+            /* Strip vlan and store to tmp instruction space*/
+            Instruction stripVlanInstruction = InstructionUtils.createPopVlanInstructions(new InstructionBuilder())
+                    .setOrder(0)
+                    .setKey(new InstructionKey(0))
+                    .build();
+
+            // Set the Output Port/Iface
+            Instruction setOutputPortInstruction =
+                    InstructionUtils.addOutputPortInstructions(new InstructionBuilder(), dpidLong, localPort,
+                            Collections.singletonList(stripVlanInstruction))
+                            .setOrder(1)
+                            .setKey(new InstructionKey(0))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, setOutputPortInstruction);
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+
+    /*
+     * (Table:2) Local Broadcast Flood
+     * Match: Tunnel ID and dMAC (::::FF:FF)
+     * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:2,3,4,5
+     */
+
+    @Override
+    public void programLocalBcastOut(Long dpidLong, String segmentationId, Long localPort, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.addNxRegMatch(matchBuilder,
+                new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_REMOTE));
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+                new MacAddress("01:00:00:00:00:00"));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "BcastOut_" + segmentationId;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
+                .setPriority(16384);
+
+        Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+
+        // Retrieve the existing instructions
+        List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
+
+        if (write) {
+            // Create output port list
+            Instruction outputPortInstruction =
+                    createOutputPortInstructions(new InstructionBuilder(), dpidLong, localPort, existingInstructions)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(0))
+                            .build();
+
+            /* Alternative method to address Bug 2004 is to use appendResubmitLocalFlood(ib) so that we send the
+             * flow back to the local flood rule. (See git history.) */
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            InstructionBuilder ib = new InstructionBuilder();
+            boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong, localPort,
+                    existingInstructions);
+            if (flowRemove) {
+                /* if all ports are removed, remove flow */
+                removeFlow(flowBuilder, nodeBuilder);
+            } else {
+                /* Install instruction with new output port list*/
+                Instruction outputPortInstruction = ib
+                        .setOrder(0)
+                        .setKey(new InstructionKey(0))
+                        .build();
+
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+
+                writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
+    }
+
+    /*
+     * (Table:2) Local VLAN Broadcast Flood
+     * Match: vlan ID and dMAC (::::FF:FF)
+     * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=strip_vlan, output:2,3,4,5
+     * table=110,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
+     */
+
+    @Override
+    public void programLocalVlanBcastOut(Long dpidLong, String segmentationId,
+                                         Long localPort, Long ethPort, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+                new MacAddress("01:00:00:00:00:00"));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "VlanBcastOut_" + segmentationId + "_" + ethPort;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
+                .setPriority(16384);
+        Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+
+        // Retrieve the existing instructions
+        List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
+
+        if (write) {
+            List<Action> actionList;
+            if (existingInstructions == null || existingInstructions.isEmpty()) {
+                /* First time called there should be no instructions.
+                 * We can simply add the output:ethPort first, followed by
+                 * popVlan and then the local port. The next calls will append
+                 * the rest of the local ports.
+                 */
+                actionList = new ArrayList<>();
+
+                actionList.add(
+                        new ActionBuilder()
+                                .setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + ethPort)))
+                                .setOrder(0)
+                                .setKey(new ActionKey(0))
+                                .build());
+
+                actionList.add(
+                        new ActionBuilder()
+                                .setAction(ActionUtils.popVlanAction())
+                                .setOrder(1)
+                                .setKey(new ActionKey(1))
+                                .build());
+
+                actionList.add(
+                        new ActionBuilder()
+                                .setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)))
+                                .setOrder(2)
+                                .setKey(new ActionKey(2))
+                                .build());
+            } else {
+                /* Subsequent calls require appending any new local ports for this tenant. */
+                Instruction in = existingInstructions.get(0);
+                actionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+
+                NodeConnectorId ncid = new NodeConnectorId(nodeName + ":" + localPort);
+                final Uri nodeConnectorUri = new Uri(ncid);
+                boolean addNew = true;
+
+                /* Check if the port is already in the output list */
+                for (Action action : actionList) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        OutputActionCase opAction = (OutputActionCase) action.getAction();
+                        if (opAction.getOutputAction().getOutputNodeConnector().equals(nodeConnectorUri)) {
+                            addNew = false;
+                            break;
+                        }
+                    }
+                }
+
+                if (addNew) {
+                    actionList.add(
+                            new ActionBuilder()
+                                    .setAction(
+                                            ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)))
+                                    .setOrder(actionList.size())
+                                    .setKey(new ActionKey(actionList.size()))
+                                    .build());
+                }
+            }
+
+            ApplyActions applyActions = new ApplyActionsBuilder().setAction(actionList).build();
+            Instruction applyActionsInstruction =
+                    new InstructionBuilder()
+                            .setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions).build())
+                            .setOrder(0)
+                            .setKey(new InstructionKey(0))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, applyActionsInstruction);
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            InstructionBuilder ib = new InstructionBuilder();
+            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong, localPort, ethPort,
+                    existingInstructions);
+            if (flowRemove) {
+                /* if all ports are removed, remove flow */
+                removeFlow(flowBuilder, nodeBuilder);
+            } else {
+                /* Install instruction with new output port list*/
+                Instruction outputPortInstruction = ib
+                        .setOrder(0)
+                        .setKey(new InstructionKey(0))
+                        .build();
+
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
+    }
+
+    private boolean removeOutputPortFromInstructions(InstructionBuilder ib, Long dpidLong, Long localPort,
+                                                     Long ethPort, List<Instruction> instructions) {
+        List<Action> actionList = new ArrayList<>();
+        boolean removeFlow = true;
+
+        if (instructions != null && !instructions.isEmpty()) {
+            Instruction in = instructions.get(0);
+            List<Action> oldActionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+            NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + localPort);
+            final Uri localNodeConnectorUri = new Uri(ncid);
+            NodeConnectorId ncidEth = new NodeConnectorId(OPENFLOW + dpidLong + ":" + ethPort);
+            final Uri ethNodeConnectorUri = new Uri(ncidEth);
+
+            // Remove the port from the output list
+            int index = 2;
+            for (Action action : oldActionList) {
+                if (action.getAction() instanceof OutputActionCase) {
+                    OutputActionCase opAction = (OutputActionCase) action.getAction();
+                    if (opAction.getOutputAction().getOutputNodeConnector().equals(ethNodeConnectorUri)) {
+                        actionList.add(action);
+                    } else if (!opAction.getOutputAction().getOutputNodeConnector().equals(localNodeConnectorUri)) {
+                        actionList.add(
+                                new ActionBuilder()
+                                        .setAction(action.getAction())
+                                        .setOrder(index)
+                                        .setKey(new ActionKey(index))
+                                        .build());
+                        index++;
+                    }
+                } else {
+                    actionList.add(action);
+                }
+            }
+            ApplyActions applyActions = new ApplyActionsBuilder().setAction(actionList).build();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions).build());
+        }
+
+        if (actionList.size() > 2) {
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            // TODO This doesn't actually do anything
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructions);
+            removeFlow = false;
+        }
+
+        return removeFlow;
+    }
+
+    /*
+     * (Table:1) Local Table Miss
+     * Match: Any Remaining Flows w/a TunID
+     * Action: Drop w/ a low priority
+     * table=2,priority=8192,tun_id=0x5 actions=drop
+     */
+
+    @Override
+    public void programLocalTableMiss(Long dpidLong, String segmentationId, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create Match(es) and Set them in the FlowBuilder Object
+        flowBuilder.setMatch(
+                MatchUtils.createTunnelIDMatch(new MatchBuilder(), new BigInteger(segmentationId)).build());
+
+        if (write) {
+            // Call the InstructionBuilder Methods Containing Actions
+            Instruction dropInstruction = InstructionUtils.createDropInstructions(new InstructionBuilder())
+                    .setOrder(0)
+                    .setKey(new InstructionKey(0))
+                    .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, dropInstruction);
+        }
+
+        // Add Flow Attributes
+        String flowName = "LocalTableMiss_" + segmentationId;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
+                .setPriority(8192);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:1) Local Table Miss
+     * Match: Any Remaining Flows w/a VLAN ID
+     * Action: Drop w/ a low priority
+     * table=2,priority=8192,vlan_id=0x5 actions=drop
+     */
+
+    @Override
+    public void programLocalVlanTableMiss(Long dpidLong, String segmentationId, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create Match(es) and Set them in the FlowBuilder Object
+        flowBuilder.setMatch(
+                MatchUtils.createVlanIdMatch(new MatchBuilder(), new VlanId(Integer.valueOf(segmentationId)),
+                        true).build());
+
+        if (write) {
+            // Call the InstructionBuilder Methods Containing Actions
+            Instruction dropInstruction = InstructionUtils.createDropInstructions(new InstructionBuilder())
+                    .setOrder(0)
+                    .setKey(new InstructionKey(0))
+                    .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, dropInstruction);
+        }
+
+        // Add Flow Attributes
+        String flowName = "LocalTableMiss_" + segmentationId;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
+                .setPriority(8192);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+
+    /*
+     * (Table:1) Egress Tunnel Traffic
+     * Match: Destination Ethernet Addr and Local InPort
+     * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+     * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+     * actions=output:10,goto_table:2"
+     */
+    // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
+    @Override
+    public void programTunnelOut(Long dpidLong, String segmentationId, Long OFPortOut, String attachedMac, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "TunnelOut_" + segmentationId + "_" + OFPortOut + "_" + attachedMac;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        if (write) {
+            // Set the Output Port/Iface
+            Instruction outputPortInstruction =
+                    InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, OFPortOut)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(1))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:1) Egress VLAN Traffic
+     * Match: Destination Ethernet Addr and VLAN id
+     * Instruction: GOTO Table Table 2
+     * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+     * actions= goto_table:2"
+     */
+    // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
+    @Override
+    public void programVlanOut(Long dpidLong, String segmentationId, Long ethPort, String attachedMac, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "VlanOut_" + segmentationId + "_" + ethPort + "_" + attachedMac;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+
+        if (write) {
+            // Instructions List Stores Individual Instructions
+            Instruction outputPortInstruction =
+                    InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, ethPort)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(1))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:1) Egress Tunnel Traffic
+     * Match: Destination Ethernet Addr and Local InPort
+     * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+     * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:10,output:11,goto_table:2
+     */
+    @Override
+    public void programTunnelFloodOut(Long dpidLong, String segmentationId, Long OFPortOut, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        // Match TunnelID
+        MatchUtils.addNxRegMatch(matchBuilder,
+                new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_LOCAL));
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        // Match DMAC
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+                new MacAddress("01:00:00:00:00:00"));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "TunnelFloodOut_" + segmentationId;
+        final FlowId flowId = new FlowId(flowName);
+        flowBuilder
+                .setId(flowId)
+                .setBarrier(true)
+                .setTableId(getTable())
+                .setKey(new FlowKey(flowId))
+                .setPriority(16383)  // FIXME: change it back to 16384 once bug 3005 is fixed.
+                .setFlowName(flowName)
+                .setHardTimeout(0)
+                .setIdleTimeout(0);
+
+        Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+        // Instantiate the Builders for the OF Actions and Instructions
+        List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
+
+        if (write) {
+            // Set the Output Port/Iface
+            Instruction outputPortInstruction =
+                    createOutputPortInstructions(new InstructionBuilder(), dpidLong, OFPortOut, existingInstructions)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(0))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            InstructionBuilder ib = new InstructionBuilder();
+            /* remove port from action list */
+            boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong,
+                    OFPortOut, existingInstructions);
+            if (flowRemove) {
+                /* if all port are removed, remove the flow too. */
+                removeFlow(flowBuilder, nodeBuilder);
+            } else {
+                /* Install instruction with new output port list*/
+                Instruction instruction = ib
+                        .setOrder(0)
+                        .setKey(new InstructionKey(0))
+                        .build();
+
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, instruction);
+                writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
+    }
+
+    /*
+     * (Table:1) Egress VLAN Traffic
+     * Match: Destination Ethernet Addr and VLAN id
+     * Instruction: GOTO table 2 and Output port eth interface
+     * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:eth1,goto_table:2
+     */
+
+    @Override
+    public void programVlanFloodOut(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        MatchBuilder matchBuilder = new MatchBuilder();
+        // Match Vlan ID
+        MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
+        // Match DMAC
+        MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+                new MacAddress("01:00:00:00:00:00"));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        // Add Flow Attributes
+        String flowName = "VlanFloodOut_" + segmentationId + "_" + ethPort;
+        final FlowId flowId = new FlowId(flowName);
+        flowBuilder
+                .setId(flowId)
+                .setBarrier(true)
+                .setTableId(getTable())
+                .setKey(new FlowKey(flowId))
+                .setPriority(16384)
+                .setFlowName(flowName)
+                .setHardTimeout(0)
+                .setIdleTimeout(0);
+
+        //ToDo: Is there something to be done with result of the call to getFlow?
+        Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+
+        if (write) {
+            // Set the Output Port/Iface
+            Instruction outputPortInstruction =
+                    InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, ethPort)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(0))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:1) Table Drain w/ Catch All
+     * Match: Tunnel ID
+     * Action: GOTO Local Table (10)
+     * table=2,priority=8192,tun_id=0x5 actions=drop
+     */
+    @Override
+    public void programTunnelMiss(Long dpidLong, String segmentationId, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create Match(es) and Set them in the FlowBuilder Object
+        flowBuilder.setMatch(
+                MatchUtils.createTunnelIDMatch(new MatchBuilder(), new BigInteger(segmentationId)).build());
+
+        if (write) {
+            // Call the InstructionBuilder Methods Containing Actions
+            Instruction mutablePipelineInstruction = getMutablePipelineInstructionBuilder()
+                    .setOrder(0)
+                    .setKey(new InstructionKey(0))
+                    .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, mutablePipelineInstruction);
+        }
+
+        // Add Flow Attributes
+        String flowName = "TunnelMiss_" + segmentationId;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
+                .setPriority(8192);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:1) Table Drain w/ Catch All
+     * Match: Vlan ID
+     * Action: Output port eth interface
+     * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
+     * table=110,priority=8192,dl_vlan=2001 actions=output:2
+     */
+
+    @Override
+    public void programVlanMiss(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create Match(es) and Set them in the FlowBuilder Object
+        flowBuilder.setMatch(
+                MatchUtils.createVlanIdMatch(new MatchBuilder(), new VlanId(Integer.valueOf(segmentationId)),
+                        true).build());
+
+        if (write) {
+            // Set the Output Port/Iface
+            Instruction outputPortInstruction =
+                    InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, ethPort)
+                            .setOrder(0)
+                            .setKey(new InstructionKey(1))
+                            .build();
+
+            // Add InstructionsBuilder to FlowBuilder
+            InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+        }
+
+        // Add Flow Attributes
+        String flowName = "VlanMiss_" + segmentationId;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
+                .setPriority(8192);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /**
+     * Create Output Port Group Instruction
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    protected InstructionBuilder createOutputPortInstructions(InstructionBuilder ib,
+            Long dpidLong, Long port ,
+            List<Instruction> instructions) {
+        NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port);
+        LOG.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions;
+        if (instructions != null && instructions.size() > 0) {
+            /**
+             * First instruction is the one containing the output ports.
+             * So, only extract the actions from that.
+             */
+            Instruction in = instructions.get(0);
+            if (in.getInstruction() instanceof ApplyActionsCase) {
+                existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                // Only include output actions
+                for (Action action : existingActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        actionList.add(action);
+                    }
+                }
+            }
+        }
+        /* Create output action for this port*/
+        OutputActionBuilder oab = new OutputActionBuilder();
+        oab.setOutputNodeConnector(ncid);
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+        boolean addNew = true;
+
+        /* Find the group action and get the group */
+        for (Action action : actionList) {
+            OutputActionCase opAction = (OutputActionCase)action.getAction();
+            /* If output port action already in the action list of one of the buckets, skip */
+            if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+                addNew = false;
+                break;
+            }
+        }
+        if (addNew) {
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+        }
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+        LOG.debug("createOutputPortInstructions() : applyAction {}", aab.build());
+        return ib;
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(L2ForwardingProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2RewriteService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2RewriteService.java
new file mode 100644 (file)
index 0000000..2d74d97
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.L2RewriteProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class L2RewriteService extends AbstractServiceInstance implements ConfigInterface, L2RewriteProvider {
+    public L2RewriteService() {
+        super(Service.L2_REWRITE);
+    }
+
+    public L2RewriteService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(L2RewriteProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
\ No newline at end of file
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L3ForwardingService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L3ForwardingService.java
new file mode 100644 (file)
index 0000000..977b49e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.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.nodes.NodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class L3ForwardingService extends AbstractServiceInstance implements L3ForwardingProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(L3ForwardingService.class);
+
+    public L3ForwardingService() {
+        super(Service.L3_FORWARDING);
+    }
+
+    public L3ForwardingService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public Status programForwardingTableEntry(Long dpid, String segmentationId, InetAddress ipAddress,
+                                              String macAddress, Action action) {
+        if (ipAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 case
+            LOG.debug("ipv6 address is not implemented yet. dpid {} segmentationId {} ipAddress {} macAddress {} Action {}",
+                      dpid, segmentationId, ipAddress, macAddress, action);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "L3Forwarding_" + segmentationId + "_" + ipAddress.getHostAddress();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(1024);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress.getHostAddress()));
+
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+
+            // Set Dest Mac address
+            InstructionUtils.createDlDstInstructions(ib, new MacAddress(macAddress));
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Goto Next Table
+            ib = getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(L3ForwardingProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/LoadBalancerService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/LoadBalancerService.java
new file mode 100644 (file)
index 0000000..6245f87
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2014 SDN Hub, LLC. 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration.LoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.action.types.rev131112.address.address.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.apply.actions._case.ApplyActionsBuilder;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+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.NxmNxReg1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
+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.openflowjava.nx.action.rev140421.OfjNxHashFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxMpAlgorithm;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class LoadBalancerService extends AbstractServiceInstance implements LoadBalancerProvider, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoadBalancerProvider.class);
+    private static final int DEFAULT_FLOW_PRIORITY = 32768;
+    private static final Long FIRST_PASS_REGA_MATCH_VALUE = 0L;
+    private static final Long SECOND_PASS_REGA_MATCH_VALUE = 1L;
+
+    private static final Class<? extends NxmNxReg> REG_FIELD_A = NxmNxReg1.class;
+    private static final Class<? extends NxmNxReg> REG_FIELD_B = NxmNxReg2.class;
+    
+    private volatile Southbound southbound;
+
+    public LoadBalancerService() {
+        super(Service.LOAD_BALANCER);
+    }
+
+    public LoadBalancerService(Service service) {
+        super(service);
+    }
+
+    private String getDpid(Node node) {
+        long dpid = southbound.getDataPathId(node);
+        if (dpid == 0) {
+            LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
+        }
+        return String.valueOf(dpid);
+    }
+    
+    /**
+     * When this method is called, we do the following for minimizing flow updates:
+     * 1. Overwrite the solo multipath rule that applies to all members
+     * 2. Append second pass rule for the header rewriting specific to this member
+     * 3. Append reverse rules specific to this member
+     */
+    @Override
+    public Status programLoadBalancerPoolMemberRules(Node node,
+                                                     LoadBalancerConfiguration lbConfig, LoadBalancerPoolMember member,
+                                                     org.opendaylight.netvirt.openstack.netvirt.api.Action action) {
+        if (lbConfig == null || member == null) {
+            LOG.error("Null value for LB config {} or Member {}", lbConfig, member);
+            return new Status(StatusCode.BADREQUEST);
+        }
+        if (!lbConfig.isValid()) {
+            LOG.error("LB config is invalid: {}", lbConfig);
+            return new Status(StatusCode.BADREQUEST);
+        }
+        LOG.debug("Performing {} rules for member {} with index {} on LB with VIP {} and total members {}",
+                action, member.getIP(), member.getIndex(), lbConfig.getVip(), lbConfig.getMembers().size());
+
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + getDpid(node)));
+        nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
+
+        //Update the multipath rule
+        manageLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig, true);
+
+        if (action.equals(org.opendaylight.netvirt.openstack.netvirt.api.Action.ADD)) {
+            manageLoadBalancerMemberVIPRulesSecondPass(nodeBuilder, lbConfig, member, true);
+            manageLoadBalancerMemberReverseRules(nodeBuilder, lbConfig, member, true);
+            return new Status(StatusCode.SUCCESS);
+        }
+        /* TODO: Delete single member.
+         * For now, removing a member requires deleting the full LB instance and re-adding
+         */
+        return new Status(StatusCode.NOTIMPLEMENTED);
+    }
+
+    /**
+     * When this method is called, we perform the following:
+     * 1. Write the solo multipath rule that applies to all members
+     * 2. Append second pass rules for the header rewriting for all members
+     * 3. Append reverse rules for all the members, specific to the protocol/port
+     */
+    @Override
+    public Status programLoadBalancerRules(Node node, LoadBalancerConfiguration lbConfig,
+                                           org.opendaylight.netvirt.openstack.netvirt.api.Action action) {
+        if (lbConfig == null || !lbConfig.isValid()) {
+            LOG.error("LB config is invalid: {}", lbConfig);
+            return new Status(StatusCode.BADREQUEST);
+        }
+        LOG.debug("Performing {} rules for VIP {} and {} members", action, lbConfig.getVip(), lbConfig.getMembers().size());
+
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + getDpid(node)));
+        nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
+
+        if (action.equals(org.opendaylight.netvirt.openstack.netvirt.api.Action.ADD)) {
+            manageLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig, true);
+            manageLoadBalancerVIPRulesSecondPass(nodeBuilder, lbConfig, true);
+            manageLoadBalancerReverseRules(nodeBuilder, lbConfig, true);
+            return new Status(StatusCode.SUCCESS);
+        }
+        else if (action.equals(org.opendaylight.netvirt.openstack.netvirt.api.Action.DELETE)) {
+            manageLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig, false);
+            manageLoadBalancerVIPRulesSecondPass(nodeBuilder, lbConfig, false);
+            manageLoadBalancerReverseRules(nodeBuilder, lbConfig, false);
+            return new Status(StatusCode.SUCCESS);
+        }
+
+        return new Status(StatusCode.NOTIMPLEMENTED);
+    }
+
+    /**
+     * Method to insert/remove default rule for traffic destined to the VIP and no
+     * server selection performed yet
+     * @param nodeBuilder NodeBuilder
+     * @param lbConfig LoadBalancerConfiguration
+     * @param write Boolean to indicate of the flow is to be inserted or removed
+     */
+    private void manageLoadBalancerVIPRulesFirstPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig,
+                                                     boolean write) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "LOADBALANCER_FORWARD_FLOW1_" + lbConfig.getProviderSegmentationId() + "_" + lbConfig.getVip();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(DEFAULT_FLOW_PRIORITY);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        // Match Tunnel-ID, VIP, and Reg0==0
+        if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
+            lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
+            MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
+        } else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
+        } else {
+            return; //Should not get here. TODO: Other types
+        }
+
+        MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(lbConfig.getVip()));
+        MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(REG_FIELD_A, FIRST_PASS_REGA_MATCH_VALUE));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            List<Action> actionList = Lists.newArrayList();
+
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD_A).build(),
+                    BigInteger.valueOf(SECOND_PASS_REGA_MATCH_VALUE)));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxMultipathAction(OfjNxHashFields.NXHASHFIELDSSYMMETRICL4,
+                    0, OfjNxMpAlgorithm.NXMPALGMODULON,
+                    lbConfig.getMembers().size()-1, //By Nicira-Ext spec, this field is max_link minus 1
+                    0L, new DstNxRegCaseBuilder().setNxReg(REG_FIELD_B).build(),
+                    0, 31));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxResubmitAction(null, this.getTable()));
+            ab.setOrder(2);
+            ab.setKey(new ActionKey(2));
+            actionList.add(ab.build());
+
+            // Create an Apply Action
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            // Call the InstructionBuilder Methods Containing Actions
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * Method to program each rule that matches on Reg0 and Reg1 to insert appropriate header rewriting
+     * rules for all members. This function calls manageLoadBalancerMemberVIPRulesSecondPass in turn.
+     * @param nodeBuilder Node to insert rule to
+     * @param lbConfig Configuration for this LoadBalancer instance
+     * @param write Boolean to indicate of the flow is to be inserted or removed
+     */
+    private void manageLoadBalancerVIPRulesSecondPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig, boolean write) {
+        for(Map.Entry<String, LoadBalancerPoolMember> entry : lbConfig.getMembers().entrySet()){
+            manageLoadBalancerMemberVIPRulesSecondPass(nodeBuilder, lbConfig, entry.getValue(), write);
+        }
+    }
+
+    private void manageLoadBalancerMemberVIPRulesSecondPass(NodeBuilder nodeBuilder,
+                                                            LoadBalancerConfiguration lbConfig,
+                                                            LoadBalancerPoolMember member, boolean write) {
+        String vip = lbConfig.getVip();
+
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "LOADBALANCER_FORWARD_FLOW2_" + lbConfig.getProviderSegmentationId() + "_"
+                + vip + "_" + member.getIP();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(DEFAULT_FLOW_PRIORITY+1);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        // Match Tunnel-ID, VIP, Reg0==1 and Reg1==Index of member
+        if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
+            lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
+            MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
+        } else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
+        } else {
+            return; //Should not get here. TODO: Other types
+        }
+
+        MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(vip));
+        MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(REG_FIELD_A, SECOND_PASS_REGA_MATCH_VALUE),
+                                               new MatchUtils.RegMatch(REG_FIELD_B, (long)member.getIndex()));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            List<Action> actionList = Lists.newArrayList();
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.setDlDstAction(new MacAddress(member.getMAC())));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            ab = new ActionBuilder();
+            Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(MatchUtils.iPv4PrefixFromIPv4Address(member.getIP()));
+            ab.setAction(ActionUtils.setNwDstAction(ipb.build()));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Create an Apply Action
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            // Call the InstructionBuilder Methods Containing Actions
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Call the InstructionBuilder Methods Containing Actions
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /**
+     * Method to program all reverse rules that matches member {IP, Protocol, Port} for all members.
+     * This function calls manageLoadBalancerMemberReverseRules in turn.
+     * @param nodeBuilder Node to insert rule to
+     * @param lbConfig Configuration for this LoadBalancer instance
+     */
+    private void manageLoadBalancerReverseRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig, boolean write) {
+        for(Map.Entry<String, LoadBalancerPoolMember> entry : lbConfig.getMembers().entrySet()){
+            manageLoadBalancerMemberReverseRules(nodeBuilder, lbConfig, entry.getValue(), write);
+        }
+    }
+
+    private void manageLoadBalancerMemberReverseRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig,
+            LoadBalancerPoolMember member, boolean write) {
+
+        String vip = lbConfig.getVip();
+        String vmac = lbConfig.getVmac();
+
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "LOADBALANCER_REVERSE_FLOW_" + lbConfig.getProviderSegmentationId() +
+                vip + "_" + member.getIP();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(DEFAULT_FLOW_PRIORITY);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        // Match Tunnel-ID, MemberIP, and Protocol/Port
+        if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
+                   lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
+            MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
+        } else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            MatchUtils.createVlanIdMatch(matchBuilder,
+                    new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
+        } else {
+            return; //Should not get here. TODO: Other types
+        }
+
+        MatchUtils.createSrcL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(member.getIP()));
+        MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(member.getPort()));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            List<Action> actionList = Lists.newArrayList();
+            ActionBuilder ab = new ActionBuilder();
+            Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(MatchUtils.iPv4PrefixFromIPv4Address(vip));
+            ab.setAction(ActionUtils.setNwSrcAction(ipb.build()));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            /* If a dummy MAC is assigned to the VIP, we use that as the
+             * source MAC for the reverse traffic.
+             */
+            if (vmac != null) {
+                ab = new ActionBuilder();
+                ab.setAction(ActionUtils.setDlDstAction(new MacAddress(vmac)));
+                ab.setOrder(1);
+                ab.setKey(new ActionKey(1));
+                actionList.add(ab.build());
+            }
+
+            // Create an Apply Action
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            // Call the InstructionBuilder Methods Containing Actions
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Call the InstructionBuilder Methods Containing Actions
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(LoadBalancerProvider.class.getName()), this);
+        southbound =(Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/OutboundNatService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/OutboundNatService.java
new file mode 100644 (file)
index 0000000..adc8437
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.action.types.rev131112.address.address.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+
+import com.google.common.collect.Lists;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OutboundNatService extends AbstractServiceInstance implements OutboundNatProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(OutboundNatService.class);
+
+    public OutboundNatService() {
+        super(Service.OUTBOUND_NAT);
+    }
+
+    public OutboundNatService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public Status programIpRewriteRule(Long dpidLong,
+                                       String matchSegmentationId,
+                                       String matchDestMacAddress,
+                                       InetAddress matchSrcAddress,
+                                       String rewriteSrcMacAddress,
+                                       String rewriteDestMacAddress,
+                                       InetAddress rewriteSrcAddress,
+                                       Long OutPort,
+                                       Action action) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "OutboundNAT_" + matchSegmentationId + "_" + matchSrcAddress.getHostAddress();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(512);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createDmacIpSaMatch(matchBuilder,
+                matchDestMacAddress,
+                MatchUtils.iPv4PrefixFromIPv4Address(matchSrcAddress.getHostAddress()),
+                matchSegmentationId);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            List<Instruction> instructions_tmp = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList =
+                    Lists.newArrayList();
+
+            // Set source Mac address
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(rewriteSrcMacAddress)));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            // DecTTL
+            ab.setAction(ActionUtils.decNwTtlAction());
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Set Destination Mac address
+            ab.setAction(ActionUtils.setDlDstAction(new MacAddress(rewriteDestMacAddress)));
+            ab.setOrder(2);
+            ab.setKey(new ActionKey(2));
+            actionList.add(ab.build());
+
+            // Set source Ip address
+            Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(
+                    MatchUtils.iPv4PrefixFromIPv4Address(rewriteSrcAddress.getHostAddress()));
+            ab.setAction(ActionUtils.setNwSrcAction(ipb.build()));
+            ab.setOrder(3);
+            ab.setKey(new ActionKey(3));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions_tmp.add(ib.build());
+
+            // Set the Output Port/Iface
+            ib = new InstructionBuilder();
+            InstructionUtils.addOutputPortInstructions(ib, dpidLong, OutPort, instructions_tmp);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public Status programIpRewriteExclusion(Long dpid, String segmentationId, String excludedCidr,
+                                            Action action) {
+        String ipAddress = excludedCidr.substring(0, excludedCidr.indexOf("/"));
+        InetAddress inetAddress;
+        try {
+            inetAddress = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+            return new Status(StatusCode.BADREQUEST);
+        }
+        if (inetAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 cidr case
+            LOG.debug("ipv6 cidr is not implemented yet. cidr {}",
+                      excludedCidr);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "OutboundNATExclusion_" + segmentationId + "_" + excludedCidr;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(1024);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+
+        MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(excludedCidr));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib;
+
+            // Goto Next Table
+            ib = getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(OutboundNatProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/RoutingService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/RoutingService.java
new file mode 100644 (file)
index 0000000..38d216c
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.providers.openflow13.services;
+
+import java.math.BigInteger;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.tables.table.FlowBuilder;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+
+import com.google.common.collect.Lists;
+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.src.choice.grouping.src.choice.SrcOfEthSrcCaseBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoutingService extends AbstractServiceInstance implements RoutingProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(RoutingService.class);
+    public RoutingService() {
+        super(Service.ROUTING);
+    }
+
+    public RoutingService(Service service) {
+        super(service);
+    }
+
+    @Override
+    public Status programRouterInterface(Long dpid, String sourceSegId, String destSegId, String macAddress,
+                                         InetAddress address, int mask, Action action) {
+        if (address instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 case
+            LOG.debug("ipv6 address is not implemented yet. address {}", address);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
+
+        SubnetUtils addressSubnetInfo = new SubnetUtils(address.getHostAddress() + "/" + mask);
+        final String prefixString = addressSubnetInfo.getInfo().getNetworkAddress() + "/" + mask;
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "Routing_" + sourceSegId + "_" + destSegId + "_" + prefixString;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(2048);
+
+        boolean isExternalNet = sourceSegId.equals(Constants.EXTERNAL_NETWORK);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        if (isExternalNet) {
+            // If matching on external network, use register reserved for InboundNatService to ensure that
+            // ip rewrite is meant to be consumed by this destination tunnel id.
+            MatchUtils.addNxRegMatch(matchBuilder,
+                    new MatchUtils.RegMatch(InboundNatService.REG_FIELD, Long.valueOf(destSegId)));
+        } else {
+            MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(sourceSegId));
+        }
+
+        MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(prefixString));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList
+                    = Lists.newArrayList();
+
+            //if this is an east<->west route, save the src mac in case this is an ICMP echo request
+            if(!isExternalNet) {
+                ab.setAction(ActionUtils.nxMoveRegAction(
+                                            new SrcOfEthSrcCaseBuilder().setOfEthSrc(Boolean.TRUE).build(),
+                                            new DstNxRegCaseBuilder().setNxReg(IcmpEchoResponderService.SRC_MAC_4_HIGH_BYTES_FIELD).build(),
+                                            0,0,31, false));
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+
+                ab.setAction(ActionUtils.nxMoveRegAction(
+                                            new SrcOfEthSrcCaseBuilder().setOfEthSrc(Boolean.TRUE).build(),
+                                            new DstNxRegCaseBuilder().setNxReg(IcmpEchoResponderService.SRC_MAC_2_LOW_BYTES_FIELD).build(),
+                                            32,0,15, false));
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+            }
+
+            // Set source Mac address
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // DecTTL
+            ab.setAction(ActionUtils.decNwTtlAction());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Set Destination Tunnel ID
+            ab.setAction(ActionUtils.setTunnelIdAction(new BigInteger(destSegId)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Goto Next Table
+            ib = getMutablePipelineInstructionBuilder();
+            ib.setOrder(2);
+            ib.setKey(new InstructionKey(2));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public Status programDefaultRouteEntry(Long dpid, String segmentationId, String macAddress,
+                                           InetAddress nextHop, Action action) {
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "DefaultRoute_" + nextHop.getHostAddress();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(1024);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (action.equals(Action.ADD)) {
+            // Instructions List Stores Individual Instructions
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList =
+                    Lists.newArrayList();
+
+            // Set source Mac address
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            // DecTTL
+            ab.setAction(ActionUtils.decNwTtlAction());
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Goto Next Table
+            ib = getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            flowBuilder.setInstructions(isb.setInstruction(instructions).build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+
+        // ToDo: WriteFlow/RemoveFlow should return something we can use to check success
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(RoutingProvider.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/Arp.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/Arp.java
new file mode 100644 (file)
index 0000000..51cbbde
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import io.netty.buffer.Unpooled;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.Packet;
+import org.opendaylight.controller.liblldp.PacketException;
+
+/**
+ * Represents ARP packet. Contains methods ({@link #setSHAFieldCoordinate(Pair)}
+ * {@link #setSPAFieldCoordinate(Pair)} {@link #setTHAFieldCoordinate(Pair)}
+ * {@link #setTPAFieldCoordinate(Pair)}) for customization of ARP.
+ * Arp by default contain fields for IPv4 as protocol address and MAC as hardware address.
+ */
+public class Arp extends Packet {
+
+    private static final String HTYPE = "htype";
+    private static final String PTYPE = "ptype";
+    private static final String HLEN = "hlen";
+    private static final String PLEN = "plen";
+    private static final String OPERATION = "operation";
+    private static final String SHA = "sha";
+    private static final String SPA = "spa";
+    private static final String THA = "tha";
+    private static final String TPA = "tpa";
+
+    private static final int ARP_FIELDS_COUNT = 9;
+    private static final int ETHERNET_HW_TYPE = 1;
+    private final Map<String, Pair<Integer, Integer>> ARP_FIELD_COORDINATES = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+
+        private static final long serialVersionUID = 1L;
+
+        {
+            put(HTYPE, ImmutablePair.of(0, 16));
+            put(PTYPE, ImmutablePair.of(16, 16));
+            put(HLEN, ImmutablePair.of(32, 8));
+            put(PLEN, ImmutablePair.of(40, 8));
+            put(OPERATION, ImmutablePair.of(48, 16));
+            put(SHA, ImmutablePair.of(64, 48));
+            put(SPA, ImmutablePair.of(112, 32));
+            put(THA, ImmutablePair.of(144, 48));
+            put(TPA, ImmutablePair.of(192, 32));
+        }
+    };
+
+    public Arp() {
+        payload = null;
+        hdrFieldsMap = new HashMap<>(ARP_FIELDS_COUNT);
+        setHardwareLength((short) 6); // MAC address length
+        setProtocolLength((short) 4); // IPv4 address length
+        setHardwareType(ETHERNET_HW_TYPE);
+        setProtocolType(EtherTypes.IPv4.intValue());
+        hdrFieldCoordMap = ARP_FIELD_COORDINATES;
+    }
+
+    public Pair<Integer, Integer> setSHAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(SHA, bitOffsetAndBitLength);
+    }
+
+    public Pair<Integer, Integer> setSPAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(SPA, bitOffsetAndBitLength);
+    }
+
+    public Pair<Integer, Integer> setTHAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(THA, bitOffsetAndBitLength);
+    }
+
+    public Pair<Integer, Integer> setTPAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(TPA, bitOffsetAndBitLength);
+    }
+
+    private void checkNotNullPair(Pair<Integer, Integer> pair) {
+        checkNotNull(pair);
+        checkNotNull(pair.getLeft());
+        checkNotNull(pair.getRight());
+    }
+
+    @Override
+    public Packet deserialize(byte[] data, int bitOffset, int size) throws PacketException {
+        return super.deserialize(data, bitOffset, size);
+    }
+
+    @Override
+    public byte[] serialize() throws PacketException {
+        return super.serialize();
+    }
+
+    @Override
+    public int getfieldnumBits(String fieldName) {
+        if (fieldName.equals(SHA) || fieldName.equals(THA)) {
+            return getHardwareLength() * NetUtils.NumBitsInAByte;
+        } else if (fieldName.equals(SPA) || fieldName.equals(TPA)) {
+            return getProtocolLength() * NetUtils.NumBitsInAByte;
+        }
+        return hdrFieldCoordMap.get(fieldName).getRight();
+    }
+
+    public Arp setHardwareType(int value) {
+        hdrFieldsMap.put(HTYPE, Unpooled.copyShort(value).array());
+        return this;
+    }
+
+    public Arp setProtocolType(int value) {
+        hdrFieldsMap.put(PTYPE, Unpooled.copyShort(value).array());
+        return this;
+    }
+
+    /**
+     * @param value hardware length in Bytes
+     */
+    public Arp setHardwareLength(short value) {
+        hdrFieldsMap.put(HLEN, Unpooled.buffer(1).writeByte(value).array());
+        return this;
+    }
+
+    /**
+     * @param value protocol length in Bytes
+     */
+    public Arp setProtocolLength(short value) {
+        hdrFieldsMap.put(PLEN, Unpooled.buffer(1).writeByte(value).array());
+        return this;
+    }
+
+    public Arp setOperation(int value) {
+        hdrFieldsMap.put(OPERATION, Unpooled.copyShort(value).array());
+        return this;
+    }
+
+    public Arp setSenderHardwareAddress(byte[] value) {
+        hdrFieldsMap.put(SHA, value);
+        return this;
+    }
+
+    public Arp setSenderProtocolAddress(byte[] value) {
+        hdrFieldsMap.put(SPA, value);
+        return this;
+    }
+
+    public Arp setTargetHardwareAddress(byte[] value) {
+        hdrFieldsMap.put(THA, value);
+        return this;
+    }
+
+    public Arp setTargetProtocolAddress(byte[] value) {
+        hdrFieldsMap.put(TPA, value);
+        return this;
+    }
+
+    public int getHardwareType() {
+        byte[] htype = hdrFieldsMap.get(HTYPE);
+        return Unpooled.wrappedBuffer(htype).readUnsignedShort();
+    }
+
+    public int getProtocolType() {
+        byte[] ptype = hdrFieldsMap.get(PTYPE);
+        return Unpooled.wrappedBuffer(ptype).readUnsignedShort();
+    }
+
+    public short getHardwareLength() {
+        byte[] hlen = hdrFieldsMap.get(HLEN);
+        return Unpooled.wrappedBuffer(hlen).readUnsignedByte();
+    }
+
+    public short getProtocolLength() {
+        byte[] plen = hdrFieldsMap.get(PLEN);
+        return Unpooled.wrappedBuffer(plen).readUnsignedByte();
+    }
+
+    public int getOperation() {
+        byte[] operation = hdrFieldsMap.get(OPERATION);
+        return Unpooled.wrappedBuffer(operation).readUnsignedShort();
+    }
+
+    public byte[] getSenderHardwareAddress() {
+        return hdrFieldsMap.get(SHA);
+    }
+
+    public byte[] getSenderProtocolAddress() {
+        return hdrFieldsMap.get(SPA);
+    }
+
+    public byte[] getTargetHardwareAddress() {
+        return hdrFieldsMap.get(THA);
+    }
+
+    public byte[] getTargetProtocolAddress() {
+        return hdrFieldsMap.get(TPA);
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpFlowFactory.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpFlowFactory.java
new file mode 100644 (file)
index 0000000..b375765
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.types.rev131026.OutputPortValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
+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.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.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
+
+/**
+ * Contains methods creating flow part for ARP flow.
+ */
+public class ArpFlowFactory {
+
+    private static final String HOST_MASK = "/32";
+
+    /**
+     * Creates {@link EthernetMatch} containing ARP ether-type and the given destination MAC address
+     */
+    public static EthernetMatch createEthernetMatch(MacAddress destinationMacAddress) {
+        return new EthernetMatchBuilder().setEthernetType(
+                new EthernetTypeBuilder().setType(new EtherType((long) EtherTypes.ARP.intValue())).build())
+            .setEthernetDestination(new EthernetDestinationBuilder().setAddress(destinationMacAddress).build())
+            .build();
+    }
+
+    /**
+     * Creates {@link ArpMatch} containing Reply ARP operation, THA and TPA for the given target
+     * address and SPA for the given sender protocol address
+     */
+    public static ArpMatch createArpMatch(ArpMessageAddress targetAddress, Ipv4Address senderProtocolAddress) {
+        return new ArpMatchBuilder().setArpOp(ArpOperation.REPLY.intValue())
+            .setArpTargetHardwareAddress(
+                    new ArpTargetHardwareAddressBuilder().setAddress(targetAddress.getHardwareAddress()).build())
+            .setArpTargetTransportAddress(new Ipv4Prefix(targetAddress.getProtocolAddress().getValue() + HOST_MASK))
+            .setArpSourceTransportAddress(new Ipv4Prefix(senderProtocolAddress.getValue() + HOST_MASK))
+            .build();
+    }
+
+    /**
+     * Creates {@link Action} representing output to the controller
+     *
+     * @param order the order for the action
+     */
+    public static Action createSendToControllerAction(int order) {
+        return new ActionBuilder().setOrder(order)
+            .setKey(new ActionKey(order))
+            .setAction(
+                    new OutputActionCaseBuilder().setOutputAction(
+                            new OutputActionBuilder().setMaxLength(0xffff)
+                                .setOutputNodeConnector(new Uri(OutputPortValues.CONTROLLER.toString()))
+                                .build()).build())
+            .build();
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpMessageAddress.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpMessageAddress.java
new file mode 100644 (file)
index 0000000..4e9d719
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+/**
+ * Represents ARP fields where protocol address is IPv4 address and hardware address is MAC address.
+ */
+@Immutable
+public class ArpMessageAddress {
+
+    private final MacAddress hwAddress;
+    private final Ipv4Address protocolAddress;
+
+    public ArpMessageAddress(MacAddress hwAddress, Ipv4Address protocolAddress) {
+        this.hwAddress = checkNotNull(hwAddress);
+        this.protocolAddress = checkNotNull(protocolAddress);
+    }
+
+    public MacAddress getHardwareAddress() {
+        return hwAddress;
+    }
+
+    public Ipv4Address getProtocolAddress() {
+        return protocolAddress;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpOperation.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpOperation.java
new file mode 100644 (file)
index 0000000..14e801e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import javax.annotation.Nullable;
+
+public enum ArpOperation {
+
+    REQUEST(1), REPLY(2);
+
+    private final int intOperation;
+
+    ArpOperation(int operationNumber) {
+        this.intOperation = operationNumber;
+    }
+
+    public int intValue() {
+        return intOperation;
+    }
+
+    public static @Nullable ArpOperation loadFromInt(int intOperation) {
+        for (ArpOperation operation : ArpOperation.values()) {
+            if (operation.intOperation == intOperation) {
+                return operation;
+            }
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpResolverMetadata.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpResolverMetadata.java
new file mode 100644 (file)
index 0000000..2552664
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.providers.openflow13.services.arp;
+
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolverListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+
+/**
+*
+* @author Anil Vishnoi (avishnoi@Brocade.com)
+*
+*/
+
+public final class ArpResolverMetadata {
+
+    private final GatewayMacResolverListener gatewayMacResolverListener;
+    private final Ipv4Address gatewayIpAddress;
+    private Long externalNetworkBridgeDpid;
+    private final boolean refreshExternalNetworkBridgeDpidIfNeeded;
+    private final Ipv4Address arpRequestSourceIp;
+    private final MacAddress arpRequestSourceMacAddress;
+    private final boolean periodicRefresh;
+    private RemoveFlowInput flowToRemove;
+    private MacAddress gatewayMacAddress;
+    private boolean gatewayMacAddressResolved;
+    private int numberOfOutstandingArpRequests;
+    private static final int MAX_OUTSTANDING_ARP_REQUESTS = 2;
+
+    public ArpResolverMetadata(final GatewayMacResolverListener gatewayMacResolverListener,
+                               final Long externalNetworkBridgeDpid,
+                               final boolean refreshExternalNetworkBridgeDpidIfNeeded,
+            final Ipv4Address gatewayIpAddress, final Ipv4Address arpRequestSourceIp,
+            final MacAddress arpRequestMacAddress, final boolean periodicRefresh){
+        this.gatewayMacResolverListener = gatewayMacResolverListener;
+        this.externalNetworkBridgeDpid = externalNetworkBridgeDpid;
+        this.refreshExternalNetworkBridgeDpidIfNeeded = refreshExternalNetworkBridgeDpidIfNeeded;
+        this.gatewayIpAddress = gatewayIpAddress;
+        this.arpRequestSourceIp = arpRequestSourceIp;
+        this.arpRequestSourceMacAddress = arpRequestMacAddress;
+        this.periodicRefresh = periodicRefresh;
+        this.gatewayMacAddress = null;
+        this.gatewayMacAddressResolved = false;
+        this.numberOfOutstandingArpRequests = 0;
+    }
+
+    public boolean isRefreshExternalNetworkBridgeDpidIfNeeded() {
+        return refreshExternalNetworkBridgeDpidIfNeeded;
+    }
+    public boolean isPeriodicRefresh() {
+        return periodicRefresh;
+    }
+    public RemoveFlowInput getFlowToRemove() {
+        return flowToRemove;
+    }
+    public void setFlowToRemove(RemoveFlowInput flowToRemove) {
+        this.flowToRemove = flowToRemove;
+    }
+    public Ipv4Address getGatewayIpAddress() {
+        return gatewayIpAddress;
+    }
+    public MacAddress getGatewayMacAddress() {
+        return gatewayMacAddress;
+    }
+    public void setGatewayMacAddress(MacAddress gatewayMacAddress) {
+        if (gatewayMacAddress != null) {
+            if (gatewayMacResolverListener != null &&
+                    !gatewayMacAddress.equals(this.gatewayMacAddress)) {
+                gatewayMacResolverListener.gatewayMacResolved(externalNetworkBridgeDpid,
+                        new IpAddress(gatewayIpAddress), gatewayMacAddress);
+            }
+            gatewayMacAddressResolved = true;
+            numberOfOutstandingArpRequests = 0;
+        } else {
+            gatewayMacAddressResolved = false;
+        }
+        this.gatewayMacAddress = gatewayMacAddress;
+    }
+
+    public Long getExternalNetworkBridgeDpid() {
+        return externalNetworkBridgeDpid;
+    }
+    public void setExternalNetworkBridgeDpid(Long externalNetworkBridgeDpid) {
+        this.externalNetworkBridgeDpid = externalNetworkBridgeDpid;
+    }
+    public Ipv4Address getArpRequestSourceIp() {
+        return arpRequestSourceIp;
+    }
+    public MacAddress getArpRequestSourceMacAddress() {
+        return arpRequestSourceMacAddress;
+    }
+    public boolean isGatewayMacAddressResolved() {
+        return gatewayMacAddressResolved;
+    }
+
+    /**
+     * This method is used to determine whether to use the broadcast MAC or the unicast MAC as the destination address
+     * for an ARP request packet based on whether one of the last MAX_OUTSTANDING_ARP_REQUESTS requests has been
+     * answered.
+     *
+     * A counter (numberOfOutstandingArpRequests) is maintained to track outstanding ARP requests.  This counter is
+     * incremented in this method and reset when setGatewayMacAddress() is called with an updated MAC address after an
+     * ARP reply is received. It is therefore expected that this method be called exactly once for each ARP request
+     * event, and not be called for other reasons, or it may result in more broadcast ARP request packets being sent
+     * than needed.
+     *
+     * @return Destination MAC address to be used in ARP request packet:  Either the unicast MAC or the broadcast MAC
+     * as described above.
+     */
+    public MacAddress getArpRequestDestMacAddress() {
+
+        numberOfOutstandingArpRequests++;
+
+        if (numberOfOutstandingArpRequests > MAX_OUTSTANDING_ARP_REQUESTS) {
+            gatewayMacAddressResolved = false;
+        }
+
+        if (gatewayMacAddressResolved) {
+            return gatewayMacAddress;
+        } else {
+            return ArpUtils.bytesToMac(NetUtils.getBroadcastMACAddr());
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+
+        result = prime
+                * result
+                + ((gatewayMacResolverListener == null) ? 0 : gatewayMacResolverListener.hashCode());
+        result = prime
+                * result
+                + ((arpRequestSourceMacAddress == null) ? 0 : arpRequestSourceMacAddress
+                        .hashCode());
+        result = prime
+                * result
+                + ((arpRequestSourceIp == null) ? 0 : arpRequestSourceIp
+                        .hashCode());
+        result = prime
+                * result
+                + ((externalNetworkBridgeDpid == null) ? 0
+                        : externalNetworkBridgeDpid.hashCode());
+        result = prime
+                * result
+                + ((gatewayIpAddress == null) ? 0 : gatewayIpAddress.hashCode());
+        result = prime * result + (periodicRefresh ? 1231 : 1237);
+        result = prime * result + (refreshExternalNetworkBridgeDpidIfNeeded ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ArpResolverMetadata other = (ArpResolverMetadata) obj;
+        if (gatewayMacResolverListener == null) {
+            if (other.gatewayMacResolverListener != null)
+                return false;
+        } else if (!gatewayMacResolverListener.equals(other.gatewayMacResolverListener))
+            return false;
+        if (arpRequestSourceMacAddress == null) {
+            if (other.arpRequestSourceMacAddress != null)
+                return false;
+        } else if (!arpRequestSourceMacAddress.equals(other.arpRequestSourceMacAddress))
+            return false;
+        if (arpRequestSourceIp == null) {
+            if (other.arpRequestSourceIp != null)
+                return false;
+        } else if (!arpRequestSourceIp.equals(other.arpRequestSourceIp))
+            return false;
+        if (externalNetworkBridgeDpid == null) {
+            if (other.externalNetworkBridgeDpid != null)
+                return false;
+        } else if (!externalNetworkBridgeDpid
+                .equals(other.externalNetworkBridgeDpid))
+            return false;
+        if (gatewayIpAddress == null) {
+            if (other.gatewayIpAddress != null)
+                return false;
+        } else if (!gatewayIpAddress.equals(other.gatewayIpAddress))
+            return false;
+        if (periodicRefresh != other.periodicRefresh)
+            return false;
+        if (refreshExternalNetworkBridgeDpidIfNeeded != other.refreshExternalNetworkBridgeDpidIfNeeded)
+            return false;
+        return true;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpResolverUtils.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpResolverUtils.java
new file mode 100644 (file)
index 0000000..7e90f62
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ArpResolverUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(ArpResolverUtils.class);
+
+
+    static {
+        Ethernet.etherTypeClassMap.put(EtherTypes.ARP.shortValue(), Arp.class);
+    }
+
+    /**
+     * Tries to deserialize received packet as ARP packet with IPv4 protocol address and MAC
+     * hardware address.
+     *
+     * @param potentialArp the packet for deserialization
+     * @return ARP packet if received packet is ARP and deserialization was successful
+     */
+    public static Arp getArpFrom(PacketReceived potentialArp) {
+        byte[] payload = potentialArp.getPayload();
+        Ethernet ethPkt = new Ethernet();
+        try {
+            ethPkt.deserialize(payload, 0, payload.length * NetUtils.NumBitsInAByte);
+        } catch (PacketException e) {
+            LOG.trace("Failed to decode the incoming packet. ignoring it.");
+        }
+        if (ethPkt.getPayload() instanceof Arp) {
+            return (Arp) ethPkt.getPayload();
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpSender.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpSender.java
new file mode 100644 (file)
index 0000000..748ba8a
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+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.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Uses packet-out for sending ARP Requests.
+ */
+public class ArpSender {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ArpSender.class);
+
+    private static final String OFPP_ALL = "0xfffffffc";
+    private final PacketProcessingService packetProcessingService;
+
+    public ArpSender(PacketProcessingService packetProcessingService) {
+        this.packetProcessingService = checkNotNull(packetProcessingService);
+    }
+
+    /**
+     * Sends ARP Request as packet-out from all openflow physical ports on the given node.
+     *
+     * @param senderAddress the addresses used in sender part of ARP packet
+     * @param tpa the target protocol address, in this case IPv4 address for which MAC should be
+     *        discovered
+     * @param nodeIid the path to node from where the ARP packet will be flooded
+     * @return future result about success of packet-out
+     */
+    public ListenableFuture<RpcResult<Void>> floodArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
+            InstanceIdentifier<Node> nodeIid) {
+        checkNotNull(senderAddress);
+        checkNotNull(tpa);
+        checkNotNull(nodeIid);
+        // node connector representing all physical ports on node
+        NodeConnectorKey nodeConnectorKey = new NodeConnectorKey(createNodeConnectorId(OFPP_ALL,
+                nodeIid.firstKeyOf(Node.class, NodeKey.class).getId()));
+        InstanceIdentifier<NodeConnector> egressNc = nodeIid.child(NodeConnector.class, nodeConnectorKey);
+        return sendArp(senderAddress, tpa, null, egressNc);
+    }
+
+    private NodeConnectorId createNodeConnectorId(String connectorId, NodeId nodeId) {
+        return new NodeConnectorId(nodeId.getValue() + ":" + connectorId);
+    }
+
+    /**
+     * Sends ARP Request as packet-out from the given port (node connector).
+     *
+     * @param senderAddress the addresses used in sender part of ARP packet
+     * @param tpa the target protocol address, in this case IPv4 address for which MAC should be
+     *        discovered
+     * @param arpRequestDestMacAddress the destination MAC address to be used in the ARP packet or null if not known.
+     * @param egressNc the path to node connector from where the ARP packet will be sent  @return future result about success of packet-out
+     */
+    public ListenableFuture<RpcResult<Void>> sendArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
+                                                     MacAddress arpRequestDestMacAddress, InstanceIdentifier<NodeConnector> egressNc) {
+        checkNotNull(senderAddress);
+        checkNotNull(tpa);
+        checkNotNull(egressNc);
+        final Ethernet arpFrame = createArpFrame(senderAddress, tpa, arpRequestDestMacAddress);
+        byte[] arpFrameAsBytes;
+        try {
+            arpFrameAsBytes = arpFrame.serialize();
+        } catch (PacketException e) {
+            LOG.warn("Serializition of ARP packet is not successful.", e);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("ARP packet: {}", ArpUtils.getArpFrameToStringFormat(arpFrame));
+            }
+            return Futures.immediateFailedFuture(e);
+        }
+        // Generate packet with destination switch and port
+        TransmitPacketInput packet = new TransmitPacketInputBuilder().setEgress(new NodeConnectorRef(egressNc))
+            .setNode(new NodeRef(egressNc.firstIdentifierOf(Node.class)))
+            .setPayload(arpFrameAsBytes)
+            .build();
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Sending ARP REQUEST \n{}", ArpUtils.getArpFrameToStringFormat(arpFrame));
+        }
+        Future<RpcResult<Void>> futureTransmitPacketResult = packetProcessingService.transmitPacket(packet);
+        return JdkFutureAdapters.listenInPoolThread(futureTransmitPacketResult);
+    }
+
+    private Ethernet createArpFrame(ArpMessageAddress senderAddress, Ipv4Address tpa, MacAddress arpRequestDestMacAddress) {
+        byte[] senderMac = ArpUtils.macToBytes(senderAddress.getHardwareAddress());
+        byte[] senderIp = ArpUtils.ipToBytes(senderAddress.getProtocolAddress());
+        byte[] targetMac;
+        if (arpRequestDestMacAddress != null) {
+            targetMac = ArpUtils.macToBytes(arpRequestDestMacAddress);
+        } else {
+            targetMac = NetUtils.getBroadcastMACAddr();
+        }
+        byte[] targetIp = ArpUtils.ipToBytes(tpa);
+        Ethernet arpFrame = new Ethernet().setSourceMACAddress(senderMac)
+            .setDestinationMACAddress(targetMac)
+            .setEtherType(EtherTypes.ARP.shortValue());
+        Arp arp = new Arp().setOperation(ArpOperation.REQUEST.intValue())
+            .setSenderHardwareAddress(senderMac)
+            .setSenderProtocolAddress(senderIp)
+            .setTargetHardwareAddress(targetMac)
+            .setTargetProtocolAddress(targetIp);
+        arpFrame.setPayload(arp);
+        return arpFrame;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpUtils.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/ArpUtils.java
new file mode 100644 (file)
index 0000000..5ac175f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import javax.annotation.Nullable;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.HexEncode;
+import org.opendaylight.controller.liblldp.Packet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+import com.google.common.net.InetAddresses;
+
+public class ArpUtils {
+
+    private ArpUtils() {
+        throw new UnsupportedOperationException("Cannot create an instance.");
+    }
+
+    /**
+     * Returns Ethernet and ARP in readable string format
+     */
+    public static String getArpFrameToStringFormat(Ethernet eth) {
+        String ethernetString = "Ethernet [getEtherType()="
+                + EtherTypes.loadFromString(String.valueOf(eth.getEtherType())) + ", getSourceMACAddress()="
+                + HexEncode.bytesToHexStringFormat(eth.getSourceMACAddress()) + ", getDestinationMACAddress()="
+                + HexEncode.bytesToHexStringFormat(eth.getDestinationMACAddress()) + "]\n";
+        Packet potentialArp = eth.getPayload();
+        String arpString = null;
+        if (potentialArp instanceof Arp) {
+            Arp arp = (Arp) potentialArp;
+            arpString = ArpUtils.getArpToStringFormat(arp);
+        } else {
+            arpString = "ARP was not found in Ethernet frame.";
+        }
+        return ethernetString.concat(arpString);
+    }
+
+    /**
+     * Returns ARP in readable string format
+     */
+    public static String getArpToStringFormat(Arp arp) {
+        try {
+            return "Arp [getHardwareType()=" + arp.getHardwareType() + ", getProtocolType()=" + arp.getProtocolType()
+                    + ", getHardwareLength()=" + arp.getHardwareLength() + ", getProtocolLength()="
+                    + arp.getProtocolLength() + ", getOperation()=" + ArpOperation.loadFromInt(arp.getOperation())
+                    + ", getSenderHardwareAddress()="
+                    + HexEncode.bytesToHexStringFormat(arp.getSenderHardwareAddress())
+                    + ", getSenderProtocolAddress()="
+                    + InetAddress.getByAddress(arp.getSenderProtocolAddress()).getHostAddress()
+                    + ", getTargetHardwareAddress()="
+                    + HexEncode.bytesToHexStringFormat(arp.getTargetHardwareAddress())
+                    + ", getTargetProtocolAddress()="
+                    + InetAddress.getByAddress(arp.getTargetProtocolAddress()).getHostAddress() + "]\n";
+        } catch (UnknownHostException e1) {
+            return "Error during parsing Arp " + arp;
+        }
+    }
+
+    public static byte[] macToBytes(MacAddress mac) {
+        return HexEncode.bytesFromHexString(mac.getValue());
+    }
+
+    public static @Nullable MacAddress bytesToMac(byte[] macBytes) {
+        String mac = HexEncode.bytesToHexStringFormat(macBytes);
+        if (!"null".equals(mac)) {
+            return new MacAddress(mac);
+        }
+        return null;
+    }
+
+    public static byte[] ipToBytes(Ipv4Address ip) {
+        return InetAddresses.forString(ip.getValue()).getAddress();
+    }
+
+    public static @Nullable Ipv4Address bytesToIp(byte[] ipv4AsBytes) {
+        try {
+            return new Ipv4Address(InetAddress.getByAddress(ipv4AsBytes).getHostAddress());
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java
new file mode 100644 (file)
index 0000000..0ce4972
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.providers.openflow13.services.arp;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolverListener;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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;
+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.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.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+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.FlowRef;
+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.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.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
+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.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+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.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ *
+ * @author Anil Vishnoi (avishnoi@Brocade.com)
+ *
+ */
+public class GatewayMacResolverService extends AbstractServiceInstance
+                                        implements ConfigInterface, GatewayMacResolver,PacketProcessingListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GatewayMacResolverService.class);
+    private static final String ARP_REPLY_TO_CONTROLLER_FLOW_NAME = "GatewayArpReplyRouter";
+    private static final int ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY = 10000;
+    private static final Instruction SEND_TO_CONTROLLER_INSTRUCTION;
+    private ArpSender arpSender;
+    private SalFlowService flowService;
+    private final AtomicLong flowCookie = new AtomicLong();
+    private final ConcurrentMap<Ipv4Address, ArpResolverMetadata> gatewayToArpMetadataMap =
+            new ConcurrentHashMap<>();
+    private static final int ARP_WATCH_BROTHERS = 10;
+    private static final int WAIT_CYCLES = 3;
+    private static final int PER_CYCLE_WAIT_DURATION = 1000;
+    private static final int REFRESH_INTERVAL = 10;
+    private final ListeningExecutorService arpWatcherWall = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(ARP_WATCH_BROTHERS));
+    private final ScheduledExecutorService gatewayMacRefresherPool = Executors.newScheduledThreadPool(1);
+    private final ScheduledExecutorService refreshRequester = Executors.newSingleThreadScheduledExecutor();
+    private AtomicBoolean initializationDone = new AtomicBoolean(false);
+    private volatile ConfigurationService configurationService;
+    private volatile NodeCacheManager nodeCacheManager;
+
+    static {
+        ApplyActions applyActions = new ApplyActionsBuilder().setAction(
+                ImmutableList.of(ArpFlowFactory.createSendToControllerAction(0))).build();
+        SEND_TO_CONTROLLER_INSTRUCTION = new InstructionBuilder().setOrder(0)
+            .setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions).build())
+            .build();
+    }
+
+    public GatewayMacResolverService(){
+        super(Service.GATEWAY_RESOLVER);
+    }
+
+    public GatewayMacResolverService(Service service){
+        super(service);
+    }
+
+    private void init(){
+        if(!initializationDone.get()){
+            initializationDone.set(true);
+            ProviderContext providerContext = NetvirtProvidersProvider.getProviderContext();
+            checkNotNull(providerContext);
+            PacketProcessingService packetProcessingService = providerContext.getRpcService(PacketProcessingService.class);
+            if (packetProcessingService != null) {
+                LOG.debug("{} was found.", PacketProcessingService.class.getSimpleName());
+                this.arpSender = new ArpSender(packetProcessingService);
+            } else {
+                LOG.error("Missing service {}", PacketProcessingService.class.getSimpleName());
+                this.arpSender = null;
+            }
+            flowService = providerContext.getRpcService(SalFlowService.class);
+            refreshRequester.scheduleWithFixedDelay(new Runnable(){
+
+                @Override
+                public void run() {
+                    if (!gatewayToArpMetadataMap.isEmpty()){
+                        for(final Entry<Ipv4Address, ArpResolverMetadata> gatewayToArpMetadataEntry : gatewayToArpMetadataMap.entrySet()){
+                            final Ipv4Address gatewayIp = gatewayToArpMetadataEntry.getKey();
+                            final ArpResolverMetadata gatewayMetaData =
+                                    checkAndGetExternalBridgeDpid(
+                                            resetFlowToRemove(gatewayIp, gatewayToArpMetadataEntry.getValue()));
+                            gatewayMacRefresherPool.schedule(new Runnable(){
+
+                                @Override
+                                public void run() {
+
+                                    final Node externalNetworkBridge = getExternalBridge(gatewayMetaData.getExternalNetworkBridgeDpid());
+                                    if(externalNetworkBridge == null){
+                                        LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} "
+                                                + "is not connected to controller.",
+                                                gatewayIp.getValue(),
+                                                gatewayMetaData.getExternalNetworkBridgeDpid() );
+                                    } else {
+                                        LOG.debug("Refresh Gateway Mac for gateway {} using source ip {} and mac {} for ARP request",
+                                                gatewayIp.getValue(),gatewayMetaData.getArpRequestSourceIp().getValue(),gatewayMetaData.getArpRequestSourceMacAddress().getValue());
+
+                                        sendGatewayArpRequest(externalNetworkBridge,gatewayIp,gatewayMetaData.getArpRequestSourceIp(), gatewayMetaData.getArpRequestSourceMacAddress());
+                                    }
+                                }
+                            }, 1, TimeUnit.SECONDS);
+                        }
+                    }
+                }
+            }, REFRESH_INTERVAL, REFRESH_INTERVAL, TimeUnit.SECONDS);
+        }
+    }
+    /**
+     * Method do following actions:
+     * 1. Install flow to direct ARP response packet to controller
+     * 2. Send ARP request packet out on all port of the given External network bridge.
+     * 3. Cache the flow that need to be removed once ARP resolution is done.
+     * 4. Return listenable future so that user can add callback to get the MacAddress
+     * @param externalNetworkBridgeDpid Broadcast ARP request packet on this bridge
+     * @param gatewayIp IP address for which MAC need to be resolved
+     * @param sourceIpAddress Source Ip address for the ARP request packet
+     * @param sourceMacAddress Source Mac address for the ARP request packet
+     * @param periodicRefresh Enable/Disable periodic refresh of the Gateway Mac address
+     * @return Future object
+     */
+    @Override
+    public ListenableFuture<MacAddress> resolveMacAddress(
+            final GatewayMacResolverListener gatewayMacResolverListener, final Long externalNetworkBridgeDpid,
+            final Boolean refreshExternalNetworkBridgeDpidIfNeeded,
+            final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress,
+            final Boolean periodicRefresh){
+        Preconditions.checkNotNull(refreshExternalNetworkBridgeDpidIfNeeded);
+        Preconditions.checkNotNull(sourceIpAddress);
+        Preconditions.checkNotNull(sourceMacAddress);
+        Preconditions.checkNotNull(gatewayIp);
+
+        LOG.info("Trigger Mac resolution for gateway {}, using source ip {} and mac {}",
+                gatewayIp.getValue(),sourceIpAddress.getValue(),sourceMacAddress.getValue());
+
+        init();
+        if(gatewayToArpMetadataMap.containsKey(gatewayIp)){
+            if(gatewayToArpMetadataMap.get(gatewayIp).getGatewayMacAddress() != null){
+                return arpWatcherWall.submit(new Callable<MacAddress>(){
+
+                    @Override
+                    public MacAddress call() throws Exception {
+                        return gatewayToArpMetadataMap.get(gatewayIp).getGatewayMacAddress();
+                    }
+                });
+            }
+        }else{
+            gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata(gatewayMacResolverListener,
+                    externalNetworkBridgeDpid, refreshExternalNetworkBridgeDpidIfNeeded,
+                    gatewayIp, sourceIpAddress, sourceMacAddress, periodicRefresh));
+        }
+
+
+        final Node externalNetworkBridge = getExternalBridge(externalNetworkBridgeDpid);
+        if (externalNetworkBridge == null) {
+            if (!refreshExternalNetworkBridgeDpidIfNeeded) {
+                LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} "
+                        + "is not connected to controller.", gatewayIp.getValue(), externalNetworkBridgeDpid);
+            } else {
+                LOG.debug("MAC address for gateway {} can not be resolved, since dpid was not refreshed yet",
+                        gatewayIp.getValue());
+            }
+            return null;
+        }
+
+        sendGatewayArpRequest(externalNetworkBridge,gatewayIp,sourceIpAddress, sourceMacAddress);
+
+        //Wait for MacAddress population in cache
+        return waitForMacAddress(gatewayIp);
+    }
+
+    private Node getExternalBridge(final Long externalNetworkBridgeDpid){
+        if (externalNetworkBridgeDpid != null) {
+            final String nodeName = OPENFLOW + externalNetworkBridgeDpid;
+            return getOpenFlowNode(nodeName);
+        }
+        return null;
+    }
+
+    private ArpResolverMetadata checkAndGetExternalBridgeDpid(ArpResolverMetadata gatewayMetaData) {
+        final Long origDpid = gatewayMetaData.getExternalNetworkBridgeDpid();
+
+        // If we are not allowing dpid to change, there is nothing further to do here
+        if (!gatewayMetaData.isRefreshExternalNetworkBridgeDpidIfNeeded()) {
+            return gatewayMetaData;
+        }
+
+        // If current dpid is null, or if mac is not getting resolved, make an attempt to
+        // grab a different dpid, so a different (or updated) external bridge gets used
+        if (origDpid == null || !gatewayMetaData.isGatewayMacAddressResolved()) {
+            Long newDpid = getAnotherExternalBridgeDpid(origDpid);
+            gatewayMetaData.setExternalNetworkBridgeDpid(newDpid);
+        }
+
+        return gatewayMetaData;
+    }
+
+    private Long getAnotherExternalBridgeDpid(final Long unwantedDpid) {
+        LOG.trace("Being asked to find a new dpid. unwantedDpid:{} cachemanager:{} configurationService:{}",
+                unwantedDpid, nodeCacheManager, configurationService);
+
+        if (nodeCacheManager == null) {
+            LOG.error("Unable to find external dpid to use for resolver: no nodeCacheManager");
+            return unwantedDpid;
+        }
+        if (configurationService == null) {
+            LOG.error("Unable to find external dpid to use for resolver: no configurationService");
+            return unwantedDpid;
+        }
+
+        // Pickup another dpid in list that is different than the unwanted one provided and is in the
+        // operational tree. If none can be found, return the provided dpid as a last resort.
+        // NOTE: We are assuming that all the br-ex are serving one external network and gateway ip of
+        // the external network is reachable from every br-ex
+        // TODO: Consider other deployment scenario, and think of another solution.
+        List<Long> dpids =  nodeCacheManager.getBridgeDpids(configurationService.getExternalBridgeName());
+        Collections.shuffle(dpids);
+        for (Long dpid : dpids) {
+            if (dpid == null || dpid.equals(unwantedDpid) || getExternalBridge(dpid) == null) {
+                continue;
+            }
+
+            LOG.debug("Gateway Mac Resolver Service will use dpid {}", dpid);
+            return dpid;
+        }
+
+        LOG.warn("Unable to find usable external dpid for resolver. Best choice is still {}", unwantedDpid);
+        return unwantedDpid;
+    }
+
+    private void sendGatewayArpRequest(final Node externalNetworkBridge,final Ipv4Address gatewayIp,
+            final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress){
+        final ArpMessageAddress senderAddress = new ArpMessageAddress(sourceMacAddress,sourceIpAddress);
+
+        //Build arp reply router flow
+        final Flow arpReplyToControllerFlow = createArpReplyToControllerFlow(senderAddress, gatewayIp);
+
+        final InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, externalNetworkBridge.getKey())
+                .build();
+        final InstanceIdentifier<Flow> flowIid = createFlowIid(arpReplyToControllerFlow, nodeIid);
+        final NodeRef nodeRef = new NodeRef(nodeIid);
+
+        //Install flow
+        Future<RpcResult<AddFlowOutput>> addFlowResult = flowService.addFlow(new AddFlowInputBuilder(
+                arpReplyToControllerFlow).setFlowRef(new FlowRef(flowIid)).setNode(nodeRef).build());
+        //wait for flow installation
+        Futures.addCallback(JdkFutureAdapters.listenInPoolThread(addFlowResult),
+                new FutureCallback<RpcResult<AddFlowOutput>>() {
+
+            @Override
+            public void onSuccess(RpcResult<AddFlowOutput> result) {
+                if (!result.isSuccessful()) {
+                    LOG.warn("Flow to route ARP Reply to Controller is not installed successfully : {} \nErrors: {}", flowIid,result.getErrors());
+                    return;
+                }
+                LOG.debug("Flow to route ARP Reply to Controller installed successfully : {}", flowIid);
+
+                ArpResolverMetadata gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp);
+                if (gatewayArpMetadata == null) {
+                    LOG.warn("No metadata found for gatewayIp: {}", gatewayIp);
+                    return;
+                }
+
+                //cache metadata
+                gatewayArpMetadata.setFlowToRemove(new RemoveFlowInputBuilder(arpReplyToControllerFlow).setNode(nodeRef).build());
+
+                //get MAC DA for ARP packets
+                MacAddress arpRequestDestMacAddress = gatewayArpMetadata.getArpRequestDestMacAddress();
+
+                //Send ARP request packets
+                for (NodeConnector egressNc : externalNetworkBridge.getNodeConnector()) {
+                    KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> egressNcIid = nodeIid.child(
+                            NodeConnector.class, new NodeConnectorKey(egressNc.getId()));
+                    ListenableFuture<RpcResult<Void>> futureSendArpResult = arpSender.sendArp(
+                            senderAddress, gatewayIp, arpRequestDestMacAddress, egressNcIid);
+                    Futures.addCallback(futureSendArpResult, logResult(gatewayIp, egressNcIid));
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.warn("ARP Reply to Controller flow was not created: {}", flowIid, t);
+            }
+            }
+        );
+    }
+
+    private ListenableFuture<MacAddress> waitForMacAddress(final Ipv4Address gatewayIp){
+
+        return arpWatcherWall.submit(new Callable<MacAddress>(){
+
+            @Override
+            public MacAddress call() throws Exception {
+                for(int cycle = 0;cycle < WAIT_CYCLES;cycle++){
+                    //Sleep before checking mac address, so meanwhile ARP request packets
+                    // will be broadcasted on the bridge.
+                    Thread.sleep(PER_CYCLE_WAIT_DURATION);
+                    ArpResolverMetadata arpResolverMetadata = gatewayToArpMetadataMap.get(gatewayIp);
+                    if(arpResolverMetadata != null && arpResolverMetadata.getGatewayMacAddress() != null){
+                        if(!arpResolverMetadata.isPeriodicRefresh()){
+                            resetFlowToRemove(gatewayIp, arpResolverMetadata);
+                            return gatewayToArpMetadataMap.remove(gatewayIp).getGatewayMacAddress();
+                        }
+                        return arpResolverMetadata.getGatewayMacAddress();
+                    }
+                }
+                return null;
+            }
+        });
+    }
+
+    private Flow createArpReplyToControllerFlow(final ArpMessageAddress senderAddress, final Ipv4Address ipForRequestedMac) {
+        checkNotNull(senderAddress);
+        checkNotNull(ipForRequestedMac);
+        FlowBuilder arpFlow = new FlowBuilder().setTableId(Service.CLASSIFIER.getTable())
+            .setFlowName(ARP_REPLY_TO_CONTROLLER_FLOW_NAME)
+            .setPriority(ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY)
+            .setBufferId(OFConstants.OFP_NO_BUFFER)
+            .setIdleTimeout(0)
+            .setHardTimeout(0)
+            .setCookie(new FlowCookie(BigInteger.valueOf(flowCookie.incrementAndGet())))
+            .setFlags(new FlowModFlags(false, false, false, false, false));
+
+        EthernetMatch ethernetMatch = ArpFlowFactory.createEthernetMatch(senderAddress.getHardwareAddress());
+        ArpMatch arpMatch = ArpFlowFactory.createArpMatch(senderAddress, ipForRequestedMac);
+        Match match = new MatchBuilder().setEthernetMatch(ethernetMatch).setLayer3Match(arpMatch).build();
+        arpFlow.setMatch(match);
+        arpFlow.setInstructions(new InstructionsBuilder().setInstruction(
+                ImmutableList.of(SEND_TO_CONTROLLER_INSTRUCTION)).build());
+        arpFlow.setId(createFlowId(ipForRequestedMac));
+        return arpFlow.build();
+    }
+
+    private FlowId createFlowId(Ipv4Address ipForRequestedMac) {
+        String flowId = ARP_REPLY_TO_CONTROLLER_FLOW_NAME + "|" + ipForRequestedMac.getValue();
+        return new FlowId(flowId);
+    }
+
+    private static InstanceIdentifier<Flow> createFlowIid(Flow flow, InstanceIdentifier<Node> nodeIid) {
+        return nodeIid.builder()
+            .augmentation(FlowCapableNode.class)
+            .child(Table.class, new TableKey(flow.getTableId()))
+            .child(Flow.class, new FlowKey(flow.getId()))
+            .build();
+    }
+
+    private FutureCallback<RpcResult<Void>> logResult(final Ipv4Address tpa,
+            final KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> egressNcIid) {
+        return new FutureCallback<RpcResult<Void>>() {
+
+            @Override
+            public void onSuccess(RpcResult<Void> result) {
+                LOG.debug("ARP Request for IP {} was sent from {}.", tpa.getValue(), egressNcIid);
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.warn("ARP Request for IP {} was NOT sent from {}.", tpa.getValue(), egressNcIid);
+            }
+        };
+    }
+
+    @Override
+    public void onPacketReceived(PacketReceived potentialArp) {
+        Arp arp = ArpResolverUtils.getArpFrom(potentialArp);
+        if(arp != null){
+            if (arp.getOperation() != ArpOperation.REPLY.intValue()) {
+                LOG.trace("Packet is not ARP REPLY packet.");
+                return;
+            }
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("ARP REPLY received - {}", ArpUtils.getArpToStringFormat(arp));
+            }
+            NodeKey nodeKey = potentialArp.getIngress().getValue().firstKeyOf(Node.class, NodeKey.class);
+            if (nodeKey == null) {
+                LOG.info("Unknown source node of ARP packet: {}", potentialArp);
+                return;
+            }
+            Ipv4Address gatewayIpAddress = ArpUtils.bytesToIp(arp.getSenderProtocolAddress());
+            MacAddress gatewayMacAddress = ArpUtils.bytesToMac(arp.getSenderHardwareAddress());
+            ArpResolverMetadata candidateGatewayIp = gatewayToArpMetadataMap.get(gatewayIpAddress);
+            if(candidateGatewayIp != null){
+                LOG.debug("Resolved MAC for Gateway Ip {} is {}",gatewayIpAddress.getValue(),gatewayMacAddress.getValue());
+                candidateGatewayIp.setGatewayMacAddress(gatewayMacAddress);
+                resetFlowToRemove(gatewayIpAddress, candidateGatewayIp);
+            }
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext,
+            ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(GatewayMacResolver.class.getName()), this);
+
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof NodeCacheManager) {
+            nodeCacheManager = (NodeCacheManager) impl;
+        } else if (impl instanceof ConfigurationService) {
+            configurationService = (ConfigurationService) impl;
+        }
+    }
+
+    @Override
+    public void stopPeriodicRefresh(Ipv4Address gatewayIp) {
+        init();
+        resetFlowToRemove(gatewayIp, null);
+        gatewayToArpMetadataMap.remove(gatewayIp);
+    }
+
+    private ArpResolverMetadata resetFlowToRemove(
+            final Ipv4Address gatewayIp, ArpResolverMetadata gatewayArpMetadata) {
+        checkNotNull(gatewayIp);
+
+        // If gatewayArpMetadata was not provided, look it up
+        if (gatewayArpMetadata == null) {
+            gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp);
+        }
+        if (gatewayArpMetadata != null && gatewayArpMetadata.getFlowToRemove() != null) {
+            LOG.debug("Flow to route ARP Reply to Controller from {} being removed from node {}",
+                    gatewayIp, gatewayArpMetadata.getFlowToRemove().getNode());
+            flowService.removeFlow(gatewayArpMetadata.getFlowToRemove());
+            gatewayArpMetadata.setFlowToRemove(null);
+        }
+        return gatewayArpMetadata;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModule.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModule.java
new file mode 100644 (file)
index 0000000..e5d9732
--- /dev/null
@@ -0,0 +1,35 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.impl.rev150513;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.osgi.framework.BundleContext;
+
+public class NetvirtProvidersImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.impl.rev150513.AbstractNetvirtProvidersImplModule {
+    private BundleContext bundleContext = null;
+
+    public NetvirtProvidersImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetvirtProvidersImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.impl.rev150513.NetvirtProvidersImplModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        NetvirtProvidersProvider provider = new NetvirtProvidersProvider(bundleContext,
+                getClusteringEntityOwnershipServiceDependency(), getTableOffset());
+        BindingAwareBroker localBroker = getBrokerDependency();
+        localBroker.registerProvider(provider);
+        return provider;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModuleFactory.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModuleFactory.java
new file mode 100644 (file)
index 0000000..3fdd06d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netvirt-providers-impl yang module local name: netvirt-providers-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed May 20 16:57:59 EDT 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.impl.rev150513;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtProvidersImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.impl.rev150513.AbstractNetvirtProvidersImplModuleFactory {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtProvidersImplModuleFactory.class);
+
+    @Override
+    public Module createModule(String instanceName,
+                               DependencyResolver dependencyResolver,
+                               DynamicMBeanWithInstance old, BundleContext bundleContext)
+            throws Exception {
+        Module module =  super.createModule(instanceName, dependencyResolver, old, bundleContext);
+        setModuleBundleContext(bundleContext, module);
+        return module;
+    }
+
+    @Override
+    public Module createModule(String instanceName,
+                               DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        Module module = super.createModule(instanceName, dependencyResolver, bundleContext);
+        setModuleBundleContext(bundleContext, module);
+        return module;
+    }
+
+    private void setModuleBundleContext(BundleContext bundleContext,
+                                        Module module) {
+        if (module instanceof NetvirtProvidersImplModule) {
+            ((NetvirtProvidersImplModule)module).setBundleContext(bundleContext);
+        } else {
+            LOG.warn("Module is of type {} expected type {}",
+                    module.getClass(), NetvirtProvidersImplModule.class);
+        }
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/yang/netvirt-providers-config.yang b/openstack/net-virt-providers/src/main/yang/netvirt-providers-config.yang
new file mode 100644 (file)
index 0000000..780b020
--- /dev/null
@@ -0,0 +1,20 @@
+module netvirt-providers-config {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:providers:config";
+    prefix "netvirt-providers-config";
+
+    revision "2016-01-09" {
+        description "Initial revision of the netvirt providers config";
+    }
+
+    container netvirt-providers-config {
+        description "Configuration for NetvirtProviders";
+
+        config true;
+
+        leaf table-offset {
+            description "The table-offset is used to set the starting table for the netvirt pipeline";
+            type uint8;
+        }
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/yang/netvirt-providers-impl.yang b/openstack/net-virt-providers/src/main/yang/netvirt-providers-impl.yang
new file mode 100644 (file)
index 0000000..b02b37e
--- /dev/null
@@ -0,0 +1,50 @@
+module netvirt-providers-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl";
+    prefix "netvirt-providers-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+    import opendaylight-entity-ownership-service {prefix eos; revision-date 2015-08-10;}
+
+    description
+        "Service definition for netvirt providers project";
+
+    revision "2015-05-13" {
+        description
+            "Initial revision";
+    }
+
+    identity netvirt-providers-impl {
+        base config:module-type;
+        config:java-name-prefix NetvirtProvidersImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netvirtproviders-impl {
+            when "/config:modules/config:module/config:type = 'netvirt-providers-impl'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+
+            container clustering-entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
+                }
+            }
+
+            leaf table-offset {
+                description "The table-offset is used to set the starting table for the netvirt pipeline";
+                type uint8;
+            }
+        }
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersProviderTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/NetvirtProvidersProviderTest.java
new file mode 100644 (file)
index 0000000..b65d82d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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.openstack.netvirt.providers;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+
+/**
+ * Unit tests for {@link NetvirtProvidersProvider}
+ */
+public class NetvirtProvidersProviderTest {
+
+    /**
+     * Test for {@link NetvirtProvidersProvider#getTableOffset()}
+     */
+    @Test
+    public void testGetTableOffset() {
+        short tableOffset = 10;
+        NetvirtProvidersProvider netvirtProvidersProvider = new NetvirtProvidersProvider(null, null, tableOffset);
+        assertEquals("Table offset was not set", tableOffset, NetvirtProvidersProvider.getTableOffset());
+    }
+
+    /**
+     * Test for method {@link NetvirtProvidersProvider#setTableOffset(short)}
+     */
+    @Test
+    public void testSetTableOffset() {
+        // verify a good value can be set
+        short tableOffset = 0;
+        NetvirtProvidersProvider netvirtProvidersProvider = new NetvirtProvidersProvider(null, null, tableOffset);
+
+        tableOffset = 10;
+        NetvirtProvidersProvider.setTableOffset(tableOffset);
+        assertEquals("tableOffset was not set", tableOffset, NetvirtProvidersProvider.getTableOffset());
+    }
+
+    /**
+     * Negative test for method {@link NetvirtProvidersProvider#setTableOffset(short)}
+     */
+    @Test
+    public void testTableOffsetNegative() {
+        // verify an out of range value is not set
+        short tableOffset = 0;
+        NetvirtProvidersProvider netvirtProvidersProvider = new NetvirtProvidersProvider(null, null, tableOffset);
+
+        short tableOffsetBad = (short)(256 - Service.L2_FORWARDING.getTable());
+        NetvirtProvidersProvider.setTableOffset(tableOffsetBad);
+        assertEquals("tableOffset should not be set", 0, NetvirtProvidersProvider.getTableOffset());
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/AbstractServiceInstanceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/AbstractServiceInstanceTest.java
new file mode 100644 (file)
index 0000000..831545e
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.providers.openflow13;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+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.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test for {@link AbstractServiceInstance}
+ */
+@RunWith(PowerMockRunner.class)
+@SuppressWarnings("unchecked")
+public class AbstractServiceInstanceTest {
+
+    @InjectMocks private AbstractServiceInstance abstractServiceInstance = mock(AbstractServiceInstance.class, Mockito.CALLS_REAL_METHODS);
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+    @Mock private Southbound southbound;
+
+    private Service service = Service.L3_FORWARDING;
+
+    private final String ID = "5710881121";
+    private final String NODE_ID = Constants.INTEGRATION_BRIDGE + ":" +  ID;
+
+    /**
+     * Test method {@link AbstractServiceInstance#isBridgeInPipeline(Node)}
+     */
+    @Test
+    public void testIsBridgeInPipeline() {
+        when(southbound.getBridgeName(any(Node.class))).thenReturn(Constants.INTEGRATION_BRIDGE);
+        assertTrue("Error, isBridgeInPipeline() did not return the correct value", abstractServiceInstance.isBridgeInPipeline(mock(Node.class)));
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#getTable()}
+     */
+    @Test
+    public void testGetTable() {
+        abstractServiceInstance.setService(service);
+        assertEquals("Error, getTable() did not return the correct value",
+                service.getTable(), abstractServiceInstance.getTable());
+
+        when(orchestrator.getTableOffset()).thenReturn(Service.DIRECTOR.getTable());
+        assertEquals("Error, getTable() did not return the correct value",
+                (short)(Service.DIRECTOR.getTable() + service.getTable()), abstractServiceInstance.getTable());
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance@getTable(Service}
+     */
+    @Test
+    public void testGetTableWithService() {
+        when(orchestrator.getTableOffset()).thenReturn((short)0);
+        abstractServiceInstance.setService(service);
+        assertEquals("Error, getTables(service) did not return the correct value",
+                Service.L2_FORWARDING.getTable(), abstractServiceInstance.getTable(Service.L2_FORWARDING));
+    }
+
+    @Test
+    public void testGetService() {
+        abstractServiceInstance.setService(service);
+        assertEquals("Error, getService() did not return the correct value", service, abstractServiceInstance.getService());
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#createNodeBuilder(String)}
+     */
+    @Test
+    public void testCreateNodeBuilder() {
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(NODE_ID);
+
+        NodeBuilder nodeBuilder = abstractServiceInstance.createNodeBuilder(NODE_ID);
+        assertNotNull("Error, createNodeBuilder() did not return the correct value", nodeBuilder);
+        assertEquals("Error, createNodeBuilder() did not return the correct ID", NODE_ID, nodeBuilder.getId().getValue());
+        assertEquals("Error, createNodeBuilder() did not return the correct Key", new NodeKey(nodeBuilder.getId()), nodeBuilder.getKey());
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#getMutablePipelineInstructionBuilder()}
+     */
+    @Test
+    public void testGetMutablePipelineInstructionBuilder() {
+        // service == null
+        assertNotNull("Error, getMutablePipelineInstructionBuilder() did not return the correct value", abstractServiceInstance.getMutablePipelineInstructionBuilder());
+        assertTrue("Error, getMutablePipelineInstructionBuilder() did not return a InstructionBuilder object", abstractServiceInstance.getMutablePipelineInstructionBuilder() instanceof InstructionBuilder);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        // service defined
+        assertNotNull("Error, getMutablePipelineInstructionBuilder() did not return the correct value", abstractServiceInstance.getMutablePipelineInstructionBuilder());
+        assertTrue("Error, getMutablePipelineInstructionBuilder() did not return a InstructionBuilder object", abstractServiceInstance.getMutablePipelineInstructionBuilder() instanceof InstructionBuilder);
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#writeFlow(FlowBuilder, NodeBuilder)}
+     */
+    @Test
+    public void testWriteFlow() throws Exception {
+        WriteTransaction transaction = mock(WriteTransaction.class);
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(transaction);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = mock(CheckedFuture.class);
+        when(transaction.submit()).thenReturn(commitFuture);
+
+        NodeBuilder nodeBuilder = mock(NodeBuilder.class);
+        when(nodeBuilder.getKey()).thenReturn(mock(NodeKey.class));
+
+        FlowBuilder flowBuilder = mock(FlowBuilder.class);
+        when(flowBuilder.getKey()).thenReturn(mock(FlowKey.class));
+
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+        abstractServiceInstance.writeFlow(flowBuilder, nodeBuilder);
+
+        //verify(transaction, times(1)).put(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class), any(DataObject.class), eq(true));
+        //verify(transaction, times(1)).merge(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class), any(DataObject.class), eq(true));
+        //verify(commitFuture, times(1)).get();
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#removeFlow(FlowBuilder, NodeBuilder)}
+     */
+    @Test
+    public void testRemoveFlow() throws Exception {
+        WriteTransaction transaction = mock(WriteTransaction.class);
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(transaction);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = mock(CheckedFuture.class);
+        when(transaction.submit()).thenReturn(commitFuture);
+
+        NodeBuilder nodeBuilder = mock(NodeBuilder.class);
+        when(nodeBuilder.getKey()).thenReturn(mock(NodeKey.class));
+
+        FlowBuilder flowBuilder = mock(FlowBuilder.class);
+        when(flowBuilder.getKey()).thenReturn(mock(FlowKey.class));
+
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+        abstractServiceInstance.removeFlow(flowBuilder, nodeBuilder);
+        verify(transaction, times(1)).delete(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class));
+        verify(commitFuture, times(1)).get();
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#getFlow(FlowBuilder, NodeBuilder)}
+     */
+    @Test
+    public void testGetFlow() throws Exception {
+        ReadOnlyTransaction transaction = mock(ReadOnlyTransaction.class);
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(transaction);
+        //when(mdsalConsumer.getDataBroker()).thenReturn(dataBrocker);
+
+        NodeBuilder nodeBuilder = mock(NodeBuilder.class);
+        when(nodeBuilder.getKey()).thenReturn(mock(NodeKey.class));
+
+        FlowBuilder flowBuilder = mock(FlowBuilder.class);
+        when(flowBuilder.getKey()).thenReturn(mock(FlowKey.class));
+
+        CheckedFuture dataRead = mock(CheckedFuture.class);
+        when(transaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(dataRead);
+        Optional<Flow> data = mock(Optional.class);
+        when(dataRead.get()).thenReturn(data);
+
+        abstractServiceInstance.getFlow(flowBuilder, nodeBuilder);
+        verify(transaction, times(1)).read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class));
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance#programDefaultPipelineRule(Node)}
+     */
+    @Test
+    public void testProgramDefaultPipelineRule() {
+        when(southbound.getBridgeName(any(Node.class))).thenReturn(Constants.INTEGRATION_BRIDGE);
+        when(southbound.getDataPathId(any(Node.class))).thenReturn(261L);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        abstractServiceInstance.setService(service);
+
+        WriteTransaction transaction = mock(WriteTransaction.class);
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(transaction);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = mock(CheckedFuture.class);
+        when(transaction.submit()).thenReturn(commitFuture);
+
+        NodeBuilder nodeBuilder = mock(NodeBuilder.class);
+        when(nodeBuilder.getKey()).thenReturn(mock(NodeKey.class));
+
+        FlowBuilder flowBuilder = mock(FlowBuilder.class);
+        when(flowBuilder.getKey()).thenReturn(mock(FlowKey.class));
+
+        abstractServiceInstance.programDefaultPipelineRule(mock(Node.class));
+
+        verify(abstractServiceInstance, times(1)).isBridgeInPipeline(any(Node.class));
+        verify(abstractServiceInstance, times(1)).createNodeBuilder(anyString());
+        verify(abstractServiceInstance, times(1)).writeFlow(any(FlowBuilder.class), any(NodeBuilder.class));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        PipelineOrchestrator pipelineOrchestrator = mock(PipelineOrchestrator.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(PipelineOrchestrator.class, pipelineOrchestrator);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        abstractServiceInstance.setDependencies(mock(ServiceReference.class), mock(AbstractServiceInstance.class));
+
+        assertEquals("Error, did not return the correct object", getField("orchestrator"), pipelineOrchestrator);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = AbstractServiceInstance.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(abstractServiceInstance);
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13ProviderTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13ProviderTest.java
new file mode 100644 (file)
index 0000000..d2f31f7
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe Technologies.  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.openstack.netvirt.providers.openflow13;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyShort;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.ClassifierProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.MdsalHelper;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+/**
+ * Unit test for {@link OF13Provider}
+ */
+@PrepareForTest({OF13Provider.class, InetAddress.class, MdsalHelper.class, ServiceHelper.class})
+@RunWith(PowerMockRunner.class)
+public class OF13ProviderTest {
+
+    @Mock private OF13Provider of13Provider;
+
+    private static final String TYPE = "gre";
+    private static final String IP = "127.0.0.1";
+    private static final String BR_INT = "br-int";
+    private static final String ID = "4";
+    private static final String PORT = "port-int";
+    private static final String SEG_ID = "5";
+    private static final String MAC_ADDRESS = "mac-address";
+    private static final long LOCAL_PORT = 3;
+
+    @Before
+    public void setUp() throws Exception{
+        of13Provider = PowerMockito.mock(OF13Provider.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @Test
+    public void testGetName() {
+        assertEquals("Error, did not return the correct name",  OF13Provider.NAME, of13Provider.getName());
+    }
+
+    @Test
+    public void testSupportsServices() {
+        assertTrue("Error, did not return the correct boolean", of13Provider.supportsServices());
+    }
+
+    @Test
+    public void testHasPerTenantTunneling() {
+        assertFalse("Error, did not return the correct boolean", of13Provider.hasPerTenantTunneling());
+    }
+
+    @Test
+    public void testGetTunnelReadinessStatus() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        BridgeConfigurationManager bridgeConfigurationManager = mock(BridgeConfigurationManager.class);
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+
+        MemberModifier.field(OF13Provider.class, "configurationService").set(of13Provider , configurationService);
+        MemberModifier.field(OF13Provider.class, "bridgeConfigurationManager").set(of13Provider , bridgeConfigurationManager);
+        MemberModifier.field(OF13Provider.class, "tenantNetworkManager").set(of13Provider , tenantNetworkManager);
+
+        assertEquals("Error, did not return the correct status code", new Status(StatusCode.NOTFOUND), Whitebox.invokeMethod(of13Provider, "getTunnelReadinessStatus", mock(Node.class), ""));
+
+        when(configurationService.getTunnelEndPoint(any(Node.class))).thenReturn(mock(InetAddress.class));
+        when(bridgeConfigurationManager.isNodeNeutronReady(any(Node.class))).thenReturn(false, true);
+
+        assertEquals("Error, did not return the correct status code", new Status(StatusCode.NOTACCEPTABLE), Whitebox.invokeMethod(of13Provider, "getTunnelReadinessStatus", mock(Node.class), ""));
+
+        when(tenantNetworkManager.isTenantNetworkPresentInNode(any(Node.class), anyString())).thenReturn(false, true);
+
+        assertEquals("Error, did not return the correct status code", new Status(StatusCode.NOTACCEPTABLE), Whitebox.invokeMethod(of13Provider, "getTunnelReadinessStatus", mock(Node.class), ""));
+        assertEquals("Error, did not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(of13Provider, "getTunnelReadinessStatus", mock(Node.class), ""));
+    }
+
+    @Test
+    public void testGetTunnelName() throws Exception {
+        PowerMockito.mockStatic(InetAddress.class);
+        InetAddress inetAddress = mock(InetAddress.class);
+        PowerMockito.when(inetAddress.getHostAddress()).thenReturn(IP);
+
+        String ret = TYPE + "-" + inetAddress.getHostAddress();
+        assertEquals("Error, did not return the correct status code", ret, Whitebox.invokeMethod(of13Provider, "getTunnelName", TYPE, inetAddress));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testAddTunnelPort() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.extractTerminationPointAugmentation(any(Node.class), anyString())).thenReturn(mock(OvsdbTerminationPointAugmentation.class));
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "getTunnelName", String.class, InetAddress.class));
+
+        MemberModifier.field(OF13Provider.class, "configurationService").set(of13Provider , configurationService);
+        MemberModifier.field(OF13Provider.class, "southbound").set(of13Provider , southbound);
+
+        assertTrue("Error, did not add the port", (boolean) Whitebox.invokeMethod(of13Provider, "addTunnelPort", node, TYPE, mock(InetAddress.class), mock(InetAddress.class)));
+
+        when(southbound.extractTerminationPointAugmentation(any(Node.class), anyString())).thenReturn(null);
+        when(southbound.addTunnelTerminationPoint(any(Node.class), anyString(), anyString(), anyString(), any(HashMap.class))).thenReturn(false);
+
+        assertFalse("Error, did add the port", (boolean) Whitebox.invokeMethod(of13Provider, "addTunnelPort", node, TYPE, mock(InetAddress.class), mock(InetAddress.class)));
+
+        when(southbound.addTunnelTerminationPoint(any(Node.class), anyString(), anyString(), anyString(), any(HashMap.class))).thenReturn(true);
+
+        assertTrue("Error, did not add the port", (boolean) Whitebox.invokeMethod(of13Provider, "addTunnelPort", node, TYPE, mock(InetAddress.class), mock(InetAddress.class)));
+        PowerMockito.verifyPrivate(of13Provider, times(3)).invoke("getTunnelName", anyString(), any(InetAddress.class));
+    }
+
+    @Test
+    public void testDeletePort() throws Exception {
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.deleteTerminationPoint(any(Node.class), anyString())).thenReturn(false, true);
+        MemberModifier.field(OF13Provider.class, "southbound").set(of13Provider , southbound);
+
+        assertFalse("Error, did delete the port", (boolean) Whitebox.invokeMethod(of13Provider, "deletePort", mock(Node.class), TYPE, PORT));
+        assertTrue("Error, did not delete the port", (boolean) Whitebox.invokeMethod(of13Provider, "deletePort", mock(Node.class), TYPE, PORT));
+    }
+
+    @Test
+    public void testDeleteTunnelPort() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+
+        MemberModifier.field(OF13Provider.class, "configurationService").set(of13Provider , configurationService);
+
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "getTunnelName", String.class, InetAddress.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "deletePort", Node.class, String.class, String.class));
+
+        PowerMockito.when(of13Provider, "deletePort", any(Node.class), anyString(), anyString()).thenReturn(true);
+
+        assertTrue("Error, did not delete the tunnel", (boolean) Whitebox.invokeMethod(of13Provider, "deleteTunnelPort", mock(Node.class), TYPE, mock(InetAddress.class), mock(InetAddress.class)));
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("getTunnelName", anyString(), any(InetAddress.class));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("deletePort", any(Node.class), anyString(), anyString());
+
+        PowerMockito.when(of13Provider, "deletePort", any(Node.class), anyString(), anyString()).thenReturn(false);
+
+        assertFalse("Error, did delete the tunnel", (boolean) Whitebox.invokeMethod(of13Provider, "deleteTunnelPort", mock(Node.class), TYPE, mock(InetAddress.class), mock(InetAddress.class)));
+
+        PowerMockito.verifyPrivate(of13Provider, times(2)).invoke("getTunnelName", anyString(), any(InetAddress.class));
+        PowerMockito.verifyPrivate(of13Provider, times(2)).invoke("deletePort", any(Node.class), anyString(), anyString());
+    }
+
+    @Test
+    public void testProgramLocalBridgeRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalInPort", Long.class, Short.class, Short.class, String.class, Long.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleDropSrcIface", Long.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalUcastOut", Long.class, Short.class, String.class, Long.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalBcastOut", Long.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelFloodOut", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelMiss", Long.class, Short.class, Short.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalTableMiss", Long.class, Short.class, String.class, boolean.class));
+
+
+        Whitebox.invokeMethod(of13Provider, "programLocalBridgeRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalInPort", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleDropSrcIface", anyLong(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalUcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalBcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelFloodOut", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelMiss", anyLong(), anyShort(), anyShort(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalTableMiss", anyLong(), anyShort(), anyString(), anyBoolean());
+    }
+
+    @Test
+    public void testRemoveLocalBridgeRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalInPort", Long.class, Short.class, Short.class, String.class, Long.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleDropSrcIface", Long.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalUcastOut", Long.class, Short.class, String.class, Long.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalBcastOut", Long.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelFloodOut", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+
+
+        Whitebox.invokeMethod(of13Provider, "removeLocalBridgeRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalInPort", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleDropSrcIface", anyLong(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalUcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalBcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelFloodOut", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+    }
+
+    @Test
+    public void testProgramLocalIngressTunnelBridgeRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelIn", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelFloodOut", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+
+
+        Whitebox.invokeMethod(of13Provider, "programLocalIngressTunnelBridgeRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelIn", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelFloodOut", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+    }
+
+    @Test
+    public void testProgramRemoteEgressTunnelBridgeRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelOut", Long.class, Short.class, Short.class, String.class, Long.class, String.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "programRemoteEgressTunnelBridgeRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelOut", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+    }
+
+    @Test
+    public void testRemovePerTunnelRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelIn", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelFloodOut", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelMiss", Long.class, Short.class, Short.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalTableMiss", Long.class, Short.class, String.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "removePerTunnelRules", mock(Node.class), Long.valueOf("45"), SEG_ID, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelIn", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelFloodOut", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleTunnelMiss", anyLong(), anyShort(), anyShort(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalTableMiss", anyLong(), anyShort(), anyString(), anyBoolean());
+    }
+
+    @Test
+    public void testProgramLocalVlanRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalInPortSetVlan", Long.class, Short.class, Short.class, String.class, Long.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleDropSrcIface", Long.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalVlanUcastOut", Long.class, Short.class, String.class, Long.class, String.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "programLocalVlanRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalInPortSetVlan", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleDropSrcIface", anyLong(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalVlanUcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+    }
+
+    @Test
+    public void testRemoveLocalVlanRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalInPortSetVlan", Long.class, Short.class, Short.class, String.class, Long.class, String.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleDropSrcIface", Long.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalVlanUcastOut", Long.class, Short.class, String.class, Long.class, String.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "programLocalVlanRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalInPortSetVlan", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleDropSrcIface", anyLong(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalVlanUcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
+    }
+
+
+    @Test
+    public void testProgramLocalIngressVlanRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleVlanIn", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalVlanBcastOut", Long.class, Short.class, String.class, Long.class, Long.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "programLocalIngressVlanRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleVlanIn", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalVlanBcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyLong(), anyBoolean());
+    }
+
+    @Test
+    public void testProgramRemoteEgressVlanRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleVlanMiss", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "programRemoteEgressVlanRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleVlanMiss", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+    }
+
+    @Test
+    public void testRemoveRemoteEgressVlanRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleLocalVlanBcastOut", Long.class, Short.class, String.class, Long.class, Long.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "removeRemoteEgressVlanRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalVlanBcastOut", anyLong(), anyShort(), anyString(), anyLong(), anyLong(), anyBoolean());
+    }
+
+    @Test
+    public void testRemovePerVlanRules() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleVlanIn", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleVlanMiss", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
+
+        Whitebox.invokeMethod(of13Provider, "removePerVlanRules", mock(Node.class), Long.valueOf("45"), SEG_ID, LOCAL_PORT, LOCAL_PORT);
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleVlanIn", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleVlanMiss", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyBoolean());
+    }
+
+    @Test
+    public void testHandleInterfaceUpdate() throws Exception{
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getProviderNetworkType()).thenReturn(NetworkHandler.NETWORK_TYPE_VLAN, NetworkHandler.NETWORK_TYPE_GRE);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        Map<NodeId, Node> nodes = new HashMap<>();
+        nodes.put(mock(NodeId.class), mock(Node.class));
+        when(nodeCacheManager.getOvsdbNodes()).thenReturn(nodes);
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.extractBridgeOvsdbNodeId(any(Node.class))).thenReturn(mock(NodeId.class));
+        when(southbound.getBridgeNode(any(Node.class), anyString())).thenReturn(mock(Node.class));
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+
+        MemberModifier.field(OF13Provider.class, "nodeCacheManager").set(of13Provider , nodeCacheManager);
+        MemberModifier.field(OF13Provider.class, "southbound").set(of13Provider , southbound);
+        MemberModifier.field(OF13Provider.class, "configurationService").set(of13Provider , configurationService);
+
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "programLocalRules", String.class, String.class, Node.class, OvsdbTerminationPointAugmentation.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "programVlanRules", NeutronNetwork.class, Node.class, OvsdbTerminationPointAugmentation.class));
+
+        assertTrue("Error, did not update the interface correclty", of13Provider.handleInterfaceUpdate(neutronNetwork, mock(Node.class), mock(OvsdbTerminationPointAugmentation.class)));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("programLocalRules", anyString(), anyString(), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("programVlanRules", any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+
+        when(configurationService.getTunnelEndPoint(any(Node.class))).thenReturn(mock(InetAddress.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "addTunnelPort", Node.class, String.class, InetAddress.class, InetAddress.class));
+        PowerMockito.when(of13Provider, "addTunnelPort", any(Node.class), anyString(), any(InetAddress.class), any(InetAddress.class)).thenReturn(true);
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "programTunnelRules", String.class, String.class, InetAddress.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class));
+
+        assertTrue("Error, did not update the interface correclty", of13Provider.handleInterfaceUpdate(neutronNetwork, mock(Node.class), mock(OvsdbTerminationPointAugmentation.class)));
+        PowerMockito.verifyPrivate(of13Provider, times(2)).invoke("addTunnelPort", any(Node.class), anyString(), any(InetAddress.class), any(InetAddress.class));
+        PowerMockito.verifyPrivate(of13Provider, times(2)).invoke("programTunnelRules", anyString(), anyString(), any(InetAddress.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), anyBoolean());
+    }
+
+    private static final String INTF = "interface";
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testHandlerInterfaceDelete() throws Exception {
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+        Map<NodeId, Node> nodes = new HashMap<>();
+        nodes.put(mock(NodeId.class), node);
+        when(nodeCacheManager.getOvsdbNodes()).thenReturn(nodes);
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.extractBridgeOvsdbNodeId(any(Node.class))).thenReturn(mock(NodeId.class));
+        when(southbound.isTunnel(any(OvsdbTerminationPointAugmentation.class))).thenReturn(true);
+        when(southbound.getOptionsValue(any(List.class), anyString())).thenReturn(IP);
+        OvsdbTerminationPointAugmentation intf = mock(OvsdbTerminationPointAugmentation.class);
+        when(intf.getName()).thenReturn(INTF);
+        List<String> intfs = new ArrayList<>();
+        intfs.add(INTF);
+        BridgeConfigurationManager bridgeConfigurationManager = mock(BridgeConfigurationManager.class);
+        when(bridgeConfigurationManager.getAllPhysicalInterfaceNames(any(Node.class))).thenReturn(intfs);
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        when(configurationService.getTunnelEndPoint(any(Node.class))).thenReturn(mock(InetAddress.class));
+
+        PowerMockito.mockStatic(InetAddress.class);
+        PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(mock(InetAddress.class));
+
+        PowerMockito.mockStatic(MdsalHelper.class);
+        PowerMockito.when(MdsalHelper.createOvsdbInterfaceType(any(Class.class))).thenReturn(INTF);
+
+        MemberModifier.field(OF13Provider.class, "nodeCacheManager").set(of13Provider , nodeCacheManager);
+        MemberModifier.field(OF13Provider.class, "southbound").set(of13Provider , southbound);
+        MemberModifier.field(OF13Provider.class, "bridgeConfigurationManager").set(of13Provider , bridgeConfigurationManager);
+        MemberModifier.field(OF13Provider.class, "configurationService").set(of13Provider , configurationService);
+
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "deleteTunnelPort", Node.class, String.class, InetAddress.class, InetAddress.class));
+
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("deleteTunnelPort", any(Node.class), anyString(), any(InetAddress.class), any(InetAddress.class));
+
+        when(southbound.isTunnel(any(OvsdbTerminationPointAugmentation.class))).thenReturn(false);
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "deletePhysicalPort", Node.class, String.class));
+
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("deletePhysicalPort", any(Node.class), anyString());
+
+        intfs.clear();
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeLocalRules", String.class, String.class, Node.class, OvsdbTerminationPointAugmentation.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeVlanRules", NeutronNetwork.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class));
+        when(neutronNetwork.getProviderNetworkType()).thenReturn(NetworkHandler.NETWORK_TYPE_VLAN);
+
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("removeLocalRules",  anyString(), anyString(), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("removeVlanRules",  any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), anyBoolean());
+
+        when(neutronNetwork.getProviderNetworkType()).thenReturn(NetworkHandler.NETWORK_TYPE_GRE);
+        when(southbound.getBridgeNode(any(Node.class), anyString())).thenReturn(node);
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeTunnelRules", String.class, String.class, InetAddress.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class, boolean.class));
+
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, node, intf, false));
+        PowerMockito.verifyPrivate(of13Provider, times(2)).invoke("removeTunnelRules", anyString(), anyString(), any(InetAddress.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(boolean.class), any(boolean.class));
+    }
+
+    // Problem with methods signatures: initializeFlowRules(Node) has the same signature than initializeFlowRules(Node, String)
+//    @Test
+//    public void testInitializeFlowRules() throws Exception {
+//        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "initializeFlowRules", Node.class, String.class));
+//        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "triggerInterfaceUpdates", Node.class));
+//
+//        of13Provider.initializeFlowRules(mock(Node.class));
+//
+//        PowerMockito.verifyPrivate(of13Provider, times(2)).invoke("initializeFlowRules", any(Node.class), anyString());
+//        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("triggerInterfaceUpdates", any(Node.class));
+//    }
+
+    @Test
+    public void testInitializeOFFlowRule() throws Exception{
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.getBridgeName(any(Node.class))).thenReturn(BR_INT);
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+
+        MemberModifier.field(OF13Provider.class, "southbound").set(of13Provider , southbound);
+        MemberModifier.field(OF13Provider.class, "configurationService").set(of13Provider , configurationService);
+
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "initializeFlowRules", Node.class, String.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "triggerInterfaceUpdates", Node.class));
+
+        of13Provider.initializeOFFlowRules(mock(Node.class));
+
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("initializeFlowRules", any(Node.class), anyString());
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("triggerInterfaceUpdates", any(Node.class));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        BridgeConfigurationManager bridgeConfigurationManager = mock(BridgeConfigurationManager.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        ClassifierProvider classifierProvider = mock(ClassifierProvider.class);
+        IngressAclProvider ingressAclProvider = mock(IngressAclProvider.class);
+        EgressAclProvider egressAclProvider = mock(EgressAclProvider.class);
+        L2ForwardingProvider l2ForwardingProvider = mock(L2ForwardingProvider.class);
+        SecurityServicesManager securityServicesManager = mock(SecurityServicesManager.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(ConfigurationService.class, configurationService);
+        ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
+        ServiceHelper.overrideGlobalInstance(BridgeConfigurationManager.class, bridgeConfigurationManager);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+        ServiceHelper.overrideGlobalInstance(ClassifierProvider.class, classifierProvider);
+        ServiceHelper.overrideGlobalInstance(IngressAclProvider.class, ingressAclProvider);
+        ServiceHelper.overrideGlobalInstance(EgressAclProvider.class, egressAclProvider);
+        ServiceHelper.overrideGlobalInstance(L2ForwardingProvider.class, l2ForwardingProvider);
+        ServiceHelper.overrideGlobalInstance(SecurityServicesManager.class, securityServicesManager);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        of13Provider.setDependencies(mock(BundleContext.class), mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
+        assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
+        assertEquals("Error, did not return the correct object", getField("bridgeConfigurationManager"), bridgeConfigurationManager);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+        assertEquals("Error, did not return the correct object", getField("classifierProvider"), classifierProvider);
+        assertEquals("Error, did not return the correct object", getField("ingressAclProvider"), ingressAclProvider);
+        assertEquals("Error, did not return the correct object", getField("egressAclProvider"), egressAclProvider);
+        assertEquals("Error, did not return the correct object", getField("l2ForwardingProvider"), l2ForwardingProvider);
+        assertEquals("Error, did not return the correct object", getField("securityServicesManager"), securityServicesManager);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        NetworkingProviderManager networkingProviderManager = mock(NetworkingProviderManager.class);
+        BundleContext bundleContext = mock(BundleContext.class);
+        when(bundleContext.getServiceReference(NetworkingProvider.class.getName())).thenReturn(mock(ServiceReference.class));
+
+        MemberModifier.field(OF13Provider.class, "bundleContext").set(of13Provider, bundleContext);
+
+        of13Provider.setDependencies(networkingProviderManager);
+        verify(networkingProviderManager).providerAdded(any(ServiceReference.class), same(of13Provider));
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = OF13Provider.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(of13Provider);
+    }
+}
\ No newline at end of file
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorImplTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorImplTest.java
new file mode 100644 (file)
index 0000000..7fd1132
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe Technologies.  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.openstack.netvirt.providers.openflow13;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.ExecutorService;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link PipelineOrchestratorImplTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class PipelineOrchestratorImplTest {
+    @InjectMocks private PipelineOrchestratorImpl orchestrator;
+
+    @Mock private ExecutorService eventHandler;
+    @Mock private Southbound southbound;
+
+    /**
+     * Test for method {@link PipelineOrchestratorImpl#getTableOffset()}
+     */
+    @Test
+    public void testGetTableOffset() {
+        short tableOffset = 0;
+        assertEquals("tableOffset was not set", tableOffset, orchestrator.getTableOffset());
+    }
+
+    /**
+     * Test for {@link PipelineOrchestratorImpl#getTable(Service)}
+     */
+    @Test
+    public void testGetTableOffsetWithService() {
+        assertEquals("tableOffset was not set", Service.CLASSIFIER.getTable(),
+                orchestrator.getTable(Service.CLASSIFIER));
+    }
+
+    /***
+     * Registers a mock service and verifies the registration by asking the
+     * pipeline orchestrator to return the associated service from its internal
+     * registry
+     */
+    @Test
+    public void testRegisterAndUnregisterService() {
+        Service service = Service.CLASSIFIER;
+        ServiceReference<?> serviceReference = mock(ServiceReference.class);
+        when(serviceReference.getProperty(anyString())).thenReturn(service);
+
+        AbstractServiceInstance abstractServiceInstance = mock(AbstractServiceInstance.class);
+
+        orchestrator.registerService(serviceReference, abstractServiceInstance);
+        assertEquals("Error, registerService() service registration fails",
+                abstractServiceInstance,
+                orchestrator.getServiceInstance(service));
+
+        orchestrator.unregisterService(serviceReference);
+        assertNull("Error, unregisterService() didn't delete the service", orchestrator.getServiceInstance(service));
+    }
+
+    /**
+     * Test method
+     * {@link PipelineOrchestratorImpl#getNextServiceInPipeline(Service)}
+     */
+    @Test
+    public void testGetNextServiceInPipeline() {
+
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.CLASSIFIER),
+                Service.ARP_RESPONDER);
+        assertEquals(
+                orchestrator.getNextServiceInPipeline(Service.ARP_RESPONDER),
+                Service.INBOUND_NAT);
+        assertEquals(
+                orchestrator.getNextServiceInPipeline(Service.INBOUND_NAT),
+                Service.EGRESS_ACL);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.EGRESS_ACL),
+                Service.LOAD_BALANCER);
+        assertEquals(
+                orchestrator.getNextServiceInPipeline(Service.LOAD_BALANCER),
+                Service.ROUTING);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.ROUTING),
+                Service.L3_FORWARDING);
+        assertEquals(
+                orchestrator.getNextServiceInPipeline(Service.L3_FORWARDING),
+                Service.L2_REWRITE);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.L2_REWRITE),
+                Service.INGRESS_ACL);
+        assertEquals(
+                orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL),
+                Service.OUTBOUND_NAT);
+        assertEquals(
+                orchestrator.getNextServiceInPipeline(Service.OUTBOUND_NAT),
+                Service.L2_FORWARDING);
+        assertNull(orchestrator.getNextServiceInPipeline(Service.L2_FORWARDING));
+    }
+
+  @Test
+  public void testSetDependencies() throws Exception {
+      NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+      Southbound southbound = mock(Southbound.class);
+
+      ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+      ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+      orchestrator.setDependencies(mock(BundleContext.class), mock(ServiceReference.class));
+
+//      assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+      assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+  }
+
+  private Object getField(String fieldName) throws Exception {
+      Field field = PipelineOrchestratorImpl.class.getDeclaredField(fieldName);
+      field.setAccessible(true);
+      return field.get(orchestrator);
+  }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/PipelineOrchestratorTest.java
new file mode 100644 (file)
index 0000000..986bec1
--- /dev/null
@@ -0,0 +1,30 @@
+package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class PipelineOrchestratorTest {
+    PipelineOrchestrator orchestrator;
+    @Before
+    public void initialize() {
+        orchestrator = new PipelineOrchestratorImpl();
+    }
+
+    @Test
+    public void testPipeline() {
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.CLASSIFIER), Service.ARP_RESPONDER);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.ARP_RESPONDER), Service.INBOUND_NAT);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.INBOUND_NAT), Service.EGRESS_ACL);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.EGRESS_ACL), Service.LOAD_BALANCER);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.LOAD_BALANCER), Service.ROUTING);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.ROUTING), Service.L3_FORWARDING);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.L3_FORWARDING), Service.L2_REWRITE);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.L2_REWRITE), Service.INGRESS_ACL);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL), Service.OUTBOUND_NAT);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.OUTBOUND_NAT), Service.L2_FORWARDING);
+        assertNull(orchestrator.getNextServiceInPipeline(Service.L2_FORWARDING));
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ArpResponderServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ArpResponderServiceTest.java
new file mode 100644 (file)
index 0000000..64a11c4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+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.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+
+/**
+ * Unit test for {@link ArpResponderService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class ArpResponderServiceTest {
+
+    @InjectMocks private ArpResponderService arpResponderService = new ArpResponderService();
+
+    @Mock private DataBroker dataBroker;
+
+    private static final String HOST_ADDRESS = "121.0.0.1";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+
+    @Test
+    public void testProgramStaticArpEntry() throws Exception {
+        arpResponderService.setService(Service.ARP_RESPONDER);
+
+        InetAddress ipAddress = mock(InetAddress.class);
+        when(ipAddress.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        WriteTransaction transaction = mock(WriteTransaction.class);
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(transaction);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = mock(CheckedFuture.class);
+        when(transaction.submit()).thenReturn(commitFuture);
+
+        NodeBuilder nodeBuilder = mock(NodeBuilder.class);
+        when(nodeBuilder.getKey()).thenReturn(mock(NodeKey.class));
+
+        FlowBuilder flowBuilder = mock(FlowBuilder.class);
+        when(flowBuilder.getKey()).thenReturn(mock(FlowKey.class));
+
+        // test Action.ADD
+        assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), arpResponderService.programStaticArpEntry(Long.valueOf(12), "2", MAC_ADDRESS, ipAddress, Action.ADD));
+
+        verify(transaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(transaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // test Action.DELETE
+        assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), arpResponderService.programStaticArpEntry(Long.valueOf(12), "2", MAC_ADDRESS, ipAddress, Action.DELETE));
+
+        verify(transaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ClassifierServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/ClassifierServiceTest.java
new file mode 100644 (file)
index 0000000..2159b4c
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test for {@link ClassifierService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class ClassifierServiceTest {
+
+    @InjectMocks private ClassifierService classifierService = new ClassifierService(Service.ARP_RESPONDER);
+
+    @Mock private DataBroker dataBroker;
+
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    @Before
+    public void setUp() {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+    }
+
+    /**
+     * Test method {@link ClassifierService#programLocalInPort(Long, String, Long, String, boolean)}
+     */
+    @Test
+    public void testProgramLocalInPort() throws Exception {
+        // write
+        classifierService.programLocalInPort(Long.valueOf(1212), "2", Long.valueOf(455), MAC_ADDRESS, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // remove
+        classifierService.programLocalInPort(Long.valueOf(1212), "2", Long.valueOf(455), MAC_ADDRESS, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link ClassifierService#programLocalInPortSetVlan(Long, String, Long, String, boolean)}
+     */
+    @Test
+    public void testProgramLocalInPortSetVlan() throws Exception {
+        // write
+        classifierService.programLocalInPortSetVlan(Long.valueOf(1212), "2", Long.valueOf(455), MAC_ADDRESS, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // remove
+        classifierService.programLocalInPortSetVlan(Long.valueOf(1212), "2", Long.valueOf(455), MAC_ADDRESS, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link ClassifierService#programDropSrcIface(Long, Long, boolean)}
+     */
+    @Test
+    public void testProgramDropSrcIface() throws Exception {
+        // write
+        classifierService.programDropSrcIface(Long.valueOf(1212), Long.valueOf(455), true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // remove
+        classifierService.programDropSrcIface(Long.valueOf(1212), Long.valueOf(455), false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link ClassifierService#programTunnelIn(Long, String, Long, boolean)}
+     */
+    @Test
+    public void testProgramTunnelIn() throws Exception {
+        // write
+        classifierService.programTunnelIn(Long.valueOf(1212), "2", Long.valueOf(455), true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // remove
+        classifierService.programTunnelIn(Long.valueOf(1212), "2", Long.valueOf(455), false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link ClassifierService#programVlanIn(Long, String, Long, boolean)}
+     */
+    @Test
+    public void testProgramVlanIn() throws Exception {
+        // write
+        classifierService.programVlanIn(Long.valueOf(1212), "2", Long.valueOf(455), true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // remove
+        classifierService.programVlanIn(Long.valueOf(1212), "2", Long.valueOf(455), false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link ClassifierService#programLLDPPuntRule(Long)}
+     */
+    @Test
+    public void testProgramLLDPPuntRule() throws Exception {
+        // write
+        classifierService.programLLDPPuntRule(Long.valueOf(1212));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclServiceTest.java
new file mode 100644 (file)
index 0000000..3bbd1d8
--- /dev/null
@@ -0,0 +1,1564 @@
+/*
+ * Copyright (c) 2015 - 2016 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv6Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.util.concurrent.CheckedFuture;
+/**
+ * Unit test for {@link EgressAclService}
+ */
+@RunWith(PowerMockRunner.class)
+@SuppressWarnings("unchecked")
+public class EgressAclServiceTest {
+
+    @InjectMocks private EgressAclService egressAclService = new EgressAclService();
+    private EgressAclService egressAclServiceSpy;
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    @Mock private NeutronSecurityGroup securityGroup;
+    @Mock private NeutronSecurityRule portSecurityRule;
+    @Mock private NeutronSecurityGroup securityGroupIpv6;
+    @Mock private NeutronSecurityRule portSecurityIpv6Rule;
+
+    @Mock private SecurityServicesManager securityServices;
+    @Mock private SecurityGroupCacheManger securityGroupCacheManger;
+
+    private Neutron_IPs neutron_ip_src;
+    private Neutron_IPs neutron_ip_dest_1;
+    private Neutron_IPs neutron_ip_dest_2;
+    private Neutron_IPs neutron_ipv6_dest_1;
+    private Neutron_IPs neutron_ipv6_dest_2;
+    private List<Neutron_IPs> neutronSrcIpList = new ArrayList<>();
+    private List<Neutron_IPs> neutronDestIpList = new ArrayList<>();
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+    private static final String SRC_IP = "192.168.0.1";
+    private static final String DEST_IP_1 = "192.169.0.1";
+    private static final String DEST_IP_2 = "192.169.0.2";
+    private static final String IPV6_DEST_IP_1 = "2001:db8:2::200";
+    private static final String IPV6_DEST_IP_2 = "2001:db8:2::201";
+    private static final String SECURITY_GROUP_UUID = "85cc3048-abc3-43cc-89b3-377341426ac5";
+    private static final String PORT_UUID = "95cc3048-abc3-43cc-89b3-377341426ac5";
+    private static final Long IPV6_ETHER_TYPE = (long) 0x86DD;
+    private static final Long IPV4_ETHER_TYPE = (long) 0x0800;
+    private static final String SEGMENT_ID = "2";
+    private static final Long DP_ID_LONG = (long) 1554;
+    private static final Long LOCAL_PORT = (long) 124;
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
+    private static FlowBuilder flowBuilder;
+    private static NodeBuilder nodeBuilder;
+
+    private static Answer<Object> answer() {
+        return new Answer<Object>() {
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> answer(InvocationOnMock invocation)
+                    throws Throwable {
+                flowBuilder = (FlowBuilder) invocation.getArguments()[0];
+                nodeBuilder = (NodeBuilder) invocation.getArguments()[1];
+                return null;
+            }
+        };
+    }
+
+    @Before
+    public void setUp() throws IllegalArgumentException, IllegalAccessException {
+        egressAclServiceSpy = PowerMockito.spy(egressAclService);
+
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        portSecurityRule = mock(NeutronSecurityRule.class);
+        portSecurityIpv6Rule = mock(NeutronSecurityRule.class);
+
+        when(portSecurityRule.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(portSecurityRule.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_EGRESS);
+        when(portSecurityIpv6Rule.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV6);
+        when(portSecurityIpv6Rule.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_EGRESS);
+
+        List<NeutronSecurityRule> portSecurityList = new ArrayList<>();
+        portSecurityList.add(portSecurityRule);
+
+        neutron_ip_src = new Neutron_IPs();
+        neutron_ip_src.setIpAddress(SRC_IP);
+        neutronSrcIpList.add(neutron_ip_src);
+
+        neutron_ip_dest_1 = new Neutron_IPs();
+        neutron_ip_dest_1.setIpAddress(DEST_IP_1);
+        neutronDestIpList.add(neutron_ip_dest_1);
+
+        neutron_ip_dest_2 = new Neutron_IPs();
+        neutron_ip_dest_2.setIpAddress(DEST_IP_2);
+        neutronDestIpList.add(neutron_ip_dest_2);
+
+        List<NeutronSecurityRule> portSecurityIpv6List = new ArrayList<>();
+        portSecurityIpv6List.add(portSecurityIpv6Rule);
+        when(securityGroupIpv6.getSecurityRules()).thenReturn(portSecurityIpv6List);
+
+        neutron_ipv6_dest_1 = new Neutron_IPs();
+        neutron_ipv6_dest_1.setIpAddress(IPV6_DEST_IP_1);
+        neutronDestIpList.add(neutron_ipv6_dest_1);
+
+        neutron_ipv6_dest_2 = new Neutron_IPs();
+        neutron_ipv6_dest_2.setIpAddress(IPV6_DEST_IP_2);
+        neutronDestIpList.add(neutron_ipv6_dest_2);
+
+        when(securityGroup.getSecurityRules()).thenReturn(portSecurityList);
+        when(securityServices.getVmListForSecurityGroup(PORT_UUID, SECURITY_GROUP_UUID)).thenReturn(neutronDestIpList);
+
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+    }
+
+    /**
+     * Test method {@link EgressAclService#programPortSecurityGroup(java.lang.Long, java.lang.String,
+     * java.lang.String, long, NeutronSecurityGroup,
+     * java.lang.String, boolean)} when portSecurityRule is incomplete
+     */
+    @Test
+    public void testProgramPortSecurityGroupWithIncompleteRule() throws Exception {
+        NeutronSecurityRule portSecurityRule1 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(portSecurityRule1.getSecurityRuleDirection()).thenReturn("not_egress");  // other direction
+
+        NeutronSecurityRule portSecurityRule2 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule2.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule2.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_EGRESS);
+
+        NeutronSecurityRule portSecurityRule3 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule3.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(portSecurityRule3.getSecurityRuleDirection()).thenReturn(null);
+
+        NeutronSecurityRule portSecurityRule4 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule4.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule4.getSecurityRuleDirection()).thenReturn(null);
+
+        List<NeutronSecurityRule> portSecurityList = new ArrayList<>();
+        portSecurityList.add(null);
+        portSecurityList.add(portSecurityRule1);
+        portSecurityList.add(portSecurityRule2);
+        portSecurityList.add(portSecurityRule3);
+        portSecurityList.add(portSecurityRule4);
+
+        NeutronSecurityGroup localSecurityGroup = mock(NeutronSecurityGroup.class);
+        when(localSecurityGroup.getSecurityRules()).thenReturn(portSecurityList);
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT,
+                localSecurityGroup, PORT_UUID, true);
+    }
+
+    /**
+     *  Test IPv4 add test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIpv4() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        egressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,true);
+
+        verify(writeTransaction, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).checkedGet();
+    }
+
+    /**
+     *  Test IPv6 add test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIpv6() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        egressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroupIpv6, PORT_UUID, true);
+
+        verify(writeTransaction, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).checkedGet();
+    }
+
+    /**
+     *  Test IPv4 remove test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIpv4() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        egressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+    }
+
+    /**
+     *  Test IPv6 remove test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIpv6() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        egressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroupIpv6, PORT_UUID, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+    }
+
+    /**
+     *  Test IPv4 TCP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port=portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port=portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(30);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(30, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port=portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(30);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(30, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port=portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(40);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        int port=portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(40);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        int port=portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        int port=portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        int port=portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 TCP add with port range (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+    }
+
+    /**
+     *  Test IPv6 TCP add with port range (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port range (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port range (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP add with port range (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP add with port range (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port range (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port range (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP add with port (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP add with port (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP remove with port (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP remove with port (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP add with port (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP add with port (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP remove with port (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP remove with port (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMP add with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIcmp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(10);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(10);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(10, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(10, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + type + "_" + code + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMPv6 add with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddIcmp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(10);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(10);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(10, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(10, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + type + "_" + code + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMP remove with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIcmp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(20, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(20, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + type + "_" + code + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMPv6 remove with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveIcmp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(20, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(20, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + type + "_" + code + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMP add with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIcmp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(30);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(30, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(30, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                                + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                                + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMPv6 add with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddIcmp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(30);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(30, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(30, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMP remove with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIcmp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(40);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                     PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(40, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(40, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                                + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                                + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMPv6 remove with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveIcmp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(40);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(40, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(40, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 invalid ether type test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleInvalidEther() throws Exception {
+        when(portSecurityRule.getSecurityRuleEthertype()).thenReturn("IP");
+
+        egressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,false);
+
+        verify(writeTransaction, times(0)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(0)).submit();
+        verify(commitFuture, times(0)).get();
+    }
+
+    /**
+     *  Test IPv4 invalid direction type test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleInvalidDirection() throws Exception {
+        when(portSecurityRule.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+
+        egressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,false);
+
+        verify(writeTransaction, times(0)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(0)).submit();
+        verify(commitFuture, times(0)).get();
+    }
+
+    /**
+      *  Test With isConntrackEnabled false
+     */
+    @Test
+    public void testProgramFixedSecurityACLAdd2() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(false);
+
+        egressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, neutronDestIpList, true);
+
+        verify(writeTransaction, times(9)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(9)).submit();
+        verify(commitFuture, times(9)).checkedGet();
+    }
+
+    /**
+     *  Test With isConntrackEnabled false
+     */
+    @Test
+    public void testProgramFixedSecurityACLRemove2() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(false);
+
+        egressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, neutronDestIpList, false);
+
+        verify(writeTransaction, times(9)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(9)).submit();
+        verify(commitFuture, times(9)).get();
+    }
+
+    /**
+     *  Test With isConntrackEnabled true
+     */
+    @Test
+    public void testProgramFixedSecurityACLAdd4() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(true);
+
+        egressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, neutronDestIpList, true);
+
+        verify(writeTransaction, times(14)).put(any(LogicalDatastoreType.class),
+                                               any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(14)).submit();
+        verify(commitFuture, times(14)).checkedGet();
+    }
+
+    /**
+     *  Test With isConntrackEnabled true
+     */
+    @Test
+    public void testProgramFixedSecurityACLRemove4() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(true);
+
+        egressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, neutronDestIpList, false);
+
+        verify(writeTransaction, times(14)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(14)).submit();
+        verify(commitFuture, times(14)).get();
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IcmpEchoResponderServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IcmpEchoResponderServiceTest.java
new file mode 100644 (file)
index 0000000..7bda7da
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 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.openstack.netvirt.providers.openflow13.services;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+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.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+import java.net.InetAddress;
+
+/**
+ * Unit test for {@link IcmpEchoResponderService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class IcmpEchoResponderServiceTest {
+    @InjectMocks private IcmpEchoResponderService icmpEchoResponderService = new IcmpEchoResponderService();
+
+    @Mock
+    private DataBroker dataBroker;
+
+    private static final String HOST_ADDRESS = "121.0.0.1";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+
+    @Test
+    public void testProgramIcmpEchoEntry() throws Exception {
+        icmpEchoResponderService.setService(Service.ARP_RESPONDER);
+
+        InetAddress ipAddress = mock(InetAddress.class);
+        when(ipAddress.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        WriteTransaction transaction = mock(WriteTransaction.class);
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(transaction);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = mock(CheckedFuture.class);
+        when(transaction.submit()).thenReturn(commitFuture);
+
+        NodeBuilder nodeBuilder = mock(NodeBuilder.class);
+        when(nodeBuilder.getKey()).thenReturn(mock(NodeKey.class));
+
+        FlowBuilder flowBuilder = mock(FlowBuilder.class);
+        when(flowBuilder.getKey()).thenReturn(mock(FlowKey.class));
+
+        // test Action.ADD
+        assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), icmpEchoResponderService.programIcmpEchoEntry(Long.valueOf(12), "2", MAC_ADDRESS, ipAddress, Action.ADD));
+
+        verify(transaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(transaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        // test Action.DELETE
+        assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), icmpEchoResponderService.programIcmpEchoEntry(Long.valueOf(12), "2", MAC_ADDRESS, ipAddress, Action.DELETE));
+
+        verify(transaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/InboundNatServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/InboundNatServiceTest.java
new file mode 100644 (file)
index 0000000..18eaf70
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.support.membermodification.MemberModifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test for {@link InboundNatService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class InboundNatServiceTest {
+
+    @InjectMocks private InboundNatService inboundNatService = new InboundNatService(Service.ARP_RESPONDER);
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    private static final String HOST_ADDRESS = "127.0.0.1";
+    private static final String HOST_ADDRESS_PREFIX = "127.0.0.1/32";
+
+    @Before
+    public void setUp() throws IllegalArgumentException, IllegalAccessException {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+    }
+
+    /**
+     * Test method {@link InboundNatService#programIpRewriteRule(Long, Long, InetAddress, InetAddress, Action)}
+     */
+    @Test
+    public void testProgramIpRewriteRule() throws Exception {
+        InetAddress rewriteAddress = mock(InetAddress.class);
+        when(rewriteAddress.getHostAddress()).thenReturn(HOST_ADDRESS);
+        InetAddress matchAddress = mock(InetAddress.class);
+        when(matchAddress.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                inboundNatService.programIpRewriteRule(Long.valueOf(123), Long.valueOf(2), "2",  // FIXME: describe params
+                        matchAddress, rewriteAddress, Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                inboundNatService.programIpRewriteRule(Long.valueOf(123), Long.valueOf(2), "2",  // FIXME: describe params
+                        matchAddress, rewriteAddress, Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link InboundNatService#programIpRewriteExclusion(Long, String, String, Action)}
+     */
+    @Test
+    public void testProgramIpRewriteExclusion() throws Exception {
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                inboundNatService.programIpRewriteExclusion(Long.valueOf(123), "2", HOST_ADDRESS_PREFIX, Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class),
+                any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                inboundNatService.programIpRewriteExclusion(Long.valueOf(123), "2",
+                        HOST_ADDRESS_PREFIX, Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclServiceTest.java
new file mode 100644 (file)
index 0000000..e5d3b06
--- /dev/null
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (c) 2015 - 2016 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv6Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test fort {@link IngressAclService}
+ */
+@RunWith(PowerMockRunner.class)
+@SuppressWarnings("unchecked")
+public class IngressAclServiceTest {
+
+    @InjectMocks private IngressAclService ingressAclService = new IngressAclService();
+    private IngressAclService ingressAclServiceSpy;
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    @Mock private NeutronSecurityGroup securityGroup;
+    @Mock private NeutronSecurityRule portSecurityRule;
+    @Mock private NeutronSecurityGroup securityGroupIpv6;
+    @Mock private NeutronSecurityRule portSecurityIpv6Rule;
+    @Mock private SecurityServicesManager securityServices;
+    @Mock private SecurityGroupCacheManger securityGroupCacheManger;
+
+    private List<Neutron_IPs> neutronSrcIpList = new ArrayList<>();
+    private List<Neutron_IPs> neutronDestIpList = new ArrayList<>();
+    private Neutron_IPs neutron_ip_src;
+    private Neutron_IPs neutron_ip_dest_1;
+    private Neutron_IPs neutron_ip_dest_2;
+    private Neutron_IPs neutron_ipv6_dest_1;
+    private Neutron_IPs neutron_ipv6_dest_2;
+
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B8";
+    private static final String DHCP_MAC_ADDRESS = "87:1D:5E:02:40:B9";
+    private static final String SRC_IP = "192.168.0.1";
+    private static final String DEST_IP_1 = "192.169.0.1";
+    private static final String DEST_IP_2 = "192.169.0.2";
+    private static final String IPV6_DEST_IP_1 = "2001:db8:2::200";
+    private static final String IPV6_DEST_IP_2 = "2001:db8:2::201";
+    private static final Long IPV6_ETHER_TYPE = (long) 0x86DD;
+    private static final Long IPV4_ETHER_TYPE = (long) 0x0800;
+    private static final String SECURITY_GROUP_UUID = "85cc3048-abc3-43cc-89b3-377341426ac5";
+    private static final String PORT_UUID = "95cc3048-abc3-43cc-89b3-377341426ac5";
+    private static final String SEGMENT_ID = "2";
+    private static final Long DP_ID_LONG = (long) 1554;
+    private static final Long LOCAL_PORT = (long) 124;
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
+    private static FlowBuilder flowBuilder;
+    private static NodeBuilder nodeBuilder;
+
+    private static Answer<Object> answer() {
+        return new Answer<Object>() {
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> answer(InvocationOnMock invocation)
+                    throws Throwable {
+                flowBuilder = (FlowBuilder) invocation.getArguments()[0];
+                nodeBuilder = (NodeBuilder) invocation.getArguments()[1];
+                return null;
+            }
+        };
+    }
+
+    @Before
+    public void setUp() throws IllegalArgumentException, IllegalAccessException{
+        ingressAclServiceSpy = PowerMockito.spy(ingressAclService);
+
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        portSecurityRule = mock(NeutronSecurityRule.class);
+        when(portSecurityRule.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(portSecurityRule.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+
+        List<NeutronSecurityRule> portSecurityList = new ArrayList<>();
+        portSecurityList.add(portSecurityRule);
+
+        neutron_ip_src = new Neutron_IPs();
+        neutron_ip_src.setIpAddress(SRC_IP);
+        neutronSrcIpList.add(neutron_ip_src);
+
+        neutron_ip_dest_1 = new Neutron_IPs();
+        neutron_ip_dest_1.setIpAddress(DEST_IP_1);
+        neutronDestIpList.add(neutron_ip_dest_1);
+
+        neutron_ip_dest_2 = new Neutron_IPs();
+        neutron_ip_dest_2.setIpAddress(DEST_IP_2);
+        neutronDestIpList.add(neutron_ip_dest_2);
+
+        portSecurityIpv6Rule = mock(NeutronSecurityRule.class);
+        when(portSecurityIpv6Rule.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV6);
+        when(portSecurityIpv6Rule.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+
+        List<NeutronSecurityRule> portSecurityIpv6List = new ArrayList<>();
+        portSecurityIpv6List.add(portSecurityIpv6Rule);
+        when(securityGroupIpv6.getSecurityRules()).thenReturn(portSecurityIpv6List);
+
+        neutron_ipv6_dest_1 = new Neutron_IPs();
+        neutron_ipv6_dest_1.setIpAddress(IPV6_DEST_IP_1);
+        neutronDestIpList.add(neutron_ipv6_dest_1);
+
+        neutron_ipv6_dest_2 = new Neutron_IPs();
+        neutron_ipv6_dest_2.setIpAddress(IPV6_DEST_IP_2);
+        neutronDestIpList.add(neutron_ipv6_dest_2);
+
+        when(securityGroup.getSecurityRules()).thenReturn(portSecurityList);
+        when(securityServices.getVmListForSecurityGroup
+             (PORT_UUID, SECURITY_GROUP_UUID)).thenReturn(neutronDestIpList);
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+    }
+    /**
+     * Test method {@link EgressAclService#programPortSecurityGroup(java.lang.Long, java.lang.String,
+     * java.lang.String, long, NeutronSecurityGroup,
+     * java.lang.String, boolean)} when portSecurityRule is incomplete
+     */
+    @Test
+    public void testProgramPortSecurityGroupWithIncompleteRule() throws Exception {
+        NeutronSecurityRule portSecurityRule1 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(portSecurityRule1.getSecurityRuleDirection()).thenReturn("not_ingress");  // other direction
+
+        NeutronSecurityRule portSecurityRule2 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule2.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule2.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+
+        NeutronSecurityRule portSecurityRule3 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule3.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(portSecurityRule3.getSecurityRuleDirection()).thenReturn(null);
+
+        NeutronSecurityRule portSecurityRule4 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule4.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule4.getSecurityRuleDirection()).thenReturn(null);
+
+        List<NeutronSecurityRule> portSecurityList = new ArrayList<>();
+        portSecurityList.add(null);
+        portSecurityList.add(portSecurityRule1);
+        portSecurityList.add(portSecurityRule2);
+        portSecurityList.add(portSecurityRule3);
+        portSecurityList.add(portSecurityRule4);
+
+        NeutronSecurityGroup localSecurityGroup = mock(NeutronSecurityGroup.class);
+        when(localSecurityGroup.getSecurityRules()).thenReturn(portSecurityList);
+
+        ingressAclServiceSpy.programPortSecurityGroup(
+                Long.valueOf(1554), "2", MAC_ADDRESS, 124, localSecurityGroup, PORT_UUID, false);
+    }
+
+    /**
+     *  Test IPv4 add test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIpv4() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        ingressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,true);
+
+        verify(writeTransaction, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).checkedGet();
+    }
+
+    /**
+     *  Test IPv6 add test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIpv6() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        ingressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroupIpv6, PORT_UUID, true);
+
+        verify(writeTransaction, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).checkedGet();
+    }
+
+    /**
+     *  Test IPv4 remove test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIpv4() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        ingressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,false);
+
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+    }
+
+    /**
+     *  Test IPv6 remove test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIpv6() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(null);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn(null);
+
+        ingressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroupIpv6, PORT_UUID, false);
+
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+    }
+
+    /**
+     *  Test IPv4 TCP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(15);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(15);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(15, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(15);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(15);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(15, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+
+    /**
+     *  Test IPv6 TCP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 TCP add with port (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP add with port (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 TCP add with port (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP add with port (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddTcpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 TCP remove with port (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 TCP remove with port (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveTcpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_TCP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP add with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP remove with port no and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                "_" + port + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP add with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP remove with port no and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityIpv6Rule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + IPV6_DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP add with ports (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN  + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP add with ports (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIPv6AddUdpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN  + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP remove with ports (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN  + "_" +
+                PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv6 UDP remove with ports (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdpAll1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN  + "_" +
+                PORT_RANGE_MAX + "_::/64_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test IPv4 UDP add with ports (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                        PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP add with ports (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddUdpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 UDP remove with ports (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                      PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                        PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv6 UDP remove with ports (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveUdpAll2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_UDP);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6,
+                PORT_UUID, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMP add with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIcmp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(10);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(10);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                                                    MAC_ADDRESS, LOCAL_PORT, securityGroup, PORT_UUID, true);
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(10, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(10, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code
+                            + "_0.0.0.0/24_Permit",
+                            flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMPv6 add with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddIcmp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(10);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(10);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6, PORT_UUID, true);
+
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(10, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(10, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code
+                        + "_::/64_Permit",
+                flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMP remove with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIcmp1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                                                    MAC_ADDRESS, LOCAL_PORT, securityGroup, PORT_UUID, false);
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(20, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(20, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code
+                            + "_0.0.0.0/24_Permit",
+                            flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMPv6 remove with code, type and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveIcmp1() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(20);
+        when(portSecurityIpv6Rule.getSecurityRuleRemoteIpPrefix()).thenReturn("::/64");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6, PORT_UUID, false);
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(20, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(20, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        Assert.assertEquals("Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code
+                        + "_::/64_Permit",
+                flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test ICMP add with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddIcmp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(30);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                                                    MAC_ADDRESS, LOCAL_PORT, securityGroup, PORT_UUID, true);
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match =match.getIcmpv4Match();
+        Assert.assertEquals(30, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(30, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                                + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                                + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMPv6 add with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6AddIcmp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(30);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6, PORT_UUID, true);
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match =match.getIcmpv6Match();
+        Assert.assertEquals(30, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(30, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMP remove with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveIcmp2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMP);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(40);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer())
+        .when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class), any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                                                    MAC_ADDRESS, LOCAL_PORT, securityGroup, PORT_UUID, false);
+        Match match = flowBuilder.getMatch();
+        Icmpv4Match icmpv4Match = match.getIcmpv4Match();
+        Assert.assertEquals(40, icmpv4Match.getIcmpv4Type().shortValue());
+        Assert.assertEquals(40, icmpv4Match.getIcmpv4Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV4_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                                + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                                + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test ICMPv6 remove with code, type and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleIpv6RemoveIcmp2() throws Exception {
+        when(portSecurityIpv6Rule.getSecurityRuleProtocol()).thenReturn(NeutronSecurityRule.PROTOCOL_ICMPV6);
+        when(portSecurityIpv6Rule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityIpv6Rule.getSecurityRulePortMin()).thenReturn(40);
+        when(portSecurityIpv6Rule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer())
+                .when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class), any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID,
+                MAC_ADDRESS, LOCAL_PORT, securityGroupIpv6, PORT_UUID, false);
+        Match match = flowBuilder.getMatch();
+        Icmpv6Match icmpv6Match = match.getIcmpv6Match();
+        Assert.assertEquals(40, icmpv6Match.getIcmpv6Type().shortValue());
+        Assert.assertEquals(40, icmpv6Match.getIcmpv6Code().shortValue());
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+        Assert.assertEquals((long) IPV6_ETHER_TYPE, (long) ethMatch.getEthernetType().getType().getValue());
+        Short type = portSecurityIpv6Rule.getSecurityRulePortMin().shortValue();
+        Short code = portSecurityIpv6Rule.getSecurityRulePortMax().shortValue();
+        String expectedFlowId1 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+                + IPV6_DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test IPv4 invalid ether type test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleInvalidEther() throws Exception {
+        when(portSecurityRule.getSecurityRuleEthertype()).thenReturn("IP");
+
+        ingressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,false);
+
+        verify(writeTransaction, times(0)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(0)).submit();
+        verify(commitFuture, times(0)).get();
+    }
+
+    /**
+     *  Test IPv4 invalid direction type test case.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleInvalidDirection() throws Exception {
+        when(portSecurityRule.getSecurityRuleDirection()).thenReturn("edgress");
+
+        ingressAclServiceSpy.programPortSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,PORT_UUID,false);
+
+        verify(writeTransaction, times(0)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(0)).submit();
+        verify(commitFuture, times(0)).get();
+    }
+
+    /**
+     *  Test With isConntrackEnabled false
+     */
+    @Test
+    public void testProgramFixedSecurityACLAdd2() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(false);
+
+        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", DHCP_MAC_ADDRESS, 1, MAC_ADDRESS, true);
+
+        verify(writeTransaction, times(3)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(3)).submit();
+        verify(commitFuture, times(3)).checkedGet();
+    }
+    /**
+     *  Test With isConntrackEnabled false
+     */
+    @Test
+    public void testProgramFixedSecurityACLRemove2() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(false);
+
+        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", DHCP_MAC_ADDRESS, 1, MAC_ADDRESS, false);
+
+        verify(writeTransaction, times(3)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(3)).submit();
+        verify(commitFuture, times(3)).get();
+    }
+    /**
+     *  Test With isConntrackEnabled true
+     */
+    @Test
+    public void testProgramFixedSecurityACLAdd4() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(true);
+
+        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", DHCP_MAC_ADDRESS, 1, MAC_ADDRESS, true);
+
+        verify(writeTransaction, times(8)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
+        verify(writeTransaction, times(8)).submit();
+        verify(commitFuture, times(8)).checkedGet();
+    }
+    /**
+     *  Test With isConntrackEnabled true
+     */
+    @Test
+    public void testProgramFixedSecurityACLRemove4() throws Exception {
+        when(securityServices.isConntrackEnabled()).thenReturn(true);
+
+        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", DHCP_MAC_ADDRESS, 1, MAC_ADDRESS, false);
+
+        verify(writeTransaction, times(8)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(8)).submit();
+        verify(commitFuture, times(8)).get();
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2FowardingServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2FowardingServiceTest.java
new file mode 100644 (file)
index 0000000..ca81623
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.support.membermodification.MemberModifier;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test fort {@link L2ForwardingService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class L2FowardingServiceTest {
+
+    @InjectMocks private L2ForwardingService l2ForwardingService = new L2ForwardingService(Service.ARP_RESPONDER);
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private ReadOnlyTransaction readOnlyTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    private static final String SEGMENTATION_ID = "2";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B8";
+    private static final Long DPID = 122L;
+    private static final Long LOCAL_PORT = 451L;
+    private static final Long ETH_PORT = 564L;
+    private static final Long OF_PORT_OUT = 5698L;
+
+    @Before
+    public void setUp() throws Exception {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+
+        CheckedFuture future = mock(CheckedFuture.class);
+        when(readOnlyTransaction.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(future);
+
+        Optional<Flow> data = mock(Optional.class);
+        when(future.get()).thenReturn(data);
+
+        //when(mdsalConsumer.getDataBroker()).thenReturn(dataBroker);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programLocalUcastOut(Long, String, Long, String, boolean)}
+     */
+    @Test
+    public void testProgramLoacalUcastOut() throws Exception {
+        l2ForwardingService.programLocalUcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, MAC_ADDRESS, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programLocalUcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, MAC_ADDRESS, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programLocalVlanUcastOut(Long, String, Long, String, boolean)}
+     */
+    @Test
+    public void testProgramLocalVlanUcastOut() throws Exception {
+        l2ForwardingService.programLocalVlanUcastOut(DPID, SEGMENTATION_ID, Long.valueOf(124), MAC_ADDRESS, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programLocalVlanUcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, MAC_ADDRESS, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programLocalBcastOut(Long, String, Long, boolean)}
+     */
+    @Test
+    public void testProgramLocalBcastOut() throws Exception {
+        l2ForwardingService.programLocalBcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programLocalBcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**--------------------------------- TODO go deeper in test
+     * Test method {@link L2ForwardingService#programLocalVlanBcastOut(Long, String, Long, Long, boolean)}
+     */
+    @Test
+    public void testProgramLocalVlanBcastOut() throws Exception {
+        l2ForwardingService.programLocalVlanBcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, ETH_PORT, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programLocalVlanBcastOut(DPID, SEGMENTATION_ID, LOCAL_PORT, ETH_PORT, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programLocalTableMiss(Long, String, boolean)}
+     */
+    @Test
+    public void testProgramLocalTableMiss() throws Exception {
+        l2ForwardingService.programLocalTableMiss(DPID, SEGMENTATION_ID, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programLocalTableMiss(DPID, SEGMENTATION_ID, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programLocalVlanTableMiss(Long, String, boolean)}
+     */
+    @Test
+    public void testProgramLocalVlanTableMiss() throws Exception {
+        l2ForwardingService.programLocalVlanTableMiss(DPID, SEGMENTATION_ID, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programLocalVlanTableMiss(DPID, SEGMENTATION_ID, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programTunnelOut(Long, String, Long, String, boolean)}
+     */
+    @Test
+    public void testProgramTunnelOut() throws Exception {
+        l2ForwardingService.programTunnelOut(DPID, SEGMENTATION_ID, OF_PORT_OUT, MAC_ADDRESS, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programTunnelOut(DPID, SEGMENTATION_ID, OF_PORT_OUT, MAC_ADDRESS, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programVlanOut(Long, String, Long, String, boolean)}
+     */
+    @Test
+    public void testProgramVlanOut() throws Exception {
+        l2ForwardingService.programVlanOut(DPID, SEGMENTATION_ID, ETH_PORT, MAC_ADDRESS, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programVlanOut(DPID, SEGMENTATION_ID, ETH_PORT, MAC_ADDRESS, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**--------------------------------- TODO go deeper in test
+     * Test method {@link L2ForwardingService#programTunnelFloodOut(Long, String, Long, boolean)}
+     */
+    @Test
+    public void testProgramTunnelFloodOut() throws Exception {
+        l2ForwardingService.programTunnelFloodOut(DPID, SEGMENTATION_ID, OF_PORT_OUT, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programTunnelFloodOut(DPID, SEGMENTATION_ID, OF_PORT_OUT, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link L2ForwardingService#programVlanFloodOut(Long, String, Long, boolean)}
+     */
+    @Test
+    public void testProgramVlanFloodOut() throws Exception {
+        l2ForwardingService.programVlanFloodOut(DPID, SEGMENTATION_ID, ETH_PORT, true);
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        l2ForwardingService.programVlanFloodOut(DPID, SEGMENTATION_ID, ETH_PORT, false);
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+    * Test method {@link L2ForwardingService#programTunnelMiss(Long, String, boolean)}
+    */
+   @Test
+   public void testProgramTunnelMiss() throws Exception {
+       l2ForwardingService.programTunnelMiss(DPID, SEGMENTATION_ID, true);
+       verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+       verify(writeTransaction, times(1)).submit();
+       verify(commitFuture, times(1)).get();
+
+       l2ForwardingService.programTunnelMiss(DPID, SEGMENTATION_ID, false);
+       verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+       verify(writeTransaction, times(2)).submit();
+       verify(commitFuture, times(2)).get(); // 1 + 1 above
+   }
+
+   /**
+    * Test method {@link L2ForwardingService#programVlanMiss(Long, String, Long, boolean)}
+    */
+   @Test
+   public void testProgramVlanMiss() throws Exception {
+       l2ForwardingService.programTunnelMiss(DPID, SEGMENTATION_ID, true);
+       verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+       verify(writeTransaction, times(1)).submit();
+       verify(commitFuture, times(1)).get();
+
+       l2ForwardingService.programTunnelMiss(DPID, SEGMENTATION_ID, false);
+       verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+       verify(writeTransaction, times(2)).submit();
+       verify(commitFuture, times(2)).get(); // 1 + 1 above
+   }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2RewriteServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2RewriteServiceTest.java
new file mode 100644 (file)
index 0000000..a498d87
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import org.junit.Test;
+
+/**
+ * Unit test for {@link L2RewriteService}
+ */
+public class L2RewriteServiceTest {
+
+    @Test
+    public void test() {
+        // TODO nothing has been done in L2RewriteService class yet.
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L3FowardingServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L3FowardingServiceTest.java
new file mode 100644 (file)
index 0000000..589bc9c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.support.membermodification.MemberModifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test fort {@link L3ForwardingService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class L3FowardingServiceTest {
+
+    @InjectMocks private L3ForwardingService l3ForwardingService = new L3ForwardingService();
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    private static final String SEGMENTATION_ID = "2";
+    private static final String HOST_ADDRESS = "127.0.0.1";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+
+    @Before
+    public void setUp() throws Exception {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        NetvirtProvidersProvider netvirtProvider = mock(NetvirtProvidersProvider.class);
+        MemberModifier.field(NetvirtProvidersProvider.class, "hasProviderEntityOwnership").set(netvirtProvider, new AtomicBoolean(true));
+
+    }
+
+    /**
+     * Test method {@link L3ForwardingService#programForwardingTableEntry(Long, String, InetAddress, String, Action)}
+     */
+    @Test
+    public void testProgramForwardingTableEntry() throws Exception {
+        InetAddress address = mock(InetAddress.class);
+        when(address.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                l3ForwardingService.programForwardingTableEntry(Long.valueOf(123),
+                        SEGMENTATION_ID, address, MAC_ADDRESS, Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class),
+                any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                l3ForwardingService.programForwardingTableEntry(Long.valueOf(123),
+                        SEGMENTATION_ID, address, MAC_ADDRESS, Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/LoadBalancerServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/LoadBalancerServiceTest.java
new file mode 100644 (file)
index 0000000..3b579a8
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import org.powermock.api.support.membermodification.MemberModifier;
+
+/**
+ * Unit test fort {@link LoadBalancerService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class LoadBalancerServiceTest {
+
+    @InjectMocks private LoadBalancerService loadBalancerService = new LoadBalancerService(Service.ARP_RESPONDER);
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    @Mock private LoadBalancerConfiguration lbConfig;
+    @Mock private LoadBalancerConfiguration.LoadBalancerPoolMember member;
+    @Mock private Node node;
+
+    private static final String SEGMENTATION_ID = "2";
+    private static final String HOST_ADDRESS = "127.0.0.1";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+
+    @Before
+    public void setUp() throws Exception {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+
+        Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> members = new HashMap<>();
+        members.put("key", member);
+
+        when(lbConfig.isValid()).thenReturn(true);
+        when(lbConfig.getVip()).thenReturn(HOST_ADDRESS);
+        when(lbConfig.getMembers()).thenReturn(members);
+        when(lbConfig.getProviderNetworkType()).thenReturn(NetworkHandler.NETWORK_TYPE_VXLAN, NetworkHandler.NETWORK_TYPE_VLAN);
+        when(lbConfig.getProviderSegmentationId()).thenReturn(SEGMENTATION_ID);
+
+        when(member.getIP()).thenReturn(HOST_ADDRESS);
+        when(member.getIndex()).thenReturn(1);
+        when(member.getMAC()).thenReturn(MAC_ADDRESS);
+
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.getDataPathId(any(Node.class))).thenReturn(123L);
+        MemberModifier.field(LoadBalancerService.class, "southbound").set(loadBalancerService, southbound);
+    }
+    /**
+     * Test method {@link LoadBalancerService#programLoadBalancerPoolMemberRules(Node, LoadBalancerConfiguration, LoadBalancerConfiguration.LoadBalancerPoolMember, Action)}
+     */
+    @Test
+    public void testprogramLoadBalancerPoolMemberRules() throws Exception {
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.BADREQUEST), loadBalancerService.programLoadBalancerPoolMemberRules(node, null, null, Action.ADD));
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.NOTIMPLEMENTED), loadBalancerService.programLoadBalancerPoolMemberRules(node, lbConfig, member, Action.DELETE));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), loadBalancerService.programLoadBalancerPoolMemberRules(node, lbConfig, member, Action.ADD));
+        verify(writeTransaction, times(8)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(4)).submit();
+        verify(commitFuture, times(4)).get();
+    }
+
+    /**
+     * Test method {@link LoadBalancerService#programLoadBalancerRules(Node, LoadBalancerConfiguration, Action)}
+     */
+    @Test
+    public void testProgramLoadBalancerRules() throws Exception {
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.BADREQUEST), loadBalancerService.programLoadBalancerRules(node, null, Action.ADD));
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.NOTIMPLEMENTED), loadBalancerService.programLoadBalancerRules(node, lbConfig, Action.UPDATE));
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), loadBalancerService.programLoadBalancerRules(node, lbConfig, Action.ADD));
+        verify(writeTransaction, times(6)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(3)).submit();
+        verify(commitFuture, times(3)).get();
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), loadBalancerService.programLoadBalancerRules(node, lbConfig, Action.DELETE));
+        verify(writeTransaction, times(3)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(6)).submit();
+        verify(commitFuture, times(6)).get(); // 3 + 3 before
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/OutboundNatServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/OutboundNatServiceTest.java
new file mode 100644 (file)
index 0000000..add569c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test fort {@link OutboundNatService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class OutboundNatServiceTest {
+
+    @InjectMocks private OutboundNatService outboundNatService = new OutboundNatService();
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    private static final String SEGMENTATION_ID = "2";
+    private static final String HOST_ADDRESS = "127.0.0.1";
+    private static final String HOST_ADDRESS_PREFIX = "127.0.0.1/24";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B7";
+
+    @Before
+    public void setUp() throws Exception {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+    }
+
+    /**
+     * Test method {@link OutboundNatService#programIpRewriteRule(Long, String, String, InetAddress, String, String, InetAddress, Long, Action)}
+     */
+    @Test
+    public void testProgramIpRewriteRule() throws Exception {
+        InetAddress address = mock(InetAddress.class);
+        when(address.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS),
+                outboundNatService.programIpRewriteRule(Long.valueOf(123), SEGMENTATION_ID, MAC_ADDRESS, address,
+                                                        MAC_ADDRESS, MAC_ADDRESS, address,
+                                                        Long.valueOf(10), Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS),
+                outboundNatService.programIpRewriteRule(Long.valueOf(123), SEGMENTATION_ID, MAC_ADDRESS, address,
+                                                        MAC_ADDRESS, MAC_ADDRESS, address,
+                                                        Long.valueOf(10), Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link OutboundNatService#programIpRewriteExclusion(Long, String, String, Action)}
+     */
+    @Test
+    public void testProgramIpRewriteExclusion() throws Exception {
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), outboundNatService.programIpRewriteExclusion(Long.valueOf(123), SEGMENTATION_ID, HOST_ADDRESS_PREFIX, Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        Assert.assertEquals("Error, did not return the expected StatusCode", new Status(StatusCode.SUCCESS), outboundNatService.programIpRewriteExclusion(Long.valueOf(123), SEGMENTATION_ID, HOST_ADDRESS_PREFIX, Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+}
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/RoutingServiceTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/RoutingServiceTest.java
new file mode 100644 (file)
index 0000000..e7675e3
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.providers.openflow13.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test fort {@link RoutingService}
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class RoutingServiceTest {
+
+    @InjectMocks private RoutingService routingService = new RoutingService();
+
+    @Mock private DataBroker dataBroker;
+    @Mock private PipelineOrchestrator orchestrator;
+
+    @Mock private WriteTransaction writeTransaction;
+    @Mock private CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
+
+    private static final String SEGMENTATION_ID = "2";
+    private static final String HOST_ADDRESS = "127.0.0.1";
+    private static final String MAC_ADDRESS = "87:1D:5E:02:40:B8";
+
+    @Before
+    public void setUp() throws Exception {
+        when(writeTransaction.submit()).thenReturn(commitFuture);
+
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+
+        when(orchestrator.getNextServiceInPipeline(any(Service.class))).thenReturn(Service.ARP_RESPONDER);
+    }
+
+    /**
+     * Test method {@link RoutingService#programRouterInterface(Long, String, String, String, InetAddress, int, Action)}
+     */
+    @Test
+    public void testProgramRouterInterface() throws Exception {
+        InetAddress address = mock(InetAddress.class);
+        when(address.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                routingService.programRouterInterface(Long.valueOf(123),
+                        SEGMENTATION_ID, SEGMENTATION_ID, MAC_ADDRESS, address, 1, Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                routingService.programRouterInterface(Long.valueOf(123),
+                        SEGMENTATION_ID, SEGMENTATION_ID, MAC_ADDRESS, address, 1, Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link RoutingService#programDefaultRouteEntry(Long, String, String, InetAddress, Action)}
+     */
+    @Test
+    public void testProgramDefaultRouteEntry() throws Exception {
+        InetAddress address = mock(InetAddress.class);
+        when(address.getHostAddress()).thenReturn(HOST_ADDRESS);
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                routingService.programDefaultRouteEntry(Long.valueOf(123),
+                        SEGMENTATION_ID, MAC_ADDRESS, address, Action.ADD));
+        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class),
+                any(InstanceIdentifier.class), any(Node.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+        verify(commitFuture, times(1)).get();
+
+        assertEquals("Error, did not return the expected StatusCode",
+                new Status(StatusCode.SUCCESS),
+                routingService.programDefaultRouteEntry(Long.valueOf(123),
+                        SEGMENTATION_ID, MAC_ADDRESS, address, Action.DELETE));
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(2)).submit();
+        verify(commitFuture, times(2)).get(); // 1 + 1 above
+    }
+}
diff --git a/openstack/net-virt-sfc/api/pom.xml b/openstack/net-virt-sfc/api/pom.xml
new file mode 100644 (file)
index 0000000..2513876
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.mdsal</groupId>
+    <artifactId>binding-parent</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-api</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <sfc.project.version>0.3.0-SNAPSHOT</sfc.project.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-model</artifactId>
+      <version>${sfc.project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.yang.gen.v1.*,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105,
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang b/openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang
new file mode 100644 (file)
index 0000000..9ed2f3d
--- /dev/null
@@ -0,0 +1,38 @@
+module netvirt-sfc-acl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:sfc:acl";
+    prefix "acl";
+
+    import ietf-access-control-list { prefix ietf-acl;}
+    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:actions" {
+        description "Redirect traffic to SFC identified by either SFC, SFP or RSP";
+        ext:augment-identifier "redirect-to-sfc";
+        leaf sfc-name {
+            type string;
+        }
+        leaf sfp-name {
+            type string;
+        }
+        leaf rsp-name {
+            type string;
+        }
+        leaf render-rsp {
+            type boolean;
+            default "false";
+        }
+    }
+}
diff --git a/openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang b/openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang
new file mode 100644 (file)
index 0000000..fa2067d
--- /dev/null
@@ -0,0 +1,51 @@
+module netvirt-sfc-classifier {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:sfc:classifier";
+    prefix "classifier";
+
+    import ietf-inet-types { prefix inet;}
+    import ietf-yang-types { prefix yang;}
+
+    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/openstack/net-virt-sfc/api/src/main/yang/netvirt-sfc.yang b/openstack/net-virt-sfc/api/src/main/yang/netvirt-sfc.yang
new file mode 100644 (file)
index 0000000..e00ddb6
--- /dev/null
@@ -0,0 +1,15 @@
+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/openstack/net-virt-sfc/artifacts/pom.xml b/openstack/net-virt-sfc/artifacts/pom.xml
new file mode 100644 (file)
index 0000000..12f4c4d
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-artifacts</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>openstack.net-virt-sfc-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>openstack.net-virt-sfc-impl</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>openstack.net-virt-sfc-features</artifactId>
+        <version>${project.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+</project>
diff --git a/openstack/net-virt-sfc/features/pom.xml b/openstack/net-virt-sfc/features/pom.xml
new file mode 100644 (file)
index 0000000..12b8d43
--- /dev/null
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>features-parent</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-features</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <properties>
+    <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+    <controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
+    <dlux.version>0.4.0-SNAPSHOT</dlux.version>
+    <mdsal.model.version>0.9.0-SNAPSHOT</mdsal.model.version>
+    <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+    <restconf.version>1.4.0-SNAPSHOT</restconf.version>
+    <sfc.version>0.3.0-SNAPSHOT</sfc.version>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>features-dlux</artifactId>
+      <classifier>features</classifier>
+      <version>${dlux.version}</version>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-mdsal</artifactId>
+      <version>${controller.mdsal.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>features-mdsal-model</artifactId>
+      <version>${mdsal.model.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>features-restconf</artifactId>
+      <version>${restconf.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>features-netvirt</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-features</artifactId>
+      <version>${ovsdb.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin-extension</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-impl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-impl</artifactId>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.netvirt-it-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.ovsdb-it-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.southbound-utils</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/openstack/net-virt-sfc/features/src/main/features/features.xml b/openstack/net-virt-sfc/features/src/main/features/features.xml
new file mode 100644 (file)
index 0000000..dc31496
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright © 2015 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
+-->
+<features name="odl-ovsdb-sfc-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+  <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.dlux/features-dlux/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.netconf/features-restconf/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.netvirt/features-netvirt/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.ovsdb/southbound-features/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.sfc/features-sfc/{{VERSION}}/xml/features</repository>
+  <feature name='odl-ovsdb-sfc-api' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: api'>
+    <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
+    <bundle>mvn:org.opendaylight.netvirt/openstack.net-virt-sfc-api/{{VERSION}}</bundle>
+  </feature>
+  <feature name='odl-ovsdb-sfc' version='${project.version}' description='OpenDaylight :: ovsdb-sfc'>
+    <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
+    <feature version='${openflowplugin.version}'>odl-openflowplugin-nxm-extensions</feature>
+    <feature version='${ovsdb.version}'>odl-ovsdb-southbound-impl</feature>
+    <feature version='${project.version}'>odl-ovsdb-openstack</feature>
+    <feature version='${sfc.version}'>odl-sfcofl2</feature>
+    <feature version='${project.version}'>odl-ovsdb-sfc-api</feature>
+    <bundle>mvn:org.opendaylight.netvirt/utils.servicehelper/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/openstack.net-virt-sfc-impl/{{VERSION}}</bundle>
+    <configfile finalname="${configfile.directory}/openstack.net-virt-sfc.xml">mvn:org.opendaylight.netvirt/openstack.net-virt-sfc-impl/{{VERSION}}/xml/config</configfile>
+  </feature>
+  <feature name='odl-ovsdb-sfc-rest' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: REST'>
+    <feature version="${project.version}">odl-ovsdb-sfc</feature>
+    <feature version="${restconf.version}">odl-restconf</feature>
+  </feature>
+  <feature name='odl-ovsdb-sfc-ui' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: UI'>
+    <feature version="${project.version}">odl-ovsdb-sfc-rest</feature>
+    <feature version="${restconf.version}">odl-mdsal-apidocs</feature>
+    <feature version="${controller.mdsal.version}">odl-mdsal-xsql</feature>
+    <feature version="${dlux.version}">odl-dlux-yangui</feature>
+  </feature>
+  <feature name='odl-ovsdb-sfc-test' version='${project.version}' description='OpenDaylight :: ovsdb-sfc-test'>
+    <bundle>mvn:org.opendaylight.netvirt/utils.netvirt-it-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.ovsdb-it-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.netvirt/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
+    <feature version='${project.version}'>odl-ovsdb-sfc-ui</feature>
+  </feature>
+</features>
diff --git a/openstack/net-virt-sfc/impl/pom.xml b/openstack/net-virt-sfc/impl/pom.xml
new file mode 100644 (file)
index 0000000..ba18741
--- /dev/null
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright © 2015, 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-impl</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+    <sfc.version>0.3.0-SNAPSHOT</sfc.version>
+    <sonar.jacoco.itReportPath>../it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-providers</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-api</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-impl</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-base</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-topology</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>iana-if-type-2014-05-08</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-model</artifactId>
+      <version>${sfc.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-provider</artifactId>
+      <version>${sfc.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar-plugins.java</groupId>
+      <artifactId>sonar-jacoco-listeners</artifactId>
+      <version>${sonar-jacoco-listeners.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+            <Export-Package>
+              org.opendaylight.netvirt.openstack.netvirt.sfc,
+              org.opendaylight.netvirt.openstack.netvirt.sfc.workaround.services
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <properties>
+            <property>
+              <name>listener</name>
+              <value>org.sonar.java.jacoco.JUnitListener</value>
+            </property>
+          </properties>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/openstack/net-virt-sfc/impl/src/main/config/default-config.xml b/openstack/net-virt-sfc/impl/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..0726eb6
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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
+-->
+<snapshot>
+  <required-capabilities>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:sfc:impl?module=netvirt-sfc-impl&amp;revision=2014-12-10</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:southbound:impl?module=southbound-impl&amp;revision=2014-12-10</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:impl?module=netvirt-impl&amp;revision=2015-05-13</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl?module=netvirt-providers-impl&amp;revision=2015-05-13</capability>
+  </required-capabilities>
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:sfc:impl">prefix:netvirt-sfc-impl</type>
+          <name>netvirt-sfc-impl</name>
+          <of13provider>workaround</of13provider>
+          <addsfflows>false</addsfflows>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/DelegatingDataTreeListener.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/DelegatingDataTreeListener.java
new file mode 100644 (file)
index 0000000..4afd0c8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, 2016 Dell, 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.openstack.netvirt.sfc;
+
+import java.util.Collection;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Preconditions;
+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 INetvirtSfcDataProcessor}.
+ */
+public class DelegatingDataTreeListener<T extends DataObject> implements AutoCloseable, DataTreeChangeListener<T> {
+    private static final Logger LOG = LoggerFactory.getLogger(DelegatingDataTreeListener.class);
+    protected INetvirtSfcOF13Provider provider;
+    private final ExecutorService executorService = Executors.newFixedThreadPool(1);
+    private final INetvirtSfcDataProcessor<T> dataProcessor;
+    private ListenerRegistration<DelegatingDataTreeListener<T>> listenerRegistration;
+
+    public DelegatingDataTreeListener(INetvirtSfcOF13Provider provider, INetvirtSfcDataProcessor<T> dataProcessor,
+                                      DataBroker db, DataTreeIdentifier<T> treeId) {
+        this.provider = Preconditions.checkNotNull(provider, "provider can not be null!");
+        this.dataProcessor = Preconditions.checkNotNull(dataProcessor, "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!"));
+    }
+
+    private void registerListener(final DataBroker db, DataTreeIdentifier<T> 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<DataTreeModification<T>> changes) {
+        LOG.info("onDataTreeChanged: Received Data Tree Changed ...", changes);
+        for (DataTreeModification<T> change : changes) {
+            final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
+            final DataObjectModification<T> 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(key, mod.getDataBefore());
+                    break;
+                case SUBTREE_MODIFIED:
+                    dataProcessor.update(key, mod.getDataBefore(), mod.getDataAfter());
+                    break;
+                case WRITE:
+                    if (mod.getDataBefore() == null) {
+                        dataProcessor.add(key, mod.getDataAfter());
+                    } else {
+                        dataProcessor.update(key, mod.getDataBefore(), mod.getDataAfter());
+                    }
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
+            }
+        }
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<T>> changes) {
+        Preconditions.checkNotNull(changes, "Changes may not be null!");
+        executorService.submit(new Runnable() {
+            @Override
+            public void run() {
+                processChanges(changes);
+            }
+        });
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            listenerRegistration.close();
+            listenerRegistration = null;
+        }
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/INetvirtSfcDataProcessor.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/INetvirtSfcDataProcessor.java
new file mode 100644 (file)
index 0000000..4fa76ff
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 2016 Dell, 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.openstack.netvirt.sfc;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * netvirt-sfc-dcl processor
+ * org.opendaylight.ovsdb.openstack.netvirt.sfc
+ */
+public interface INetvirtSfcDataProcessor<D extends DataObject> {
+
+    /**
+     * Method removes DataObject which is identified by InstanceIdentifier.
+     *
+     * @param identifier - the whole path to DataObject
+     * @param del - DataObject for removing
+     */
+    void remove(InstanceIdentifier<D> identifier, D del);
+
+    /**
+     * Method updates the original DataObject to the update DataObject.
+     * Both are identified by same InstanceIdentifier.
+     *
+     * @param identifier - the whole path to DataObject
+     * @param original - original DataObject (for update)
+     * @param update - changed DataObject (contain updates)
+     */
+    void update(InstanceIdentifier<D> identifier, D original, D update);
+
+    /**
+     * Method adds the DataObject which is identified by InstanceIdentifier
+     * to device.
+     *
+     * @param identifier - the whole path to new DataObject
+     * @param add - new DataObject
+     */
+    void add(InstanceIdentifier<D> identifier, D add);
+
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/INetvirtSfcOF13Provider.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/INetvirtSfcOF13Provider.java
new file mode 100644 (file)
index 0000000..6f14e35
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015 Dell, 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.openstack.netvirt.sfc;
+
+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.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
+ * @author Arun Yerra
+ */
+public interface INetvirtSfcOF13Provider {
+
+    /**
+     * Method installs the OF rules corresponding to rules within ACL
+     * on a given Service Function Forwarder. DataObject which is identified by InstanceIdentifier.
+     *
+     * @param bridge - Service Function Forwarder
+     * @param acl - Access list includes rules that need to be installed in a SFF.
+     */
+    void addClassifierRules(Bridge bridge, Acl acl);
+    void addClassifierRules(Bridges bridges, Acl acl);
+
+    /**
+     * Method removes the OF rules corresponding to rules within ACL
+     * on a given Service Function Forwarder. DataObject which is identified by InstanceIdentifier.
+     *
+     * @param sff - Service Function Forwarder
+     * @param acl - Access list includes rules that need to be installed in a SFF.
+     */
+    void removeClassifierRules(Sff sff, Acl acl);
+
+    void addClassifierRules(Acl acl);
+    void removeClassifierRules(Acl acl);
+    void setSfcClassifierService(ISfcClassifierService sfcClassifierService);
+    public void setDependencies(ServiceReference serviceReference);
+    void updateRsp(RenderedServicePath change);
+    void removeRsp(RenderedServicePath change);
+    void addRsp(RenderedServicePath change);
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/ISfcClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/ISfcClassifierService.java
new file mode 100644 (file)
index 0000000..71e6fb4
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+
+public interface ISfcClassifierService {
+    void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
+                                  NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write);
+
+    void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
+
+    void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                  int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
+
+    void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                 long sfOfPort, int tunnelId, String rspName, boolean write);
+
+    void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                       long sfOfPort, int tunnelId, String rspName, boolean write);
+
+    void program_sfEgress(long dataPathId, int dstPort, String rspName, boolean write);
+
+    void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                           String ipAddress, String sfDplName, String rspName, boolean write);
+
+    void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                               String ipAddress, String rspName, boolean write);
+
+    void clearFlows(DataBroker dataBroker, String rspName);
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/ISfcStandaloneClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/ISfcStandaloneClassifierService.java
new file mode 100644 (file)
index 0000000..026ee56
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+
+public interface ISfcStandaloneClassifierService {
+    void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
+                                  NshUtils nshHeader, long vxGpeOfPort, boolean write);
+
+    void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
+
+    void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                  int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
+
+    void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                 long sfOfPort, int tunnelId, boolean write);
+
+    void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                       long sfOfPort, int tunnelId, boolean write);
+
+    void program_sfEgress(long dataPathId, int dstPort, boolean write);
+
+    void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                           String ipAddress, String sfDplName, boolean write);
+
+    void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                               String ipAddress, boolean write);
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcAclDataProcessor.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcAclDataProcessor.java
new file mode 100644 (file)
index 0000000..27b08f0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2015, 2016 Dell, 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.openstack.netvirt.sfc;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Data processor for AccessList.
+ */
+public class NetvirtSfcAclDataProcessor implements INetvirtSfcDataProcessor<Acl> {
+    private final INetvirtSfcOF13Provider provider;
+
+    /**
+     * {@link NetvirtSfcAclDataProcessor} constructor.
+     * @param provider OpenFlow 1.3 Provider
+     */
+    public NetvirtSfcAclDataProcessor(final INetvirtSfcOF13Provider provider) {
+        this.provider = Preconditions.checkNotNull(provider, "Provider can not be null!");
+    }
+
+    @Override
+    public void remove(final InstanceIdentifier<Acl> identifier,
+                       final Acl change) {
+        Preconditions.checkNotNull(change, "Removed object can not be null!");
+        provider.removeClassifierRules(change);
+    }
+
+    @Override
+    public void update(final InstanceIdentifier<Acl> identifier,
+                       final Acl original, final Acl change) {
+        Preconditions.checkNotNull(original, "Updated original object can not be null!");
+        Preconditions.checkNotNull(original, "Updated update object can not be null!");
+        remove(identifier, original);
+        provider.addClassifierRules(change);
+    }
+
+    @Override
+    public void add(final InstanceIdentifier<Acl> identifier,
+                    final Acl change) {
+        Preconditions.checkNotNull(change, "Added object can not be null!");
+        provider.addClassifierRules(change);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcAclListener.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcAclListener.java
new file mode 100644 (file)
index 0000000..fe2d2c6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2015, 2016 Dell, 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.openstack.netvirt.sfc;
+
+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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Data tree listener for AccessList.
+ */
+public class NetvirtSfcAclListener extends DelegatingDataTreeListener<Acl> {
+    /**
+     * {@link NetvirtSfcAclListener} constructor.
+     * @param provider OpenFlow 1.3 Provider
+     * @param db MdSal {@link DataBroker}
+     */
+    public NetvirtSfcAclListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
+        super(provider, new NetvirtSfcAclDataProcessor(provider), db,
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.create(AccessLists.class).child(Acl.class)));
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcClassifierDataProcessor.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcClassifierDataProcessor.java
new file mode 100644 (file)
index 0000000..03fd547
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2015, 2016 Dell, 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.openstack.netvirt.sfc;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers
+        .Classifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data processor for Classifier.
+ */
+public class NetvirtSfcClassifierDataProcessor implements INetvirtSfcDataProcessor<Classifier> {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcClassifierDataProcessor.class);
+    private final MdsalUtils mdsalUtils;
+    private final INetvirtSfcOF13Provider provider;
+
+    /**
+     * {@link NetvirtSfcClassifierDataProcessor} constructor.
+     * @param provider OpenFlow 1.3 Provider
+     * @param db MdSal {@link DataBroker}
+     */
+    public NetvirtSfcClassifierDataProcessor(final INetvirtSfcOF13Provider provider, final DataBroker db) {
+        this.provider = Preconditions.checkNotNull(provider, "Provider can not be null!");
+        Preconditions.checkNotNull(db, "DataBroker can not be null!");
+        mdsalUtils = new MdsalUtils(db);
+    }
+
+    @Override
+    public void remove(final InstanceIdentifier<Classifier> identifier,
+                       final Classifier change) {
+        Preconditions.checkNotNull(change, "Added object can not be null!");
+        String aclName = change.getAcl();
+        // Read the ACL information from data store and make sure it exists.
+        Acl acl = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
+        if (acl == null) {
+            LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
+            return;
+        }
+
+        provider.removeClassifierRules(acl);
+    }
+
+    @Override
+    public void update(final InstanceIdentifier<Classifier> identifier,
+                       final Classifier original, final Classifier change) {
+        //TODO
+
+    }
+
+    @Override
+    public void add(final InstanceIdentifier<Classifier> identifier,
+                    final Classifier change) {
+        Preconditions.checkNotNull(change, "Added object can not be null!");
+        String aclName = change.getAcl();
+        // Read the ACL information from data store and make sure it exists.
+        Acl acl = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
+        if (acl == null) {
+            LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
+            return;
+        }
+
+        provider.addClassifierRules(acl);
+    }
+
+    private InstanceIdentifier<Acl> getIetfAclIid(String aclName) {
+        return InstanceIdentifier.create(AccessLists.class).child(Acl.class, new AclKey(aclName));
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java
new file mode 100644 (file)
index 0000000..21d0ea6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2015, 2016 Dell, 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.openstack.netvirt.sfc;
+
+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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Data tree listener for Classifier.
+ *
+ * @author Arun Yerra
+ */
+public class NetvirtSfcClassifierListener extends DelegatingDataTreeListener<Classifier> {
+    /**
+     * {@link NetvirtSfcClassifierListener} constructor.
+     * @param provider OpenFlow 1.3 Provider
+     * @param db MdSal {@link DataBroker}
+     */
+    public NetvirtSfcClassifierListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
+        super(provider, new NetvirtSfcClassifierDataProcessor(provider, db), db,
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.create(Classifiers.class).child(Classifier.class)));
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcProvider.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NetvirtSfcProvider.java
new file mode 100644 (file)
index 0000000..f9bc99e
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2015, 2016 Dell, 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.openstack.netvirt.sfc;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.OF13Provider;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.standalone.openflow13.NetvirtSfcStandaloneOF13Provider;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.standalone.openflow13.services.SfcClassifierService;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.workaround.NetvirtSfcWorkaroundOF13Provider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcProvider.class);
+    private AutoCloseable aclListener;
+    private AutoCloseable classifierListener;
+    private AutoCloseable rspListener;
+    private Boolean addSfFlows;
+
+    public void setOf13Provider(String of13Provider) {
+        LOG.info("of13Provider is: {}", of13Provider);
+        this.of13Provider = of13Provider;
+    }
+
+    private String of13Provider;
+
+    public void setBundleContext(BundleContext bundleContext) {
+        LOG.info("bundleContext is: {}", bundleContext);
+        this.bundleContext = bundleContext;
+    }
+
+    private BundleContext bundleContext;
+
+    public NetvirtSfcProvider(BundleContext bundleContext) {
+        LOG.info("NetvirtSfcProvider: bundleContext: {}", bundleContext);
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public void onSessionInitiated(ProviderContext session) {
+        LOG.info("NetvirtSfcProvider Session Initiated");
+        DataBroker dataBroker = session.getSALService(DataBroker.class);
+
+        MdsalUtils mdsalUtils = new MdsalUtils(dataBroker);
+        SfcUtils sfcUtils = new SfcUtils(mdsalUtils);
+
+        // Allocate provider based on config
+        INetvirtSfcOF13Provider provider;
+        if (of13Provider.equals("standalone")) {
+            provider = new NetvirtSfcStandaloneOF13Provider(dataBroker);
+        } else {
+            provider = new NetvirtSfcWorkaroundOF13Provider(dataBroker, mdsalUtils, sfcUtils, addSfFlows);
+        }
+        aclListener = new NetvirtSfcAclListener(provider, dataBroker);
+        classifierListener = new NetvirtSfcClassifierListener(provider, dataBroker);
+        rspListener = new RspListener(provider, dataBroker);
+
+        addToPipeline(provider);
+        provider.setDependencies(null);
+    }
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("NetvirtSfcProvider Closed");
+        aclListener.close();
+        classifierListener.close();
+        rspListener.close();
+    }
+
+    private void addToPipeline(INetvirtSfcOF13Provider provider) {
+        if (provider instanceof NetvirtSfcStandaloneOF13Provider) {
+            SfcClassifierService sfcClassifierService =
+                    new SfcClassifierService();
+            registerService(bundleContext, ISfcClassifierService.class.getName(),
+                    sfcClassifierService, Service.SFC_CLASSIFIER);
+            sfcClassifierService.setDependencies(bundleContext, null);
+        } else {
+            org.opendaylight.netvirt.openstack.netvirt.sfc.workaround.services.SfcClassifierService sfcClassifierService =
+                    new org.opendaylight.netvirt.openstack.netvirt.sfc.workaround.services.SfcClassifierService();
+            registerService(bundleContext, ISfcClassifierService.class.getName(),
+                    sfcClassifierService, Service.SFC_CLASSIFIER);
+            sfcClassifierService.setDependencies(bundleContext, null);
+        }
+
+        //provider.setSfcClassifierService(sfcClassifierService);
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String[] interfaces,
+                                                   Dictionary<String, Object> properties, Object impl) {
+        ServiceRegistration<?> serviceRegistration = bundleContext.registerService(interfaces, impl, properties);
+        return serviceRegistration;
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String interfaceClassName,
+                                                       Object impl, Object serviceProperty) {
+        Dictionary<String, Object> properties = new Hashtable<>();
+        properties.put(AbstractServiceInstance.SERVICE_PROPERTY, serviceProperty);
+        properties.put(Constants.PROVIDER_NAME_PROPERTY, OF13Provider.NAME);
+        return registerService(bundleContext,
+                new String[] {AbstractServiceInstance.class.getName(),interfaceClassName},
+                properties, impl);
+    }
+
+    public void setAddSfFlows(Boolean addSfFlows) {
+        LOG.info("setAddSfFlows: addSfFlows is {}", addSfFlows);
+        this.addSfFlows = addSfFlows;
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NshUtils.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/NshUtils.java
new file mode 100644 (file)
index 0000000..47e60cd
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015 Dell, 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.openstack.netvirt.sfc;
+
+import com.google.common.net.InetAddresses;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+
+/**
+ * Open Vswitch DB OpenFlow 1.3 Networking Provider for Netvirt SFC Utilities.
+ * @author Arun Yerra
+ */
+public class NshUtils {
+    private Ipv4Address nshTunIpDst;
+    private PortNumber nshTunUdpPort;
+    private long nshNsp;
+    private short nshNsi;
+    private long nshMetaC1;
+    private long nshMetaC2;
+
+    public NshUtils() {
+        super();
+    }
+
+    /**
+     * {@link NshUtils} constructor.
+     * @param nshTunIpDst Tunnel Destination IP
+     * @param nshTunUdpPort Tunnel Transport Port
+     * @param nshNsp Service Path Id
+     * @param nshNsi Service Path Index
+     * @param nshMetaC1 End point ID
+     * @param nshMetaC2 Tunnel Id.
+     */
+    public NshUtils(Ipv4Address nshTunIpDst, PortNumber nshTunUdpPort,
+            long nshNsp, short nshNsi, long nshMetaC1,
+            long nshMetaC2) {
+        super();
+        this.nshTunIpDst = nshTunIpDst;
+        this.nshTunUdpPort = nshTunUdpPort;
+        this.nshNsp = nshNsp;
+        this.nshNsi = nshNsi;
+        this.nshMetaC1 = nshMetaC1;
+        this.nshMetaC2 = nshMetaC2;
+    }
+
+    /*
+     * @return the nshTunIpDst
+     */
+    public Ipv4Address getNshTunIpDst() {
+        return nshTunIpDst;
+    }
+
+    /*
+     * @param nshTunIpDst the nshTunIpDst to set
+     */
+    public void setNshTunIpDst(Ipv4Address nshTunIpDst) {
+        this.nshTunIpDst = nshTunIpDst;
+    }
+
+    /*
+     * @return the nshTunUdpPort
+     */
+    public PortNumber getNshTunUdpPort() {
+        return nshTunUdpPort;
+    }
+
+    /*
+     * @param nshTunUdpPort the nshTunUdpPort to set
+     */
+    public void setNshTunUdpPort(PortNumber nshTunUdpPort) {
+        this.nshTunUdpPort = nshTunUdpPort;
+    }
+
+    /*
+     * @return the nshNsp
+     */
+    public long getNshNsp() {
+        return nshNsp;
+    }
+
+    /*
+     * @param nshNsp the nshNsp to set
+     */
+    public void setNshNsp(long nshNsp) {
+        this.nshNsp = nshNsp;
+    }
+
+    /*
+     * @return the nshNsi
+     */
+    public short getNshNsi() {
+        return nshNsi;
+    }
+
+    /*
+     * @param nshNsi the nshNsi to set
+     */
+    public void setNshNsi(short nshNsi) {
+        this.nshNsi = nshNsi;
+    }
+
+    /*
+     * @return the nshMetaC1
+     */
+    public long getNshMetaC1() {
+        return nshMetaC1;
+    }
+
+    /*
+     * @param nshMetaC1 the nshMetaC1 to set
+     */
+    public void setNshMetaC1(long nshMetaC1) {
+        this.nshMetaC1 = nshMetaC1;
+    }
+
+    /*
+     * @return the nshMetaC2
+     */
+    public long getNshMetaC2() {
+        return nshMetaC2;
+    }
+
+    /*
+     * @param nshMetaC2 the nshMetaC2 to set
+     */
+    public void setNshMetaC2(long nshMetaC2) {
+        this.nshMetaC2 = nshMetaC2;
+    }
+
+    public static Long convertIpAddressToLong(Ipv4Address ipv4Address) {
+        return (InetAddresses.coerceToInteger(InetAddresses.forString(ipv4Address.getValue()))) & 0xFFFFFFFFL;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "NshUtils [nshTunIpDst=" + nshTunIpDst + ", nshTunUdpPort=" + nshTunUdpPort + ", nshNsp=" + nshNsp
+                + ", nshNsi=" + nshNsi + ", nshMetaC1=" + nshMetaC1 + ", nshMetaC2=" + nshMetaC2 + "]";
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/RspDataProcessor.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/RspDataProcessor.java
new file mode 100644 (file)
index 0000000..0315e72
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2015, 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.openstack.netvirt.sfc;
+
+import com.google.common.base.Preconditions;
+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 processor for {@link RenderedServicePath}
+ */
+public class RspDataProcessor implements INetvirtSfcDataProcessor<RenderedServicePath> {
+    private final INetvirtSfcOF13Provider provider;
+
+    public RspDataProcessor(final INetvirtSfcOF13Provider provider) {
+        this.provider = Preconditions.checkNotNull(provider, "Provider can not be null!");
+    }
+
+    @Override
+    public void remove(final InstanceIdentifier<RenderedServicePath> identifier, final RenderedServicePath change) {
+        Preconditions.checkNotNull(change, "Removed object can not be null!");
+        provider.removeRsp(change);
+    }
+
+    @Override
+    public void update(final InstanceIdentifier<RenderedServicePath> identifier, final RenderedServicePath original,
+                       RenderedServicePath change) {
+        Preconditions.checkNotNull(original, "Updated original object can not be null!");
+        Preconditions.checkNotNull(original, "Updated update object can not be null!");
+        remove(identifier, original);
+        provider.addRsp(change);
+    }
+
+    @Override
+    public void add(final InstanceIdentifier<RenderedServicePath> identifier, final RenderedServicePath change) {
+        Preconditions.checkNotNull(change, "Created object can not be null!");
+        provider.addRsp(change);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/RspListener.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/RspListener.java
new file mode 100644 (file)
index 0000000..7ad0fae
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2015, 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.openstack.netvirt.sfc;
+
+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.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 {@link RenderedServicePath}
+ */
+public class RspListener extends DelegatingDataTreeListener<RenderedServicePath> {
+    public RspListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
+        super(provider, new RspDataProcessor(provider), db, new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.create(RenderedServicePaths.class).child(RenderedServicePath.class)));
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/SfcUtils.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/SfcUtils.java
new file mode 100644 (file)
index 0000000..e65d807
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc;
+
+import java.util.List;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+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.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.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.sf.rev140701.ServiceFunctions;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.entry.SfDataPlaneLocator;
+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.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+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.sl.rev140701.data.plane.locator.locator.type.Ip;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sf.ovs.rev160107.SfDplOvsAugmentation;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sf.ovs.rev160107.connected.port.OvsPort;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcUtils.class);
+    private MdsalUtils mdsalUtils;
+
+    public SfcUtils(MdsalUtils mdsalUtils) {
+        this.mdsalUtils = mdsalUtils;
+    }
+
+    public InstanceIdentifier<Classifiers> getClassifierIid() {
+        return InstanceIdentifier.create(Classifiers.class);
+    }
+
+    public InstanceIdentifier<RenderedServicePaths> getRspsId() {
+        return InstanceIdentifier.builder(RenderedServicePaths.class).build();
+    }
+
+    public InstanceIdentifier<RenderedServicePath> getRspId(String rspName) {
+        return InstanceIdentifier.builder(RenderedServicePaths.class)
+                .child(RenderedServicePath.class, new RenderedServicePathKey(new RspName(rspName))).build();
+    }
+
+    public InstanceIdentifier<ServiceFunction> getSfId(String sfName) {
+        return InstanceIdentifier.builder(ServiceFunctions.class)
+                .child(ServiceFunction.class, new ServiceFunctionKey(SfName.getDefaultInstance(sfName))).build();
+    }
+
+    public RenderedServicePath getRsp(String rspName) {
+        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, getRspId(rspName));
+    }
+
+    public RenderedServicePath getRspforSfp(String sfpName) {
+        RenderedServicePath rspFound = null;
+        RenderedServicePaths rsps = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, this.getRspsId());
+        if (rsps != null) {
+            for (RenderedServicePath rsp : rsps.getRenderedServicePath()) {
+                if (rsp.getParentServiceFunctionPath() != null) {
+                    if (rsp.getParentServiceFunctionPath().getValue().equals(sfpName)) {
+                        rspFound = rsp;
+                    }
+                }
+            }
+        }
+        return rspFound;
+    }
+
+    public ServiceFunctionPath getSfp(String sfcName) {
+        ServiceFunctionPath sfpFound = null;
+        ServiceFunctionPaths sfps = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+        if (sfps != null) {
+            for (ServiceFunctionPath sfp: sfps.getServiceFunctionPath()) {
+                if (sfp.getServiceChainName().getValue().equalsIgnoreCase(sfcName)) {
+                    sfpFound = sfp;
+                }
+            }
+        }
+        return sfpFound;
+    }
+
+    private AccessLists readAccessLists() {
+        InstanceIdentifier<AccessLists> path = InstanceIdentifier.create(AccessLists.class);
+        return mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+    }
+
+    public Ace getAce(RenderedServicePath rsp) {
+        return getAce(rsp.getName().getValue(), rsp.getParentServiceFunctionPath().getValue(),
+                rsp.getServiceChainName().getValue());
+    }
+
+    // TODO: optimize this by adding a ACL to RSP mapping in the netvirt-classifier when the ACL is processed
+    @SuppressWarnings("unchecked")
+    public Ace getAce(String rspName, String sfpName, String sfcName) {
+        Ace aceFound = null;
+        AccessLists accessLists = readAccessLists();
+        if (accessLists != null) {
+            List<Acl> acls = accessLists.getAcl();
+            if (acls != null) {
+                for (Acl acl : acls) {
+                    AccessListEntries accessListEntries = acl.getAccessListEntries();
+                    if (accessListEntries != null) {
+                        List<Ace> aces = accessListEntries.getAce();
+                        for (Ace ace : aces) {
+                            RedirectToSfc sfcRedirect = ace.getActions().getAugmentation(RedirectToSfc.class);
+                            if (sfcRedirect != null) {
+                                if ((sfcRedirect.getRspName() != null && sfcRedirect.getRspName().equals(rspName)) ||
+                                        (sfcRedirect.getSfcName() != null && sfcRedirect.getSfcName().equals(sfcName)) ||
+                                        (sfcRedirect.getSfpName() != null && sfcRedirect.getSfpName().equals(sfpName))) {
+                                    aceFound = ace;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    if (aceFound != null) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        LOG.info("getAce: {}", aceFound);
+        return aceFound;
+    }
+
+    public IpAddress getSfIpAddress(String sfname) {
+        ServiceFunction serviceFunction =
+                SfcProviderServiceFunctionAPI.readServiceFunction(SfName.getDefaultInstance(sfname));
+
+        if (serviceFunction == null) {
+            LOG.info("Failed to read ServiceFunction: {}", sfname);
+            return null;
+        }
+
+        return getSfIpAddress(serviceFunction);
+    }
+
+    public IpAddress getSfIpAddress(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
+        Ip ipLocator = (Ip) serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
+        return ipLocator.getIp();
+    }
+
+    public PortNumber getSfPort(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
+        Ip ipLocator = (Ip) serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
+        return ipLocator.getPort();
+    }
+
+    public Ip getSfIp(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
+        return (Ip)serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
+    }
+
+    public String getSfDplName(ServiceFunction serviceFunction) {
+        String sfDplName = null;
+        if (serviceFunction == null) {
+            LOG.warn("getSfDplName: Servicefunction is null");
+            return null;
+        }
+
+        sfDplName = serviceFunction.getSfDataPlaneLocator().get(0).getName().getValue();
+        return sfDplName;
+    }
+
+    public String getSfDplPortId(ServiceFunction serviceFunction) {
+        String sfDplName = null;
+        if (serviceFunction != null &&
+                serviceFunction.getSfDataPlaneLocator() != null &&
+                serviceFunction.getSfDataPlaneLocator().get(0) != null &&
+                serviceFunction.getSfDataPlaneLocator().get(0).getAugmentation(SfDplOvsAugmentation.class) != null ) {
+
+            SfDplOvsAugmentation sfDplOvsAugmentation =
+                    serviceFunction.getSfDataPlaneLocator().get(0).getAugmentation(SfDplOvsAugmentation.class);
+            if (sfDplOvsAugmentation.getOvsPort() != null) {
+                sfDplName = sfDplOvsAugmentation.getOvsPort().getPortId();
+            } else {
+                LOG.warn("getSfDplPortId: OvsPort is null");
+            }
+        } else {
+            LOG.warn("getSfDplPortId: ServiceFunction is null");
+        }
+
+        return sfDplName;
+    }
+
+    public Ip getSffIp(ServiceFunctionForwarder serviceFunctionForwarder) {
+        if (serviceFunctionForwarder != null &&
+                serviceFunctionForwarder.getSffDataPlaneLocator() != null &&
+                serviceFunctionForwarder.getSffDataPlaneLocator().get(0) != null &&
+                serviceFunctionForwarder.getSffDataPlaneLocator().get(0).getDataPlaneLocator() != null) {
+            return (Ip)serviceFunctionForwarder.getSffDataPlaneLocator().get(0)
+                    .getDataPlaneLocator().getLocatorType();
+        } else {
+            LOG.info("getSffIp: ServiceFunctionForwarder is null");
+            return null;
+        }
+    }
+
+    public Ip getSffIp(SffName sffName) {
+        ServiceFunctionForwarder serviceFunctionForwarder =
+                SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName);
+        return getSffIp(serviceFunctionForwarder);
+    }
+
+    public RenderedServicePathHop getFirstHop(RenderedServicePath rsp) {
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return null;
+        }
+
+        return pathHopList.get(0);
+    }
+
+    public RenderedServicePathHop getLastHop(RenderedServicePath rsp) {
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return null;
+        }
+
+        return pathHopList.get(pathHopList.size()-1);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/NetvirtSfcStandaloneOF13Provider.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/NetvirtSfcStandaloneOF13Provider.java
new file mode 100644 (file)
index 0000000..1e92d13
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2015 Dell, 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.openstack.netvirt.sfc.standalone.openflow13;
+
+import com.google.common.base.Preconditions;
+
+import com.google.common.collect.Iterables;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+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.rsp.rev140701.CreateRenderedPathInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+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.path.first.hop.info.RenderedServicePathFirstHop;
+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.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.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.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.rev150317.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.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
+ * @author Arun Yerra
+ */
+public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcStandaloneOF13Provider.class);
+    private static final short TABLE_0_CLASSIFIER = 0;
+    private static final short TABLE_3_INGR_ACL = 50;
+
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile Southbound southbound;
+    private MdsalUtils mdsalUtils;
+    private SfcClassifier sfcClassifier;
+
+    // TBD:: Remove these constants after integrating with openstack.
+    private static final String TUNNEL_DST = "192.168.50.75";
+    private static final String TUNNEL_VNID = "10";
+    private static final String CLIENT_PORT_NAME = "vethl-h35_2";
+    private static final String SERVER_PORT_NAME = "vethl-h35_4";
+    private static final String CLIENT_GPE_PORT_NAME = "sw1-vxlangpe-0";
+    private static final String SERVER_GPE_PORT_NAME = "sw6-vxlangpe-0";
+    private static final String INTERFACE_TYPE_VXLAN_GPE = "vxlangpe";
+
+    /**
+     * {@link NetvirtSfcStandaloneOF13Provider} constructor.
+     * @param dataBroker MdSal {@link DataBroker}
+     */
+    public NetvirtSfcStandaloneOF13Provider(final DataBroker dataBroker) {
+        Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
+        mdsalUtils = new MdsalUtils(dataBroker);
+        //this.setDependencies(null);
+        sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
+    }
+
+    public void removeClassifierRules(Sff sff, Acl acl) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void addClassifierRules(Acl acl) {
+        String aclName = acl.getAclName();
+        Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
+        if (classifiers == null) {
+            LOG.debug("add: No Classifiers found");
+            return;
+        }
+
+        LOG.debug("add: Classifiers: {}", classifiers);
+        for (Classifier classifier : classifiers.getClassifier()) {
+            if (classifier.getAcl().equals(aclName)) {
+                if (classifier.getBridges() != null) {
+                    addClassifierRules(classifier.getBridges(), acl);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void removeClassifierRules(Acl acl) {
+        String aclName = acl.getAclName();
+        Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
+        if (classifiers != null) {
+            for (Classifier classifier : classifiers.getClassifier()) {
+                if (classifier.getAcl().equalsIgnoreCase(aclName)) {
+                    if (classifier.getSffs() != null) {
+                        for (Sff sff : classifier.getSffs().getSff()) {
+                            removeClassifierRules(sff, acl);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Bridge bridge, Acl acl) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Bridges bridges, Acl acl) {
+        Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
+        Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
+
+        for (Ace ace : acl.getAccessListEntries().getAce()) {
+            processAclEntry(ace, bridges, true);
+        }
+    }
+
+    private void processAclEntry(Ace entry, Bridges bridges, boolean write) {
+        Matches matches = entry.getMatches();
+        if (matches == null) {
+            LOG.warn("processAclEntry: matches not found");
+            return;
+        }
+
+        RenderedServicePath rsp = getRenderedServicePath(entry);
+        if (rsp == null) {
+            LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
+            return;
+        }
+
+        LOG.info("processAclEntry: RSP: {}", rsp);
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("Service Path = {} has empty hops!!", rsp.getName());
+            return;
+        }
+
+        for (Bridge bridge : bridges.getBridge()) {
+            if (bridge.getDirection().getIntValue() == 0) {
+                Node bridgeNode = getBridgeNode(bridge.getName());
+                if (bridgeNode == null) {
+                    LOG.debug("processAclEntry: bridge {} not yet configured. Skip processing !!", bridge.getName());
+                    continue;
+                }
+
+                long tunnelOfPort = southbound.getOFPort(bridgeNode, CLIENT_GPE_PORT_NAME);
+                if (tunnelOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, tunnelOfPort, bridgeNode);
+                    return;
+                }
+
+                long localOfPort = southbound.getOFPort(bridgeNode, CLIENT_PORT_NAME);
+                if (localOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, localOfPort, bridgeNode);
+                    return;
+                }
+
+                // Find the first Hop within an RSP.
+                // The classifier flow needs to send all matched traffic to this first hop SFF.
+                RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
+                        .readRenderedServicePathFirstHop(new RspName(rsp.getName()));
+
+                LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(),
+                        firstRspHop.getPort().getValue());
+
+                NshUtils nshHeader = new NshUtils();
+                // C1 is the normal overlay dest ip and c2 is the vnid
+                // Hardcoded for now, netvirt integration will have those values
+                nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(new Ipv4Address(TUNNEL_DST)));
+                nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
+                nshHeader.setNshNsp(rsp.getPathId());
+
+                RenderedServicePathHop firstHop = pathHopList.get(0);
+                nshHeader.setNshNsi(firstHop.getServiceIndex());
+                nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(firstRspHop.getPort());
+                LOG.debug("The Nsh Header = {}", nshHeader);
+
+                handleLocalInPort(southbound.getDataPathId(bridgeNode), rsp.getPathId().toString(), localOfPort,
+                        TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, matches, true);
+
+                handleSfcClassiferFlows(southbound.getDataPathId(bridgeNode), TABLE_3_INGR_ACL, entry.getRuleName(),
+                        matches, nshHeader, tunnelOfPort, true);
+            } else {
+                Node bridgeNode = getBridgeNode(bridge.getName());
+                if (bridgeNode == null) {
+                    LOG.debug("processAclEntry: bridge {} not yet configured. Skip processing !!", bridge.getName());
+                    continue;
+                }
+
+                long tunnelOfPort = southbound.getOFPort(bridgeNode, SERVER_GPE_PORT_NAME);
+                if (tunnelOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, tunnelOfPort, bridgeNode);
+                    return;
+                }
+
+                long localOfPort = southbound.getOFPort(bridgeNode, SERVER_PORT_NAME);
+                if (localOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, localOfPort, bridgeNode);
+                    return;
+                }
+
+                RenderedServicePathHop lastRspHop = Iterables.getLast(rsp.getRenderedServicePathHop());
+
+                LOG.debug("programAclEntry: Last Hop #: {}, nsi: {}", lastRspHop.getHopNumber().intValue(),
+                        lastRspHop.getServiceIndex().intValue() - 1);
+
+                NshUtils nshHeader = new NshUtils();
+                nshHeader.setNshNsp(rsp.getPathId());
+                nshHeader.setNshNsi((short)(lastRspHop.getServiceIndex().intValue() - 1));
+                nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
+                LOG.debug("programAclEntry: The Nsh Header = {}", nshHeader);
+
+                //handleLocalEgressPort(southbound.getDataPathId(bridgeNode), rsp.getPathId().toString(), localOfPort,
+                //        TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, true);
+
+                handleEgressSfcClassiferFlows(southbound.getDataPathId(bridgeNode),
+                        TABLE_0_CLASSIFIER, entry.getRuleName(), matches, nshHeader, tunnelOfPort, localOfPort, true);
+            }
+        }
+    }
+
+    private RenderedServicePath getRenderedServicePath (Ace entry) {
+        RenderedServicePath rsp = null;
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("processAClEntry: sfcRedirect is null");
+            return null;
+        }
+
+        if (sfcRedirect.getRspName() != null) {
+            rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
+        } else if (sfcRedirect.getSfpName() != null) {
+            LOG.warn("getRenderedServicePath: sfp not handled yet");
+        } else {
+            rsp = getRenderedServicePathFromSfc(entry);
+        }
+        LOG.info("getRenderedServicePath: rsp: {}", rsp);
+        return rsp;
+    }
+
+    private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
+        return null;//getRsp(rspName);
+    }
+
+    private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("processAClEntry: sfcRedirect is null");
+            return null;
+        }
+
+        String sfcName = sfcRedirect.getSfcName();
+        ServiceFunctionPath sfp = getSfp(sfcName);
+        if (sfp == null || sfp.getName() == null) {
+            LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
+            return null;
+        }
+
+        LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
+        // If RSP doesn't exist, create an RSP.
+        String sfpName = sfp.getName().getValue();
+        RenderedServicePath rsp = getRspforSfp(sfpName);
+        String rspName = sfp.getName().getValue() + "_rsp";
+        if (rsp == null) {
+            LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}", sfpName, rspName);
+            CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
+                    .setParentServiceFunctionPath(sfpName)
+                    .setName(rspName)
+                    .setSymmetric(sfp.isSymmetric())
+                    .build();
+            rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
+            if (rsp == null) {
+                LOG.warn("failed to add RSP");
+                return null;
+            }
+
+            // If SFP is symmetric, create RSP in the reverse direction.
+            if (sfp.isSymmetric()) {
+                LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
+                String rspNameRev = rspName + "-Reverse";
+                RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
+                        getRspId(rspNameRev));
+                if (rspReverse == null) {
+                    rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
+                    if (rspReverse == null) {
+                        LOG.warn("failed to add reverse RSP");
+                        return null;
+                    }
+                }
+            }
+        }
+        return rsp;
+    }
+
+    private void handleLocalEgressPort(long dataPathId, String s, long localOfPort, short writeTable,
+                                       short gotoTable, boolean write) {
+
+    }
+
+    private void handleEgressSfcClassiferFlows(long dataPathId, short writeTable, String ruleName,
+                                               Matches matches, NshUtils nshHeader, long tunnelOfPort,
+                                               long outOfPort, boolean write) {
+        sfcClassifier.programEgressSfcClassiferFlows(dataPathId, writeTable, ruleName, matches, nshHeader,
+                tunnelOfPort, outOfPort, write);
+    }
+
+    private void handleSfcClassiferFlows(long dataPathId, short writeTable, String ruleName,
+                                         Matches matches, NshUtils nshHeader, long tunnelOfPort,
+                                         boolean write) {
+        sfcClassifier.programSfcClassiferFlows(dataPathId, writeTable, ruleName, matches, nshHeader,
+                tunnelOfPort, write);
+    }
+
+    private InstanceIdentifier<RenderedServicePaths> getRspsId() {
+        return InstanceIdentifier.builder(RenderedServicePaths.class).build();
+    }
+
+    private InstanceIdentifier<RenderedServicePath> getRspId(String rspName) {
+        return InstanceIdentifier.builder(RenderedServicePaths.class)
+                .child(RenderedServicePath.class, new RenderedServicePathKey(new RspName(rspName))).build();
+    }
+
+    public Node getBridgeNode(String bridgeName) {
+        Node nodeFound = null;
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (nodes != null && !nodes.isEmpty()) {
+            for (Node node : nodes) {
+                if (southbound.getBridge(node, bridgeName) != null) {
+                    nodeFound = node;
+                    break;
+                }
+            }
+        }
+        return nodeFound;
+    }
+
+    public RenderedServicePath getRspforSfp(String sfpName) {
+        RenderedServicePath rspFound = null;
+        RenderedServicePaths rsps = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, this.getRspsId());
+        if (rsps != null) {
+            for (RenderedServicePath rsp : rsps.getRenderedServicePath()) {
+                if (rsp.getParentServiceFunctionPath() != null) {
+                    if (rsp.getParentServiceFunctionPath().getValue().equals(sfpName)) {
+                        rspFound = rsp;
+                    }
+                }
+            }
+        }
+        return rspFound;
+    }
+
+    public ServiceFunctionPath getSfp(String redirectSfc) {
+        ServiceFunctionPath sfpFound = null;
+        ServiceFunctionPaths sfps = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+        if (sfps != null) {
+            for (ServiceFunctionPath sfp: sfps.getServiceFunctionPath()) {
+                if (sfp.getServiceChainName().getValue().equalsIgnoreCase(redirectSfc)) {
+                    sfpFound = sfp;
+                }
+            }
+        }
+        return sfpFound;
+    }
+
+/*
+ * (TABLE:0) EGRESS VM TRAFFIC TOWARDS TEP
+ * MATCH: DESTINATION ETHERNET ADDR AND OPENFLOW INPORT
+ * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N)
+ * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \
+ * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1"
+ */
+    public String getDestIp(Matches match) {
+        if (match.getAceType() instanceof AceIp) {
+            AceIp aceIp = (AceIp)match.getAceType();
+            if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+                AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+                if (aceIpv4.getDestinationIpv4Network() != null) {
+                    String ipAddrPrefix = aceIpv4.getDestinationIpv4Network().getValue();
+                    return new StringTokenizer(ipAddrPrefix, "/").nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    public String getSourceIp(Matches match) {
+        if (match.getAceType() instanceof AceIp) {
+            AceIp aceIp = (AceIp)match.getAceType();
+            if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+                AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+                if (aceIpv4.getSourceIpv4Network() != null) {
+                    //String ipAddr = new StringTokenizer(ipAddrPrefix, "/").nextToken();
+                    return aceIpv4.getSourceIpv4Network().getValue();
+                }
+            }
+        }
+        return null;
+    }
+
+    private InstanceIdentifier<Classifiers> getClassifierIid() {
+        return InstanceIdentifier.create(Classifiers.class);
+    }
+
+    public void handleLocalInPort(long dpidLong, String segmentationId, Long inPort,
+                                  short writeTable, short goToTableId, Matches matches, boolean write) {
+        sfcClassifier.programLocalInPort(dpidLong, segmentationId, inPort, writeTable, goToTableId, matches, write);
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void removeRsp(RenderedServicePath change) {
+        LOG.warn("removeRsp is not implemented yet");
+    }
+
+    @Override
+    public void addRsp(RenderedServicePath change) {
+        LOG.warn("addRsp is not implemented yet");
+    }
+
+    @Override
+    public void updateRsp(RenderedServicePath change) {
+        LOG.warn("updateRsp is not implemented yet");
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/SfcClassifier.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/SfcClassifier.java
new file mode 100644 (file)
index 0000000..7791742
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.standalone.openflow13;
+
+import com.google.common.collect.Lists;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.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.rev150317.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.rev150317.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.yang.types.rev100924.MacAddress;
+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.tables.table.FlowBuilder;
+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.ApplyActionsCase;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+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.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcClassifier {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcClassifier.class);
+    private DataBroker dataBroker;
+    private Southbound southbound;
+    private MdsalUtils mdsalUtils;
+    public final static long REG_VALUE_FROM_LOCAL = 0x1L;
+    public final static long REG_VALUE_FROM_REMOTE = 0x2L;
+    public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg0.class;
+    private static final String OPENFLOW = "openflow:";
+
+    public SfcClassifier(DataBroker dataBroker, Southbound southbound, MdsalUtils mdsalUtils) {
+        this.dataBroker = dataBroker;
+        this.southbound = southbound;
+        this.mdsalUtils = mdsalUtils;
+    }
+
+    /*
+     * (TABLE:50) EGRESS VM TRAFFIC TOWARDS TEP with NSH header
+     * MATCH: Match fields passed through ACL entry
+     * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N)
+     * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \
+     * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1"
+     */
+    public void programSfcClassiferFlows(Long dpidLong, short writeTable, String ruleName, Matches match,
+                                         NshUtils nshHeader, long tunnelOfPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "sfcClass_" + ruleName + "_" + nshHeader.getNshNsp();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, writeTable);
+
+        MatchBuilder matchBuilder = buildMatch(match);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            List<Action> actionList = getNshAction(nshHeader);
+            ActionBuilder ab = new ActionBuilder();
+
+            ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dpidLong, tunnelOfPort)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            List<Instruction> instructions = Lists.newArrayList();
+            instructions.add(ib.build());
+
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public void programEgressSfcClassiferFlows(Long dpidLong, short writeTable, String ruleName,
+                                               Matches match, NshUtils nshHeader,
+                                               long tunnelOfPort, long outOfPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "egressSfcClass_" + ruleName + "_" + nshHeader.getNshNsp() + "_" + nshHeader.getNshNsi();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, writeTable);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, tunnelOfPort).build());
+        flowBuilder.setMatch(
+                MatchUtils.createTunnelIDMatch(matchBuilder, BigInteger.valueOf(nshHeader.getNshMetaC2())).build());
+        flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nshHeader.getNshNsp()).build());
+        flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nshHeader.getNshNsi()).build());
+
+        if (write) {
+            List<Action> actionList = new ArrayList<>();
+            ActionBuilder ab = new ActionBuilder();
+
+            ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
+                    BigInteger.valueOf(REG_VALUE_FROM_REMOTE)));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dpidLong, outOfPort)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            List<Instruction> instructions = new ArrayList<>();
+            instructions.add(ib.build());
+
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructions);
+
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    private List<Action> getNshAction(NshUtils header) {
+        // Build the Actions to Add the NSH Header
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
+                ActionUtils.nxLoadNshc1RegAction(header.getNshMetaC1());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC2Load =
+                ActionUtils.nxLoadNshc2RegAction(header.getNshMetaC2());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad =
+                ActionUtils.nxSetNspAction(header.getNshNsp());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad =
+                ActionUtils.nxSetNsiAction(header.getNshNsi());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
+                ActionUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshNsp()), false);
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
+                ActionUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false);
+
+        int count = 0;
+        List<Action> actionList = Lists.newArrayList();
+        actionList.add(new ActionBuilder().setOrder(count++).setAction(nshC1Load).build());
+        actionList.add(new ActionBuilder().setOrder(count++).setAction(nshC2Load).build());
+        actionList.add(new ActionBuilder().setOrder(count++).setAction(nspLoad).build());
+        actionList.add(new ActionBuilder().setOrder(count++).setAction(nsiLoad).build());
+        actionList.add(new ActionBuilder().setOrder(count++).setAction(loadChainTunDest).build());
+        actionList.add(new ActionBuilder().setOrder(count++).setAction(loadChainTunVnid).build());
+        return actionList;
+    }
+
+    public void programLocalInPort(Long dpidLong, String segmentationId, Long inPort,
+                                   short writeTable, short goToTableId, Matches match, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "sfcIngress_" + segmentationId + "_" + inPort;
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, writeTable);
+
+        MatchBuilder matchBuilder = buildMatch(match);
+        flowBuilder.setMatch(matchBuilder.build());
+        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build());
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+
+            InstructionUtils.createSetTunnelIdInstructions(ib, new BigInteger(segmentationId));
+            ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
+            List<Action> actionList = aac.getApplyActions().getAction();
+
+            // TODO: Mark the packets as sfc classified?
+
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
+                    BigInteger.valueOf(REG_VALUE_FROM_LOCAL)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Next service GOTO Instructions Need to be appended to the List
+            ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId);
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public MatchBuilder buildMatch(Matches matches) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        if (matches.getAceType() instanceof AceIp) {
+            AceIp aceIp = (AceIp)matches.getAceType();
+            if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+                //AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+                //MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
+                //MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
+                MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+                MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), 0,
+                        aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
+            }
+        } else if (matches.getAceType() instanceof AceEth) {
+            AceEth aceEth = (AceEth) matches.getAceType();
+            MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
+            MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
+                    new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
+        }
+
+        LOG.info("buildMatch: {}", matchBuilder.build());
+        return matchBuilder;
+    }
+
+    protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}", flowBuilder.build(), nodeBuilder.build());
+        mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, FlowUtils.createNodePath(nodeBuilder),
+                nodeBuilder.build());
+        mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, FlowUtils.createFlowPath(flowBuilder, nodeBuilder),
+                flowBuilder.build());
+    }
+
+    protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, FlowUtils.createFlowPath(flowBuilder, nodeBuilder));
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java
new file mode 100644 (file)
index 0000000..c0ffc32
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.standalone.openflow13.services;
+
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.ISfcStandaloneClassifierService;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface,
+        ISfcStandaloneClassifierService {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
+
+    public SfcClassifierService(Service service) {
+        super(service);
+    }
+
+    public SfcClassifierService() {
+        super(Service.SFC_CLASSIFIER);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(ISfcClassifierService.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+
+    @Override
+    public void programIngressClassifier(long dataPathId, String ruleName, Matches matches, NshUtils nshHeader, long vxGpeOfPort, boolean write) {
+
+    }
+
+    @Override
+    public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
+
+    }
+
+    @Override
+    public void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi, int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
+
+    }
+
+    @Override
+    public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi, long sfOfPort, int tunnelId, boolean write) {
+
+    }
+
+    @Override
+    public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi, long sfOfPort, int tunnelId, boolean write) {
+
+    }
+
+    @Override
+    public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
+
+    }
+
+    @Override
+    public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort, String ipAddress, String sfDplName, boolean write) {
+
+    }
+
+    @Override
+    public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr, String ipAddress, boolean write) {
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java
new file mode 100644 (file)
index 0000000..5ea5f02
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.workaround;
+
+import com.google.common.base.Preconditions;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.SfcUtils;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
+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.rendered.service.path.RenderedServicePathHop;
+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.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.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcWorkaroundOF13Provider.class);
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile Southbound southbound;
+    private volatile ISfcClassifierService sfcClassifierService;
+    private static final short SFC_TABLE = 150;
+    private MdsalUtils mdsalUtils;
+    private SfcUtils sfcUtils;
+    private DataBroker dataBroker;
+    private static final String VXGPE = "vxgpe";
+    public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
+    private Boolean addSfFlows;
+
+    public NetvirtSfcWorkaroundOF13Provider(final DataBroker dataBroker, MdsalUtils mdsalUtils,
+                                            SfcUtils sfcUtils, Boolean addSfFlows) {
+        Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
+        Preconditions.checkNotNull(mdsalUtils, "Input mdsalUtils cannot be NULL!");
+        Preconditions.checkNotNull(sfcUtils, "Input sfcUtils cannot be NULL!");
+
+        this.dataBroker = dataBroker;
+        this.mdsalUtils = mdsalUtils;
+        this.sfcUtils = sfcUtils;
+        this.addSfFlows = addSfFlows;
+    }
+
+    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
+        this.sfcClassifierService = sfcClassifierService;
+    }
+
+    @Override
+    public void addClassifierRules(Bridge bridge, Acl acl) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Bridges bridges, Acl acl) {
+        Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
+        Preconditions.checkNotNull(acl, "Input acl cannot be NULL!");
+    }
+
+    @Override
+    public void removeClassifierRules(Sff sff, Acl acl) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Acl acl) {
+        for (Ace ace : acl.getAccessListEntries().getAce()) {
+            processAclEntry(ace);
+        }
+    }
+
+    @Override
+    public void removeClassifierRules(Acl acl) {
+        for (Ace ace : acl.getAccessListEntries().getAce()) {
+            RenderedServicePath rsp = getRenderedServicePath(ace);
+            if (rsp == null) {
+                LOG.warn("Failed to get renderedServicePatch for entry: {}", ace);
+                return;
+            }
+            sfcClassifierService.clearFlows(dataBroker, rsp.getName().getValue());
+        }
+    }
+
+    @Override
+    public void removeRsp(RenderedServicePath change) {
+        sfcClassifierService.clearFlows(dataBroker, change.getName().getValue());
+    }
+
+    @Override
+    public void addRsp(RenderedServicePath change) {
+        handleRenderedServicePath(change);
+    }
+
+    @Override
+    public void updateRsp(RenderedServicePath change) {
+        LOG.info("updateRsp not implemented yet");
+    }
+
+    private void processAclEntry(Ace entry) {
+        Matches matches = entry.getMatches();
+        Preconditions.checkNotNull(matches, "ACL Entry cannot be null!");
+
+        RenderedServicePath rsp = getRenderedServicePath(entry);
+        if (rsp == null) {
+            LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
+            return;
+        }
+
+        handleRenderedServicePath(rsp, entry);
+    }
+
+    private void handleRenderedServicePath(RenderedServicePath rsp) {
+        LOG.info("handleRenderedServicePath: RSP: {}", rsp);
+        Ace entry = getAceFromRenderedServicePath(rsp);
+        if (entry == null) {
+            LOG.warn("handleRenderedServicePath: failed to get acl entry");
+            return;
+        }
+
+        handleRenderedServicePath(rsp, entry);
+    }
+
+    private void handleRenderedServicePath(RenderedServicePath rsp, Ace entry) {
+        LOG.info("handleRenderedServicePath: RSP: {}, Ace: {}", rsp, entry);
+
+        Matches matches = entry.getMatches();
+        if (matches == null) {
+            LOG.warn("processAclEntry: matches not found");
+            return;
+        }
+
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return;
+        }
+        LOG.info("handleRenderedServicePath: pathHopList: {}", pathHopList);
+
+        RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
+                .readRenderedServicePathFirstHop(rsp.getName());
+        LOG.info("handleRenderedServicePath: firstRspHop: {}", firstRspHop);
+
+        RenderedServicePathHop firstHop = pathHopList.get(0);
+        RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
+
+        final List<Node> bridgeNodes = nodeCacheManager.getBridgeNodes();
+        if (bridgeNodes == null || bridgeNodes.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: There are no bridges to process");
+            return;
+        }
+        for (RenderedServicePathHop hop : pathHopList) {
+            for (Node bridgeNode : bridgeNodes) {
+                // ignore bridges other than br-int
+                // TODO: Get bridge name from DPL, rework this loop to use DPL list
+                OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
+                if (ovsdbBridgeAugmentation == null) {
+                    continue;
+                }
+                // TODO: Get port name from the DPL
+                long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
+                if (vxGpeOfPort == 0L) {
+                    LOG.warn("handleRenderedServicePath: Could not identify gpe vtep {} -> OF ({}) on {}",
+                            VXGPE, vxGpeOfPort, bridgeNode);
+                    continue;
+                }
+                long dataPathId = southbound.getDataPathId(bridgeNode);
+                if (dataPathId == 0L) {
+                    LOG.warn("handleRenderedServicePath: Could not identify datapathId on {}", bridgeNode);
+                    continue;
+                }
+
+                ServiceFunction serviceFunction =
+                        SfcProviderServiceFunctionAPI.readServiceFunction(firstHop.getServiceFunctionName());
+                if (serviceFunction == null) {
+                    LOG.warn("handleRenderedServicePath: Could not identify ServiceFunction {} on {}",
+                            firstHop.getServiceFunctionName().getValue(), bridgeNode);
+                    continue;
+                }
+                ServiceFunctionForwarder serviceFunctionForwarder =
+                        SfcProviderServiceForwarderAPI
+                                .readServiceFunctionForwarder(hop.getServiceFunctionForwarder());
+                if (serviceFunctionForwarder == null) {
+                    LOG.warn("handleRenderedServicePath: Could not identify ServiceFunctionForwarder {} on {}",
+                            firstHop.getServiceFunctionName().getValue(), bridgeNode);
+                    continue;
+                }
+
+                handleSf(bridgeNode, serviceFunction, rsp);
+                handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, firstHop, lastHop,
+                        entry.getRuleName(), matches, vxGpeOfPort, rsp);
+                if (firstHop == lastHop) {
+                    handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, null, lastHop,
+                            entry.getRuleName(), matches, vxGpeOfPort, rsp);
+                }
+            }
+        }
+    }
+
+    private void handleSff(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder,
+                           ServiceFunction serviceFunction,
+                           RenderedServicePathHop hop,
+                           RenderedServicePathHop firstHop,
+                           RenderedServicePathHop lastHop,
+                           String ruleName, Matches matches,
+                           long vxGpeOfPort, RenderedServicePath rsp) {
+        long dataPathId = southbound.getDataPathId(bridgeNode);
+
+        if (hop == firstHop) {
+            LOG.info("handleSff: first hop processing {} - {}",
+                    bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
+            NshUtils nshHeader = new NshUtils();
+            nshHeader.setNshNsp(rsp.getPathId());
+            nshHeader.setNshNsi(firstHop.getServiceIndex());
+            Ip sffIp = sfcUtils.getSffIp(lastHop.getServiceFunctionForwarder());
+            nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(sffIp.getIp().getIpv4Address()));
+            if (isSffOnBridge(bridgeNode, serviceFunctionForwarder)) {
+                LOG.info("handleSff: sff and bridge are the same: {} - {}, skipping first sff",
+                        bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
+                Ip ip = sfcUtils.getSfIp(serviceFunction);
+                nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(ip.getPort());
+                sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
+                        rsp.getPathId(), rsp.getStartingIndex(),
+                        nshHeader, 0, rsp.getName().getValue(), true);
+            } else {
+                LOG.info("handleSff: sff and bridge are not the same: {} - {}, sending to first sff",
+                        bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
+                Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
+                nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(ip.getPort());
+                sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
+                        rsp.getPathId(), rsp.getStartingIndex(),
+                        nshHeader, vxGpeOfPort, rsp.getName().getValue(), true);
+            }
+        } else if (hop == lastHop) {
+            LOG.info("handleSff: last hop processing {} - {}",
+                    bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
+            short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+            String sfDplPortName = sfcUtils.getSfDplPortId(serviceFunction);
+            long sfOfPort = getSfPort(bridgeNode, sfDplPortName);
+            // TODO: Coexistence: SFC flows should take this using new egressTable REST
+            sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
+            // TODO: Coexistence: This flow should like like one above, change port, add reg0=1, resubmit
+            sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
+        } else {
+            // add typical sff flows
+        }
+
+        // TODO: Coexistence: SFC flows should take this using new tableOffset REST
+        //sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
+    }
+
+    void handleSf(Node bridgeNode, ServiceFunction serviceFunction, RenderedServicePath rsp) {
+        if (isSfOnBridge(bridgeNode, serviceFunction)) {
+            LOG.info("handleSf: sf and bridge are on the same node: {} - {}, adding workaround and arp",
+                    bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
+            long dataPathId = southbound.getDataPathId(bridgeNode);
+            Ip ip = sfcUtils.getSfIp(serviceFunction);
+            String sfIpAddr = String.valueOf(ip.getIp().getValue());
+            int sfIpPort = ip.getPort().getValue(); //GPE_PORT
+            String sfDplPortName = sfcUtils.getSfDplPortId(serviceFunction);
+            long sfOfPort = getSfPort(bridgeNode, sfDplPortName);
+            String sfMac = getMacFromExternalIds(bridgeNode, sfDplPortName);
+            if (sfMac == null) {
+                LOG.warn("handleSff: could not find mac for {} on {}", sfDplPortName, bridgeNode);
+                return;
+            }
+            //should be sffdplport, but they should all be the same 6633/4790
+            // TODO: Coexistence: SFC flows should take this using new sf dpl augmentation
+            if (addSfFlows == true) {
+                sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, rsp.getName().getValue(), true);
+                sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplPortName,
+                        rsp.getName().getValue(), true);
+            }
+            sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr,
+                    rsp.getName().getValue(), true);
+        } else {
+            LOG.info("handleSf: sf and bridge are not on the same node: {} - {}, do nothing",
+                    bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
+        }
+    }
+
+    private boolean isSffOnBridge(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder) {
+        String localIp = "";
+        Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
+        Node ovsdbNode = southbound.readOvsdbNode(bridgeNode);
+        if (ovsdbNode != null) {
+            localIp = getLocalip(ovsdbNode);
+        }
+        LOG.info("isSffOnBridge: {}: {}, localIp: {}, sff ip: {}",
+                bridgeNode.getNodeId().getValue(),
+                localIp.equals(String.valueOf(ip.getIp().getValue())),
+                localIp, ip.getIp().getValue());
+        return localIp.equals(String.valueOf(ip.getIp().getValue()));
+    }
+
+    private String getLocalip(Node ovsdbNode) {
+        Preconditions.checkNotNull(ovsdbNode, "The ovsdbNode was null");
+        String localIp = null;
+        if (ovsdbNode != null) {
+            OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+            if (ovsdbNodeAugmentation != null && ovsdbNodeAugmentation.getOpenvswitchOtherConfigs() != null) {
+                localIp = southbound.getOtherConfig(ovsdbNode, OvsdbTables.OPENVSWITCH, TUNNEL_ENDPOINT_KEY);
+            }
+        }
+        if (localIp == null) {
+            LOG.warn("local_ip was not found for node: {}", ovsdbNode);
+            localIp = "";
+        }
+        return localIp;
+    }
+
+    private boolean isSfOnBridge(Node bridgeNode, ServiceFunction serviceFunction) {
+        String sfDplPortName = sfcUtils.getSfDplPortId(serviceFunction);
+        long sfOfPort = getSfPort(bridgeNode, sfDplPortName);
+        LOG.info("isSfOnBridge: {}: {}, sfOfPort: {}", bridgeNode.getNodeId().getValue(), sfOfPort != 0L, sfOfPort);
+        return sfOfPort != 0L;
+    }
+
+    private Ace getAceFromRenderedServicePath(RenderedServicePath rsp) {
+        Preconditions.checkNotNull(rsp, "RSP cannot be null");
+        Ace ace;
+        //String rspName = rsp.getName().getValue();
+        //String rspNameSuffix = "_rsp";
+        //String sfcName = rspName.substring(0, rspName.length() - rspNameSuffix.length());
+        //String sfcName = rsp.getServiceChainName().getValue()
+        //LOG.info("getAceFromRenderedServicePath: rsp: {}, sfcName: {}", rsp, sfcName);
+        ace = sfcUtils.getAce(rsp);
+
+        return ace;
+    }
+
+    private RenderedServicePath getRenderedServicePath (Ace entry) {
+        RenderedServicePath rsp = null;
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("getRenderedServicePath: Processing ACL entry = {} sfcRedirect = {}",
+                entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("getRenderedServicePath: sfcRedirect is null");
+            return null;
+        }
+
+        if (sfcRedirect.getRspName() != null) {
+            rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
+        } else if (sfcRedirect.getSfpName() != null) {
+            LOG.warn("getRenderedServicePath: by sfp not handled yet");
+        } else {
+            rsp = getRenderedServicePathFromSfc(entry);
+        }
+        LOG.info("getRenderedServicePath: rsp: {}", rsp);
+        return rsp;
+    }
+
+    private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
+        return sfcUtils.getRsp(rspName);
+    }
+
+    private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("getRenderedServicePathFromSfc: Processing ACL entry = {} sfcRedirect = {}",
+                entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("getRenderedServicePathFromSfc: sfcRedirect is null");
+            return null;
+        }
+
+        String sfcName = sfcRedirect.getSfcName();
+        ServiceFunctionPath sfp = sfcUtils.getSfp(sfcName);
+        if (sfp == null || sfp.getName() == null) {
+            LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
+            return null;
+        }
+
+        LOG.debug("getRenderedServicePathFromSfc: Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
+        // If RSP doesn't exist, create an RSP.
+        String sfpName = sfp.getName().getValue();
+        RenderedServicePath rsp = sfcUtils.getRspforSfp(sfpName);
+        String rspName = sfp.getName().getValue() + "_rsp";
+        if (rsp == null) {
+            if (!sfcRedirect.isRenderRsp()) {
+                LOG.info("getRenderedServicePathFromSfc: will not create RSP");
+                return null;
+            }
+            LOG.info("getRenderedServicePathFromSfc: No configured RSP corresponding to SFP = {}, "
+                    + "Creating new RSP = {}", sfpName, rspName);
+            CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
+                    .setParentServiceFunctionPath(sfpName)
+                    .setName(rspName)
+                    .setSymmetric(sfp.isSymmetric())
+                    .build();
+            rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
+            if (rsp == null) {
+                LOG.warn("getRenderedServicePathFromSfc: failed to add RSP");
+                return null;
+            }
+
+            // If SFP is symmetric, create RSP in the reverse direction.
+            if (sfp.isSymmetric()) {
+                LOG.warn("getRenderedServicePathFromSfc: symmetric RSP is not supported yet");
+                /*LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
+                String rspNameRev = rspName + "-Reverse";
+                RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
+                        sfcUtils.getRspId(rspNameRev));
+                if (rspReverse == null) {
+                    rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
+                    if (rspReverse == null) {
+                        LOG.warn("failed to add reverse RSP");
+                        return null;
+                    }
+                }*/
+            }
+        }
+        return rsp;
+    }
+
+    private long getSfPort(Node bridgeNode, String sfPortName) {
+        return getOFPort(bridgeNode, sfPortName);
+    }
+
+    private long getOFPort(Node bridgeNode, String portName) {
+        long ofPort = 0L;
+        OvsdbTerminationPointAugmentation port =
+                southbound.extractTerminationPointAugmentation(bridgeNode, portName);
+        if (port != null) {
+            ofPort = southbound.getOFPort(port);
+        }
+        if (ofPort == 0L) {
+            for (int i = 0; i < 5; i++) {
+                LOG.info("Looking for ofPort {}, try: {}", portName, i);
+                TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
+                if (tp != null) {
+                    port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                    if (port != null) {
+                        ofPort = southbound.getOFPort(port);
+                        LOG.info("found ofPort {} - {}, try: {}", portName, ofPort, i);
+                        break;
+                    }
+                }
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.error("Interrupted while waiting for ofPort {}", portName, e);
+                }
+            }
+        }
+        return ofPort;
+    }
+
+    private String getMacFromExternalIds(Node bridgeNode, String portName) {
+        String mac = null;
+        OvsdbTerminationPointAugmentation port = southbound.getTerminationPointOfBridge(bridgeNode, portName);
+        LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
+        if (port != null && port.getInterfaceExternalIds() != null) {
+            mac = southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_VM_MAC);
+        }
+        return mac;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        sfcClassifierService =
+                (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
+        LOG.info("sfcClassifierService= {}", sfcClassifierService);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclMatches.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclMatches.java
new file mode 100644 (file)
index 0000000..475ffc8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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.openstack.netvirt.sfc.workaround.services;
+
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.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.rev150317.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.rev150317.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.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AclMatches {
+    private static final Logger LOG = LoggerFactory.getLogger(AclMatches.class);
+    MatchBuilder matchBuilder;
+    Matches matches;
+
+    public AclMatches(Matches matches) {
+        matchBuilder = new MatchBuilder();
+        this.matches = matches;
+    }
+
+    /**
+     * Convert the ACL into an OpenFlow {@link MatchBuilder}
+     * @return {@link MatchBuilder}
+     */
+    //TODO: Matches will overwrite previous matches for ethernet and ip since these methods
+    // can be called successively for the same ACL.
+    // This requires fixing the MatchUtils to preserve previously set fields.
+    protected MatchBuilder buildMatch() {
+        if (matches.getAceType() instanceof AceEth) {
+            addEthMatch();
+        } else if (matches.getAceType() instanceof AceIp) {
+            addIpMatch();
+        }
+
+        LOG.info("buildMatch: {}", matchBuilder.build());
+        return matchBuilder;
+    }
+
+    private void addEthMatch() {
+        AceEth aceEth = (AceEth) matches.getAceType();
+        MatchUtils.createEthSrcDstMatch(matchBuilder, aceEth.getSourceMacAddress(),
+                aceEth.getDestinationMacAddress());
+    }
+
+    private void addIpMatch() {
+        AceIp aceIp = (AceIp)matches.getAceType();
+
+        if (aceIp.getDscp() != null) {
+            MatchUtils.addDscp(matchBuilder, aceIp.getDscp().getValue());
+        }
+
+        if (aceIp.getProtocol() != null) {
+            addIpProtocolMatch(aceIp);
+        }
+
+        if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+            addIpV4Match(aceIp);
+        }
+
+        if (aceIp.getAceIpVersion() instanceof AceIpv6) {
+            addIpV6Match(aceIp);
+        }
+    }
+
+    private void addIpProtocolMatch(AceIp aceIp) {
+        int srcPort = 0;
+        int dstPort = 0;
+
+        // TODO Ranges are not supported yet
+        if (aceIp.getSourcePortRange() != null && aceIp.getSourcePortRange().getLowerPort() != null) {
+            srcPort = aceIp.getSourcePortRange().getLowerPort().getValue();
+        }
+        if (aceIp.getDestinationPortRange() != null && aceIp.getDestinationPortRange().getLowerPort() != null) {
+            dstPort = aceIp.getDestinationPortRange().getLowerPort().getValue();
+        }
+        MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+        MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), srcPort, dstPort);
+    }
+
+    private void addIpV4Match(AceIp aceIp) {
+        AceIpv4 aceIpv4 = (AceIpv4)aceIp.getAceIpVersion();
+
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(MatchUtils.ETHERTYPE_IPV4));
+        matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, aceIpv4.getSourceIpv4Network(),
+                aceIpv4.getDestinationIpv4Network());
+    }
+
+    private void addIpV6Match(AceIp aceIp) {
+        AceIpv6 aceIpv6 = (AceIpv6)aceIp.getAceIpVersion();
+
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(MatchUtils.ETHERTYPE_IPV6));
+        matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder, aceIpv6.getSourceIpv6Network(),
+                aceIpv6.getDestinationIpv6Network());
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclUtils.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclUtils.java
new file mode 100644 (file)
index 0000000..eefced6
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.openstack.netvirt.sfc.workaround.services;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.PermitBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.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.rev150317.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.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.DestinationPortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.SourcePortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfcBuilder;
+
+public class AclUtils {
+    private static final String ACLNAME= "httpAcl";
+    private static final String RULENAME= "httpRule";
+    private static final String SFCNAME = "SFC";
+
+    public MatchesBuilder matchesBuilder(MatchesBuilder matchesBuilder, int dstPort) {
+        SourcePortRangeBuilder sourcePortRangeBuilder = new SourcePortRangeBuilder()
+                .setLowerPort(PortNumber.getDefaultInstance("0"))
+                .setUpperPort(PortNumber.getDefaultInstance("0"));
+
+        PortNumber portNumber = new PortNumber(dstPort);
+        DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder()
+                .setLowerPort(portNumber)
+                .setUpperPort(portNumber);
+
+        AceIpBuilder aceIpBuilder = new AceIpBuilder()
+                .setSourcePortRange(sourcePortRangeBuilder.build())
+                .setDestinationPortRange(destinationPortRangeBuilder.build())
+                .setProtocol((short)6);
+
+        return matchesBuilder.setAceType(aceIpBuilder.build());
+    }
+
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, Boolean permit) {
+        return actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(permit).build());
+    }
+
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, String sfcName, boolean renderRsp) {
+        RedirectToSfcBuilder redirectToSfcBuilder = new RedirectToSfcBuilder()
+                .setSfcName(sfcName)
+                .setRenderRsp(renderRsp);
+
+        return actionsBuilder.addAugmentation(RedirectToSfc.class, redirectToSfcBuilder.build());
+    }
+
+    public AceBuilder aceBuilder(AceBuilder accessListEntryBuilder,
+                                 String ruleName,
+                                 MatchesBuilder matchesBuilder,
+                                 ActionsBuilder actionsBuilder) {
+        return accessListEntryBuilder
+                .setRuleName(ruleName)
+                .setMatches(matchesBuilder.build())
+                .setActions(actionsBuilder.build());
+    }
+
+    public AccessListEntriesBuilder accessListEntriesBuidler(AccessListEntriesBuilder accessListEntriesBuilder,
+                                                             AceBuilder aceBuilder) {
+        List<Ace> aceList = new ArrayList<>();
+        aceList.add(aceBuilder.build());
+
+        return accessListEntriesBuilder.setAce(aceList);
+    }
+
+    public AclBuilder aclBuilder(AclBuilder aclBuilder,
+                                 String aclName,
+                                 AccessListEntriesBuilder accessListEntriesBuilder) {
+        return aclBuilder
+                .setAclName(aclName)
+                .setAccessListEntries(accessListEntriesBuilder.build());
+    }
+
+    public AccessListsBuilder accessListsbuilder(AccessListsBuilder accessListsBuilder,
+                                                 AclBuilder aclBuilder) {
+        List<Acl> aclList = new ArrayList<>();
+        aclList.add(aclBuilder.build());
+
+        return accessListsBuilder.setAcl(aclList);
+    }
+
+    public AccessListsBuilder accessListsBuilder(boolean renderRsp) {
+        String ruleName = RULENAME;
+        String sfcName = SFCNAME;
+        MatchesBuilder matchesBuilder = matchesBuilder(new MatchesBuilder(), 80);
+        ActionsBuilder actionsBuilder = actionsBuilder(new ActionsBuilder(), sfcName, renderRsp);
+        AceBuilder accessListEntryBuilder =
+                aceBuilder(new AceBuilder(), ruleName, matchesBuilder, actionsBuilder);
+        AccessListEntriesBuilder accessListEntriesBuilder =
+                accessListEntriesBuidler(new AccessListEntriesBuilder(), accessListEntryBuilder);
+        AclBuilder accessListBuilder =
+                aclBuilder(new AclBuilder(), ACLNAME, accessListEntriesBuilder);
+        AccessListsBuilder accessListsBuilder =
+                accessListsbuilder(new AccessListsBuilder(), accessListBuilder);
+        return accessListsBuilder;
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/FlowCache.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/FlowCache.java
new file mode 100644 (file)
index 0000000..f546e56
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.workaround.services;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCache {
+    private static final Logger LOG = LoggerFactory.getLogger(FlowCache.class);
+    private Map<String, Map<Integer, InstanceIdentifier<Flow>>> flowCache = new HashMap<>();
+
+    public void addFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, int flowId) {
+        Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.get(rspName);
+        if (flowMap == null) {
+            LOG.info("addFlow: adding new flowMap for {}({})", rspName, flowId);
+            flowMap = new HashMap<>();
+        }
+        InstanceIdentifier<Flow> path = FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
+        flowMap.put(flowId, path);
+        flowCache.put(rspName, flowMap);
+        LOG.info("addFlow: added {}({}) {} to cache size {} - {}", rspName, flowId, path,
+                flowCache.size(), flowCache);
+    }
+
+    public void removeFlow(String rspName, int flowId) {
+        Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.get(rspName);
+        if (flowMap != null) {
+            flowMap.remove(flowId);
+            if (flowMap.isEmpty()) {
+                flowCache.remove(rspName);
+                LOG.info("removeFlow: removed flowMap {}({}) from cache size {}", rspName, flowId,
+                        flowCache.size());
+            } else {
+                flowCache.put(rspName, flowMap);
+            }
+        }
+        LOG.info("removeFlow: removed {}({}) from cache size {}", rspName, flowId, flowCache.size());
+    }
+
+    public Map<Integer, InstanceIdentifier<Flow>> getFlows(String rspName) {
+        return flowCache.get(rspName);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/FlowNames.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/FlowNames.java
new file mode 100644 (file)
index 0000000..b741b2c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.workaround.services;
+
+public class FlowNames {
+
+    public static String getSfcIngressClass(String ruleName, long nsp, short nsi) {
+        return "sfcIngressClass_" + nsp + "_" + nsi + "_" + ruleName;
+    }
+
+    public static String getSfcTable(long vxGpeOfPort) {
+        return "sfcTable_" + vxGpeOfPort;
+    }
+
+    public static String getSfcEgressClass1(long vxGpeOfPort) {
+        return "sfcEgressClass1_" + vxGpeOfPort;
+    }
+
+    public static String getSfcEgressClass(long vxGpeOfPort, long nsp, short nsi) {
+        return "sfcEgressClass_" + nsp + "_" + nsi + "_" + vxGpeOfPort;
+    }
+
+    public static String getSfcEgressClassBypass(long nsp, short nsi, long sfOfPort) {
+        return "sfcEgressClassBypass_" + nsp + "_" + nsi + "_"  + sfOfPort;
+    }
+
+    public static String getSfEgress(int dstPort) {
+        return "sfEgress_" + dstPort;
+    }
+
+    public static String getSfIngress(int dstPort, String ipAddress) {
+        return "sfIngress_" + dstPort + "_" + ipAddress;
+    }
+
+    public static String getArpResponder(String ipAddress) {
+        return "ArpResponder_" + ipAddress;
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java
new file mode 100644 (file)
index 0000000..7edb9fd
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.workaround.services;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
+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.apply.actions._case.ApplyActionsBuilder;
+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.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
+    private static final short UDP_SHORT = 17;
+    static int cookieIndex = 0;
+    private FlowCache flowCache = new FlowCache();
+
+    private enum FlowID {
+        FLOW_INGRESSCLASS(1), FLOW_SFINGRESS(2), FLOW_SFEGRESS(3), FLOW_SFARP(4),
+        FLOW_EGRESSCLASSUNUSED(5), FLOW_EGRESSCLASS(6), FLOW_EGRESSCLASSBYPASS(7), FLOW_SFCTABLE(8);
+
+        private int value;
+        FlowID(int value) {
+            this.value = value;
+        }
+    }
+
+    private BigInteger getCookie(FlowID flowID) {
+        String cookieString = String.format("1110%02d%010d", flowID.value, cookieIndex++);
+        return new BigInteger(cookieString, 16);
+    }
+
+    private BigInteger getCookie(FlowID flowID, short nsp, short nsi) {
+        String cookieString = String.format("1110%02d%03d%03d0%03d", flowID.value, 0, nsp, nsi);
+        return new BigInteger(cookieString, 16);
+    }
+
+    public SfcClassifierService(Service service) {
+        super(service);
+    }
+
+    public SfcClassifierService() {
+        super(Service.SFC_CLASSIFIER);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(ISfcClassifierService.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+
+    private FlowBuilder initFlowBuilder(FlowBuilder flowBuilder, String flowName, short table, FlowID flowID) {
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, table)
+                .setCookie(new FlowCookie(getCookie(flowID)))
+                .setCookieMask(new FlowCookie(getCookie(flowID)));
+        return flowBuilder;
+    }
+
+    private FlowBuilder initFlowBuilder(FlowBuilder flowBuilder, String flowName, short table, FlowID flowID,
+                                        short nsp, short nsi) {
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, table)
+                .setCookie(new FlowCookie(getCookie(flowID, nsp, nsi)))
+                .setCookieMask(new FlowCookie(getCookie(flowID, nsp, nsi)));
+        return flowBuilder;
+    }
+
+    private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
+        flowCache.addFlow(flowBuilder, nodeBuilder, rspName, flowID.value);
+        writeFlow(flowBuilder, nodeBuilder);
+    }
+
+    private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
+        flowCache.removeFlow(rspName, flowID.value);
+        removeFlow(flowBuilder, nodeBuilder);
+    }
+
+    @Override
+    public void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
+                                         NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfcIngressClass(ruleName, nsp, nsi);
+        initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_INGRESSCLASS,
+                (short)nshHeader.getNshNsp(), nshHeader.getNshNsi());
+
+        MatchBuilder matchBuilder = new AclMatches(matches).buildMatch();
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            ActionBuilder ab = new ActionBuilder();
+            List<Action> actionList = new ArrayList<>();
+
+            ab.setAction(ActionUtils.nxMoveTunIdtoNshc2());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            getNshAction(nshHeader, actionList);
+
+            if (vxGpeOfPort != 0) {
+                ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dataPathId, vxGpeOfPort)));
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+            } else {
+                ab.setAction(ActionUtils.nxResubmitAction(null, Service.CLASSIFIER.getTable()));
+                ab.setOrder(actionList.size());
+                ab.setKey(new ActionKey(actionList.size()));
+                actionList.add(ab.build());
+            }
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            List<Instruction> instructions = Lists.newArrayList();
+            instructions.add(ib.build());
+
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
+        }
+    }
+
+    @Override
+    public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfcTable(vxGpeOfPort);
+        initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_SFCTABLE)
+                .setPriority(1000);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib =
+                    InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                         int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfcEgressClass1(vxGpeOfPort);
+        initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_EGRESSCLASSUNUSED,
+                (short)nsp, nsi);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        MatchUtils.addNxNsiMatch(matchBuilder, nsi);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+
+            InstructionBuilder ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
+            ib.setOrder(instructions.size());
+            ib.setKey(new InstructionKey(instructions.size()));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                        long sfOfPort, int tunnelId, String rspName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfcEgressClass(vxGpeOfPort, nsp, nsi);
+        initFlowBuilder(flowBuilder, flowName, getTable(Service.SFC_CLASSIFIER), FlowID.FLOW_EGRESSCLASS,
+                (short)nsp, nsi);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        MatchUtils.addNxNsiMatch(matchBuilder, nsi);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            List<Action> actionList = Lists.newArrayList();
+
+            ActionBuilder ab = new ActionBuilder();
+
+            ab.setAction(
+                    ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(FlowUtils.REG_FIELD).build(),
+                    BigInteger.valueOf(FlowUtils.REG_VALUE_FROM_LOCAL)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.nxMoveNshc2ToTunId());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.nxResubmitAction((int)sfOfPort, getTable(Service.CLASSIFIER)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
+        }
+    }
+
+    @Override
+    public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                              long sfOfPort, int tunnelId, String rspName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfcEgressClassBypass(nsp, nsi, sfOfPort);
+        initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER),
+                FlowID.FLOW_EGRESSCLASSBYPASS, (short)nsp, nsi)
+                .setPriority(40000);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, sfOfPort);
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        MatchUtils.addNxNsiMatch(matchBuilder, nsi);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+
+            InstructionBuilder ib;
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
+        }
+    }
+
+    // packet from sf to sff that need to go out local
+    @Override
+    public void program_sfEgress(long dataPathId, int dstPort, String rspName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfEgress(dstPort);
+        initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_SFEGRESS);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
+        MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionUtils.createLocalInstructions(ib, dataPathId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFEGRESS);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFEGRESS);
+        }
+    }
+
+    // looped back sff to sf packets
+    @Override
+    public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                                  String ipAddress, String sfDplName, String rspName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getSfIngress(dstPort, ipAddress);
+        initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(), FlowID.FLOW_SFINGRESS);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
+        Ipv4Prefix ipCidr = MatchUtils.iPv4PrefixFromIPv4Address(ipAddress);
+        MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(ipCidr));
+        MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionUtils.createOutputPortInstructions(ib, dataPathId, sfOfPort);
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFINGRESS);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFINGRESS);
+        }
+    }
+
+    @Override
+    public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                                      String ipAddress, String rspName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = FlowNames.getArpResponder(ipAddress);
+        initFlowBuilder(flowBuilder, flowName, getTable(Service.ARP_RESPONDER), FlowID.FLOW_SFARP)
+                .setPriority(1024);
+
+        MacAddress macAddress = new MacAddress(macAddressStr);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortReservedMatch(matchBuilder, dataPathId, OutputPortValues.LOCAL.toString());
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(Constants.ARP_ETHERTYPE));
+        MatchUtils.createArpDstIpv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<Action> actionList = Lists.newArrayList();
+
+            // Move Eth Src to Eth Dst
+            ab.setAction(ActionUtils.nxMoveEthSrcToEthDstAction());
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            // Set Eth Src
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Set ARP OP
+            ab.setAction(ActionUtils.nxLoadArpOpAction(BigInteger.valueOf(FlowUtils.ARP_OP_REPLY)));
+            ab.setOrder(2);
+            ab.setKey(new ActionKey(2));
+            actionList.add(ab.build());
+
+            // Move ARP SHA to ARP THA
+            ab.setAction(ActionUtils.nxMoveArpShaToArpThaAction());
+            ab.setOrder(3);
+            ab.setKey(new ActionKey(3));
+            actionList.add(ab.build());
+
+            // Move ARP SPA to ARP TPA
+            ab.setAction(ActionUtils.nxMoveArpSpaToArpTpaAction());
+            ab.setOrder(4);
+            ab.setKey(new ActionKey(4));
+            actionList.add(ab.build());
+
+            // Load Mac to ARP SHA
+            ab.setAction(ActionUtils.nxLoadArpShaAction(macAddress));
+            ab.setOrder(5);
+            ab.setKey(new ActionKey(5));
+            actionList.add(ab.build());
+
+            // Load IP to ARP SPA
+            ab.setAction(ActionUtils.nxLoadArpSpaAction(ipAddress));
+            ab.setOrder(6);
+            ab.setKey(new ActionKey(6));
+            actionList.add(ab.build());
+
+            // Output of InPort
+            ab.setAction(ActionUtils.outputAction(
+                    FlowUtils.getSpecialNodeConnectorId(dataPathId, OutputPortValues.INPORT.toString())));
+            ab.setOrder(7);
+            ab.setKey(new ActionKey(7));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
+        }
+    }
+
+    private List<Action> getNshAction(NshUtils header, List<Action> actionList) {
+        // Build the Actions to Add the NSH Header
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
+                ActionUtils.nxLoadNshc1RegAction(header.getNshMetaC1());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad =
+                ActionUtils.nxSetNspAction(header.getNshNsp());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad =
+                ActionUtils.nxSetNsiAction(header.getNshNsi());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
+                ActionUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshNsp()), false);
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
+                ActionUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false);
+
+        int count = actionList.size();
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(nshC1Load).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(nspLoad).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(nsiLoad).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(loadChainTunDest).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count).setAction(loadChainTunVnid).build());
+        return actionList;
+    }
+
+    private static FlowID flowSet[] = {FlowID.FLOW_INGRESSCLASS, FlowID.FLOW_EGRESSCLASS,
+            FlowID.FLOW_EGRESSCLASSBYPASS, FlowID.FLOW_SFARP, FlowID.FLOW_SFINGRESS, FlowID.FLOW_SFEGRESS};
+
+    @Override
+    public void clearFlows(DataBroker dataBroker, String rspName) {
+        Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.getFlows(rspName);
+        if (flowMap != null) {
+            for (FlowID flowID : flowSet) {
+                InstanceIdentifier<Flow> path = flowMap.get(flowID.value);
+                if (path != null) {
+                    flowCache.removeFlow(rspName, flowID.value);
+                    removeFlow(dataBroker, path);
+                }
+            }
+        }
+    }
+
+    private void removeFlow(DataBroker dataBroker, InstanceIdentifier<Flow> path) {
+        WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
+        modification.delete(LogicalDatastoreType.CONFIGURATION, path);
+
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+        try {
+            commitFuture.get();  // TODO: Make it async (See bug 1362)
+            LOG.debug("Transaction success for deletion of Flow {}", path);
+        } catch (Exception e) {
+            LOG.error("Failed to remove flow {}", path, e);
+            modification.cancel();
+        }
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModule.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModule.java
new file mode 100644 (file)
index 0000000..343d528
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210;
+
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NetvirtSfcProvider;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtSfcImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210.AbstractNetvirtSfcImplModule {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcImplModule.class);
+    private BundleContext bundleContext;
+
+    public NetvirtSfcImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetvirtSfcImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210.NetvirtSfcImplModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        LOG.info("Netvirt SFC module initialization.");
+        NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider(bundleContext);
+        sfcProvider.setOf13Provider(getOf13provider());
+        sfcProvider.setAddSfFlows(getAddsfflows());
+        getBrokerDependency().registerProvider(sfcProvider);
+        return sfcProvider;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleFactory.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleFactory.java
new file mode 100644 (file)
index 0000000..badc825
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+public class NetvirtSfcImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210.AbstractNetvirtSfcImplModuleFactory {
+
+    @Override
+    public NetvirtSfcImplModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
+                                                  BundleContext bundleContext) {
+        NetvirtSfcImplModule module = super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public NetvirtSfcImplModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
+                                                  NetvirtSfcImplModule oldModule, AutoCloseable oldInstance,
+                                                  BundleContext bundleContext) {
+        NetvirtSfcImplModule module = super.instantiateModule(instanceName, dependencyResolver,
+                oldModule, oldInstance, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/yang/netvirt-sfc-impl.yang b/openstack/net-virt-sfc/impl/src/main/yang/netvirt-sfc-impl.yang
new file mode 100644 (file)
index 0000000..fedcd9e
--- /dev/null
@@ -0,0 +1,43 @@
+module netvirt-sfc-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:sfc:impl";
+    prefix "netvirt-sfc-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28;}
+
+    description
+        "Service definition for netvirt sfc project";
+
+    revision "2014-12-10" {
+        description
+            "Initial revision";
+    }
+
+    identity netvirt-sfc-impl {
+        base config:module-type;
+        config:java-name-prefix NetvirtSfcImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netvirt-sfc-impl {
+            when "/config:modules/config:module/config:type = 'netvirt-sfc-impl'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-broker-osgi-registry;
+                    }
+                }
+            }
+
+            leaf of13provider {
+                type string;
+            }
+
+            leaf addsfflows {
+                type boolean;
+            }
+        }
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclMatchesTest.java b/openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/workaround/services/AclMatchesTest.java
new file mode 100644 (file)
index 0000000..f6f1c1a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.openstack.netvirt.sfc.workaround.services;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+
+public class AclMatchesTest {
+    @Test
+    public void buildMatchTest() {
+        AclUtils aclUtils = new AclUtils();
+        MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
+        AclMatches aclMatches = new AclMatches(matchesBuilder.build());
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createIpProtocolMatch(matchBuilder, (short)6);
+        MatchUtils.addLayer4Match(matchBuilder, 6, 0, 80);
+        assertEquals(matchBuilder.build(), aclMatches.buildMatch().build());
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleFactoryTest.java b/openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleFactoryTest.java
new file mode 100644 (file)
index 0000000..612a459
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2015 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210;
+
+import org.junit.Test;
+
+public class NetvirtSfcImplModuleFactoryTest {
+    @Test
+    public void testFactoryConstructor() {
+        // ensure no exceptions on construction
+        new NetvirtSfcImplModuleFactory();
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleTest.java b/openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/impl/rev141210/NetvirtSfcImplModuleTest.java
new file mode 100644 (file)
index 0000000..116278b
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2015, 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.impl.rev141210;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Dictionary;
+
+import javax.management.ObjectName;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NetvirtSfcProvider;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.standalone.openflow13.services.SfcClassifierService;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+public class NetvirtSfcImplModuleTest {
+    @Test
+    public void testCustomValidation() {
+        NetvirtSfcImplModule module = new NetvirtSfcImplModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class));
+        // ensure no exceptions on validation
+        // currently this method is empty
+        module.customValidation();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testCreateInstance() throws Exception {
+        // configure mocks
+        DependencyResolver dependencyResolver = mock(DependencyResolver.class);
+        BindingAwareBroker broker = mock(BindingAwareBroker.class);
+        ProviderContext session = mock(ProviderContext.class);
+        DataBroker dataBroker = mock(DataBroker.class);
+        when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class),
+                any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
+        when(session.getSALService(eq(DataBroker.class))).thenReturn(dataBroker);
+
+        // create instance of module with injected mocks
+        NetvirtSfcImplModule module = new NetvirtSfcImplModule(mock(ModuleIdentifier.class), dependencyResolver);
+        // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+        BundleContext bundleContext = mock(BundleContext.class);
+        PipelineOrchestrator pipelineOrchestrator = mock(PipelineOrchestrator.class);
+        ServiceHelper.overrideGlobalInstance(PipelineOrchestrator.class, pipelineOrchestrator);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, mock(Southbound.class));
+
+        doNothing().when(pipelineOrchestrator).registerService(any(ServiceReference.class),
+                any(AbstractServiceInstance.class));
+        when(bundleContext.registerService(
+                eq(new String[]{AbstractServiceInstance.class.getName(), SfcClassifierService.class.getName()}),
+                any(),
+                any(Dictionary.class)))
+                .thenReturn(mock(ServiceRegistration.class));
+        when(bundleContext.getServiceReference(SfcClassifierService.class.getName()))
+                .thenReturn(mock(ServiceReference.class));
+        AutoCloseable closeable = module.getInstance();
+        ((NetvirtSfcProvider)closeable).setBundleContext(bundleContext);
+        ((NetvirtSfcProvider)closeable).setOf13Provider("standalone");
+        ((NetvirtSfcProvider)closeable).setAddSfFlows(false);
+        ((NetvirtSfcProvider)closeable).onSessionInitiated(session);
+        // verify that the module registered the returned provider with the broker
+        verify(broker).registerProvider((NetvirtSfcProvider)closeable);
+
+        // ensure no exceptions on close
+        closeable.close();
+    }
+}
diff --git a/openstack/net-virt-sfc/it/pom.xml b/openstack/net-virt-sfc/it/pom.xml
new file mode 100644 (file)
index 0000000..850a59c
--- /dev/null
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.netvirt</groupId>
+    <artifactId>it</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath>../../../commons/it</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-it</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <properties>
+    <karaf.distro.groupId>org.opendaylight.netvirt</karaf.distro.groupId>
+    <karaf.distro.artifactId>openstack.net-virt-sfc-karaf</karaf.distro.artifactId>
+    <karaf.distro.version>${project.version}</karaf.distro.version>
+    <karaf.distro.type>zip</karaf.distro.type>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+   </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>openstack.net-virt-sfc-artifacts</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-features</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-impl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-providers</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.southbound-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.netvirt-it-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.ovsdb-it-utils</artifactId>
+      <version>${ovsdb.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>concepts</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar-plugins.java</groupId>
+      <artifactId>sonar-jacoco-listeners</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <configuration>
+        <!--  <excludes>
+            <exclude>**/NetvirtSfcIT.java</exclude>
+          </excludes>-->
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/NetvirtSfcIT.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/NetvirtSfcIT.java
new file mode 100644 (file)
index 0000000..0e45960
--- /dev/null
@@ -0,0 +1,912 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it;
+
+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 static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
+import static org.ops4j.pax.exam.CoreOptions.when;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.AclUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.ClassifierUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.RenderedServicePathUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.ServiceFunctionChainUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.ServiceFunctionPathUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.ServiceFunctionUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.SfcConfigUtils;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.SfcUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.standalone.openflow13.SfcClassifier;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.NetvirtConfigUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.ServiceFunctionForwarderUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.it.utils.NetvirtSfcUtils;
+import org.opendaylight.netvirt.openstack.netvirt.sfc.workaround.services.FlowNames;
+import org.opendaylight.netvirt.utils.netvirt.it.utils.NetvirtItUtils;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.utils.ovsdb.it.utils.OvsdbItUtils;
+import org.opendaylight.ovsdb.utils.ovsdb.it.utils.NodeInfo;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.ovsdb.utils.mdsal.utils.NotifyingDataChangeListener;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+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.SftType;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+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.sf.rev140701.ServiceFunctions;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctionsBuilder;
+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.sfc.rev140701.ServiceFunctionChains;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChainsBuilder;
+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.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.sff.rev140701.ServiceFunctionForwarders;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwardersBuilder;
+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.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsBuilder;
+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.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfig;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.NetvirtProvidersConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.NetvirtProvidersConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.SffsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.SffBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.Sfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
+import org.ops4j.pax.exam.options.MavenUrlReference;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Maps;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class NetvirtSfcIT extends AbstractMdsalTestBase {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcIT.class);
+    private static AclUtils aclUtils = new AclUtils();
+    private static ClassifierUtils classifierUtils = new ClassifierUtils();
+    private static NetvirtSfcUtils netvirtSfcUtils = new NetvirtSfcUtils();
+    private static ServiceFunctionUtils serviceFunctionUtils = new ServiceFunctionUtils();
+    private static ServiceFunctionForwarderUtils serviceFunctionForwarderUtils = new ServiceFunctionForwarderUtils();
+    private static ServiceFunctionChainUtils serviceFunctionChainUtils = new ServiceFunctionChainUtils();
+    private static ServiceFunctionPathUtils serviceFunctionPathUtils = new ServiceFunctionPathUtils();
+    private static RenderedServicePathUtils renderedServicePathUtils = new RenderedServicePathUtils();
+    private static SfcConfigUtils sfcConfigUtils = new SfcConfigUtils();
+    private static NetvirtConfigUtils netvirtConfigUtils = new NetvirtConfigUtils();
+    private static MdsalUtils mdsalUtils;
+    private static AtomicBoolean setup = new AtomicBoolean(false);
+    private static SouthboundUtils southboundUtils;
+    private static SfcUtils sfcUtils;
+    private static String addressStr;
+    private static String portStr;
+    private static String connectionType;
+    private static String controllerStr;
+    private static boolean ovsdb_wait = false;
+    private static String userSpaceEnabled = "no";
+    private static PipelineOrchestrator pipelineOrchestrator;
+    private static Southbound southbound;
+    private static DataBroker dataBroker;
+    private static OvsdbItUtils itUtils;
+    private static NetvirtItUtils nvItUtils;
+    public static final String CONTROLLER_IPADDRESS = "ovsdb.controller.address";
+    public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
+    public static final String SERVER_PORT = "ovsdbserver.port";
+    public static final String CONNECTION_TYPE = "ovsdbserver.connection";
+    public static final String CONNECTION_TYPE_ACTIVE = "active";
+    public static final String CONNECTION_TYPE_PASSIVE = "passive";
+    public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String USERSPACE_ENABLED = "ovsdb.userspace.enabled";
+    public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+    private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
+    private static final String OVSDB_TRACE = "ovsdb.trace";
+    private static final String OVSDB_WAIT = "ovsdb.wait";
+    private static final String SF1NAME = "firewall-72";
+    private static final String SF2NAME = "dpi-72";
+    private static final String SF1IP = "10.2.1.1";//"192.168.50.70";//"192.168.120.31";
+    private static final String SF2IP = "10.2.1.2";
+    private static final String SF1DPLNAME = "sf1";
+    private static final String SF2DPLNAME = "sf2";
+    private static final String SF1DPLPORTNAME = "tap-123456789ab";
+    // Use 192.168.50.70 when running against vagrant vm for workaround testing, eg. netvirtsfc-env.
+    // Use 192.168.1.129 (or whatever address is dhcp'ed) for tacker-vm.
+    // "192.168.50.70"; "127.0.0.1"; "192.168.1.129";
+    private static final String SFF1IP = "192.168.50.70";
+    private static final String SFF2IP = "127.0.0.1";
+    private static final String SFF1NAME = "sff1";
+    private static final String SFF2NAME = "sff2";
+    private static final String SFFDPL1NAME = "vxgpe";
+    private static final String SFFDPL2NAME = "vxgpe";
+    private static final String SN1NAME = "ovsdb1";
+    private static final String SN2NAME = "ovsdb2";
+    private static final String BRIDGE1NAME= "br-int";
+    private static final String BRIDGE2NAME= "br-int";
+    private static final String ACLNAME= "httpAcl";
+    private static final String RULENAME= "httpRule";
+    private static final String SFCNAME = "SFC";
+    private static final String SFCPATH = "SFC-Path";
+    private static final String RSPNAME = SFCPATH + "_rsp";
+    private static final String SFCSF1NAME = "firewall-abstract";
+    private static final SftType SFCSF1TYPE = new SftType("firewall");
+    private static final int GPEUDPPORT = 6633;
+
+    @Override
+    public String getModuleName() {
+        return "netvirt-sfc-impl";
+    }
+
+    @Override
+    public String getInstanceName() {
+        return "netvirt-sfc-impl";
+    }
+
+    @Override
+    public MavenUrlReference getFeatureRepo() {
+        return maven()
+                .groupId("org.opendaylight.netvirt")
+                .artifactId("openstack.net-virt-sfc-features")
+                .classifier("features")
+                .type("xml")
+                .versionAsInProject();
+    }
+
+    @Override
+    public String getFeatureName() {
+        return "odl-ovsdb-sfc-test";
+    }
+
+    @Configuration
+    @Override
+    public Option[] config() {
+        Option[] parentOptions = super.config();
+        Option[] propertiesOptions = getPropertiesOptions();
+        Option[] otherOptions = getOtherOptions();
+        Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
+        System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
+        System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
+        System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
+                otherOptions.length);
+        return options;
+    }
+
+    private Option[] getOtherOptions() {
+        return new Option[] {
+                wrappedBundle(
+                        mavenBundle("org.opendaylight.netvirt", "utils.mdsal-openflow")
+                                .version(asInProject())
+                                .type("jar")),
+                configureConsole().startLocalConsole(),
+                //vmOption("-verbose:class"),
+                vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
+                keepRuntimeFolder()
+        };
+    }
+
+    public Option[] getPropertiesOptions() {
+        return new Option[] {
+                propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE,
+                        CONTROLLER_IPADDRESS, OVSDB_TRACE, OVSDB_WAIT, USERSPACE_ENABLED),
+        };
+    }
+
+    @Override
+    public Option getLoggingOption() {
+        return composite(
+                when(Boolean.getBoolean(OVSDB_TRACE)).useOptions(
+                        editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                                "log4j.logger.org.opendaylight.ovsdb",
+                                LogLevelOption.LogLevel.TRACE.name())),
+                //editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                //        "log4j.logger.org.opendaylight.ovsdb",
+                //        LogLevelOption.LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb.library",
+                        LogLevel.INFO.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        logConfiguration(NetvirtSfcIT.class),
+                        LogLevel.INFO.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.netvirt.openstack.netvirt.sfc",
+                        LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.netvirt.openstack.netvirt.providers.openflow13",
+                        LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.sfc",
+                        LogLevel.TRACE.name()),
+                super.getLoggingOption());
+    }
+
+    protected String usage() {
+        return "Integration Test needs a valid connection configuration as follows :\n"
+                + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
+                + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
+    }
+
+    private void getProperties() {
+        Properties props = System.getProperties();
+        addressStr = props.getProperty(SERVER_IPADDRESS);
+        portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
+        connectionType = props.getProperty(CONNECTION_TYPE, "active");
+        controllerStr = props.getProperty(CONTROLLER_IPADDRESS, "0.0.0.0");
+        userSpaceEnabled = props.getProperty(USERSPACE_ENABLED, "no");
+        LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
+                        "userspace.enabled: {}",
+                connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
+        if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
+            if (addressStr == null) {
+                fail(usage());
+            }
+        }
+        LOG.info("getProperties {}: {}", OVSDB_TRACE, props.getProperty(OVSDB_TRACE));
+        LOG.info("getProperties {}: {}", OVSDB_WAIT, props.getProperty(OVSDB_WAIT));
+        if (props.getProperty(OVSDB_WAIT) != null && props.getProperty(OVSDB_WAIT).equals("true")) {
+            ovsdb_wait = true;
+        }
+    }
+
+    @Before
+    @Override
+    public void setup() {
+        if (setup.get()) {
+            LOG.info("Skipping setUp, already initialized");
+            return;
+        }
+
+        try {
+            Thread.sleep(1000);
+            super.setup();
+        } catch (Exception e) {
+            LOG.warn("Failed to setup test", e);
+            fail("Failed to setup test: " + e);
+        }
+
+        getProperties();
+
+        dataBroker = getDatabroker(getProviderContext());
+        itUtils = new OvsdbItUtils(dataBroker);
+        nvItUtils = new NetvirtItUtils(dataBroker);
+        mdsalUtils = new MdsalUtils(dataBroker);
+        org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils sbMdsalUtils =
+                new org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils(dataBroker);
+        assertNotNull("mdsalUtils should not be null", mdsalUtils);
+        southboundUtils = new SouthboundUtils(sbMdsalUtils);
+        sfcUtils = new SfcUtils(mdsalUtils);
+        assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
+        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        assertNotNull("southbound should not be null", southbound);
+        pipelineOrchestrator =
+                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+        assertNotNull("pipelineOrchestrator should not be null", pipelineOrchestrator);
+
+        setup.set(true);
+    }
+
+    @After
+    public void teardown() {
+        closeWaitFors();
+    }
+
+    private ProviderContext getProviderContext() {
+        ProviderContext providerContext = null;
+        for (int i=0; i < 60; i++) {
+            providerContext = getSession();
+            if (providerContext != null) {
+                break;
+            } else {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.warn("Interrupted while waiting for provider context", e);
+                }
+            }
+        }
+        assertNotNull("providercontext should not be null", providerContext);
+        /* One more second to let the provider finish initialization */
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            LOG.warn("Interrupted while waiting for other provider", e);
+        }
+        return providerContext;
+    }
+
+    private DataBroker getDatabroker(ProviderContext providerContext) {
+        DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
+        assertNotNull("dataBroker should not be null", dataBroker);
+        return dataBroker;
+    }
+
+    private Boolean getNetvirtTopology() {
+        LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
+        Boolean found = false;
+        final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
+        InstanceIdentifier<Topology> path =
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+        for (int i = 0; i < 60; i++) {
+            Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+            if (topology != null) {
+                LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
+                found = true;
+                break;
+            } else {
+                LOG.info("getNetvirtTopology: still looking ({})...", i);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.warn("Interrupted while waiting for {}", NETVIRT_TOPOLOGY_ID, e);
+                }
+            }
+        }
+        return found;
+    }
+
+    private AccessListsBuilder accessListsBuilder() {
+        return accessListsBuilder(false);
+    }
+
+    private AccessListsBuilder accessListsBuilder(boolean renderRsp) {
+        String ruleName = RULENAME;
+        String sfcName = SFCNAME;
+        MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
+        LOG.info("Matches: {}", matchesBuilder.build());
+        ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), sfcName, renderRsp);
+        AceBuilder accessListEntryBuilder =
+                aclUtils.aceBuilder(new AceBuilder(), ruleName, matchesBuilder, actionsBuilder);
+        AccessListEntriesBuilder accessListEntriesBuilder =
+                aclUtils.accessListEntriesBuidler(new AccessListEntriesBuilder(), accessListEntryBuilder);
+        AclBuilder accessListBuilder =
+                aclUtils.aclBuilder(new AclBuilder(), ACLNAME, accessListEntriesBuilder);
+        AccessListsBuilder accessListsBuilder =
+                aclUtils.accesslistsbuilder(new AccessListsBuilder(), accessListBuilder);
+        LOG.info("AccessLists: {}", accessListsBuilder.build());
+        return accessListsBuilder;
+    }
+
+    @Test
+    public void testAccessLists() throws InterruptedException {
+        testModel(accessListsBuilder(), AccessLists.class, 0);
+    }
+
+    private ClassifiersBuilder classifiersBuilder() {
+        SffBuilder sffBuilder = classifierUtils.sffBuilder(new SffBuilder(), SFF1NAME);
+        SffsBuilder sffsBuilder = classifierUtils.sffsBuilder(new SffsBuilder(), sffBuilder);
+        ClassifierBuilder classifierBuilder = classifierUtils.classifierBuilder(new ClassifierBuilder(),
+                "classifierName", ACLNAME, sffsBuilder);
+        ClassifiersBuilder classifiersBuilder = classifierUtils.classifiersBuilder(new ClassifiersBuilder(),
+                classifierBuilder);
+        LOG.info("Classifiers: {}", classifiersBuilder.build());
+        return classifiersBuilder;
+    }
+
+    @Test
+    public void testClassifiers() throws InterruptedException {
+        testModel(classifiersBuilder(), Classifiers.class, 0);
+    }
+
+    private SfcBuilder netvirtSfcBuilder() {
+        return netvirtSfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
+    }
+
+    @Test
+    public void testNetvirtSfcModel() throws InterruptedException {
+        testModel(netvirtSfcBuilder(), Sfc.class, 0);
+    }
+
+    private <T extends DataObject> void testModelPut(Builder<T> builder, Class<T> clazz) {
+        InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
+        assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, path, builder.build()));
+        T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+        assertNotNull(clazz.getSimpleName() + " should not be null", result);
+    }
+
+    private <T extends DataObject> void testModelDelete(Builder<T> builder, Class<T> clazz)
+            throws InterruptedException {
+        InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
+        assertTrue("Failed to remove " + clazz.getSimpleName(),
+                mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, path));
+        T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+        assertNull(clazz.getSimpleName() + " should be null", result);
+    }
+
+    private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz, long wait)
+            throws InterruptedException {
+        testModelPut(builder, clazz);
+        Thread.sleep(wait);
+        testModelDelete(builder, clazz);
+    }
+
+    private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz)
+            throws InterruptedException {
+        testModelPut(builder, clazz);
+        Thread.sleep(1000);
+        testModelDelete(builder, clazz);
+    }
+
+    private ServiceFunctionsBuilder serviceFunctionsBuilder() {
+        String sf1Name = SF1NAME;
+        String sf1Ip = SF1IP;
+        String sff1Name = SFF1NAME;
+        String sf1DplName = SF1DPLNAME;
+        String sf1DplportName = SF1DPLPORTNAME;
+        int port = GPEUDPPORT;
+
+        ServiceFunctionBuilder serviceFunctionBuilder =
+                serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sf1DplName, sf1DplportName,
+                        sff1Name, sf1Name);
+        List<ServiceFunction> serviceFunctionList = serviceFunctionUtils.list(
+                new ArrayList<ServiceFunction>(), serviceFunctionBuilder);
+
+        ServiceFunctionsBuilder serviceFunctionsBuilder =
+                serviceFunctionUtils.serviceFunctionsBuilder(new ServiceFunctionsBuilder(),
+                        serviceFunctionList);
+        LOG.info("ServiceFunctions: {}", serviceFunctionsBuilder.build());
+        return serviceFunctionsBuilder;
+    }
+
+    private ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder() {
+        return serviceFunctionForwardersBuilder(null);
+    }
+
+    private ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder(OvsdbNodeRef ovsdbNodeRef) {
+        String sf1Name = SF1NAME;
+        String sf1Ip = SF1IP;
+        String sf1DplName = SF1DPLNAME;
+        String sff1Ip = SFF1IP;
+        String sff1Name = SFF1NAME;
+        String sffDpl1Name = SFFDPL1NAME;
+        String sn1Name = SN1NAME;
+        String bridge1Name= BRIDGE1NAME;
+        int port = GPEUDPPORT;
+
+        ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
+                serviceFunctionForwarderUtils.serviceFunctionForwarderBuilder(
+                        sff1Name, sff1Ip, port, sffDpl1Name, sf1Ip, sn1Name, bridge1Name, sf1Name, sf1DplName,
+                        ovsdbNodeRef);
+        List<ServiceFunctionForwarder>  serviceFunctionForwarderList = serviceFunctionForwarderUtils.list(
+                new ArrayList<ServiceFunctionForwarder>(), serviceFunctionForwarderBuilder);
+
+        ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder =
+                serviceFunctionForwarderUtils.serviceFunctionForwardersBuilder(
+                        new ServiceFunctionForwardersBuilder(), serviceFunctionForwarderList);
+        LOG.info("ServiceFunctionForwarders: {}", serviceFunctionForwardersBuilder.build());
+        return serviceFunctionForwardersBuilder;
+    }
+
+    private ServiceFunctionChainsBuilder serviceFunctionChainsBuilder() {
+        String sf1Name = SFCSF1NAME;
+        SftType sfType = SFCSF1TYPE;
+        String sfcName = SFCNAME;
+
+        SfcServiceFunctionBuilder sfcServiceFunctionBuilder = serviceFunctionChainUtils.sfcServiceFunctionBuilder(
+                new SfcServiceFunctionBuilder(), sf1Name, sfType);
+        List<SfcServiceFunction> sfcServiceFunctionList =
+                serviceFunctionChainUtils.list(new ArrayList<SfcServiceFunction>(), sfcServiceFunctionBuilder);
+
+        ServiceFunctionChainBuilder serviceFunctionChainBuilder =
+                serviceFunctionChainUtils.serviceFunctionChainBuilder(
+                        new ServiceFunctionChainBuilder(), sfcName, false, sfcServiceFunctionList);
+        ServiceFunctionChainsBuilder serviceFunctionChainsBuilder =
+                serviceFunctionChainUtils.serviceFunctionChainsBuilder(
+                        new ServiceFunctionChainsBuilder(),
+                        serviceFunctionChainUtils.list(new ArrayList<ServiceFunctionChain>(),
+                                serviceFunctionChainBuilder));
+        LOG.info("ServiceFunctionChains: {}", serviceFunctionChainBuilder.build());
+        return serviceFunctionChainsBuilder;
+    }
+
+    private ServiceFunctionPathsBuilder serviceFunctionPathsBuilder() {
+        String sfpName = SFCPATH;
+        String sfcName = SFCNAME;
+        short startingIndex = 255;
+
+        ServiceFunctionPathBuilder serviceFunctionPathBuilder =
+                serviceFunctionPathUtils.serviceFunctionPathBuilder(
+                        new ServiceFunctionPathBuilder(), sfpName, sfcName, startingIndex, false);
+        ServiceFunctionPathsBuilder serviceFunctionPathsBuilder =
+                serviceFunctionPathUtils.serviceFunctionPathsBuilder(
+                        serviceFunctionPathUtils.list(new ArrayList<ServiceFunctionPath>(),
+                                serviceFunctionPathBuilder));
+        LOG.info("ServiceFunctionPaths: {}", serviceFunctionPathsBuilder.build());
+        return serviceFunctionPathsBuilder;
+    }
+
+    private SfcOfRendererConfigBuilder sfcOfRendererConfigBuilder(short tableOffset, short egressTable) {
+        SfcOfRendererConfigBuilder sfcOfRendererConfigBuilder =
+                sfcConfigUtils.sfcOfRendererConfigBuilder(new SfcOfRendererConfigBuilder(), tableOffset, egressTable);
+        LOG.info("SfcOfRendererConfig: {}", sfcOfRendererConfigBuilder.build());
+        return sfcOfRendererConfigBuilder;
+    }
+
+    private NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder(short tableOffset) {
+        NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder =
+                netvirtConfigUtils.netvirtProvidersConfigBuilder(new NetvirtProvidersConfigBuilder(), tableOffset);
+        LOG.info("NetvirtProvidersConfig: {}", netvirtProvidersConfigBuilder.build());
+        return netvirtProvidersConfigBuilder;
+    }
+
+    @Test
+    public void testSfcModel() throws InterruptedException {
+        int timeout = 1000;
+        testModel(serviceFunctionsBuilder(), ServiceFunctions.class, timeout);
+        testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class, timeout);
+        testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class, timeout);
+        testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class, timeout);
+    }
+
+    @Test
+    public void testSfcModels() throws InterruptedException {
+        testModel(serviceFunctionsBuilder(), ServiceFunctions.class);
+        testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
+        testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
+        testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
+
+        testModel(accessListsBuilder(), AccessLists.class);
+        testModel(classifiersBuilder(), Classifiers.class);
+    }
+
+    /**
+     * Test that the NetvirtSfc SfcClassifierService is added to the Netvirt pipeline. The test
+     * sets the table offset and verifies the correct flow is programmed with the offset.
+     */
+    @Test
+    public void testNetvirtSfcPipeline() throws InterruptedException {
+        short netvirtTableOffset = 1;
+        testModelPut(netvirtProvidersConfigBuilder(netvirtTableOffset), NetvirtProvidersConfig.class);
+
+        NodeInfo nodeInfo = itUtils.createNodeInfo(SouthboundUtils.getConnectionInfo(addressStr, portStr), waitList);
+        nodeInfo.connect();
+
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER));
+
+        nodeInfo.disconnect();
+    }
+
+    /**
+     * Test the full NetvirtSfc functionality by creating everything needed to realize a chain and
+     * then verify all flows have been created.
+     * NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
+     * @throws InterruptedException
+     */
+    @Test
+    public void testNetvirtSfcAll() throws Exception {
+        if (userSpaceEnabled.equals("yes")) {
+            LOG.info("testNetvirtSfcAll: skipping test because userSpaceEnabled {}", userSpaceEnabled);
+            return;
+        }
+
+        String sfpName = SFCPATH;
+        String sfcName = SFCNAME;
+        short startingIndex = 255;
+
+        short netvirtTableOffset = 1;
+        testModelPut(netvirtProvidersConfigBuilder(netvirtTableOffset), NetvirtProvidersConfig.class);
+        short sfcTableoffset = 150;
+        short egressTable = pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
+        testModelPut(sfcOfRendererConfigBuilder(sfcTableoffset, egressTable), SfcOfRendererConfig.class);
+
+        NodeInfo nodeInfo = itUtils.createNodeInfo(SouthboundUtils.getConnectionInfo(addressStr, portStr), waitList);
+        nodeInfo.connect();
+
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER));
+
+        Map<String, String> externalIds = Maps.newHashMap();
+        externalIds.put("attached-mac", "f6:00:00:0f:00:01");
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, SF1DPLPORTNAME, "internal", null, externalIds);
+        externalIds.clear();
+        externalIds.put("attached-mac", "f6:00:00:0c:00:01");
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vm1", "internal");
+        externalIds.clear();
+        externalIds.put("attached-mac", "f6:00:00:0c:00:02");
+        southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vm2", "internal");
+
+        InstanceIdentifier<TerminationPoint> tpIid =
+                southboundUtils.createTerminationPointInstanceIdentifier(nodeInfo.bridgeNode, SF1DPLPORTNAME);
+        final NotifyingDataChangeListener portOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, tpIid, waitList);
+        portOperationalListener.registerDataChangeListener(dataBroker);
+
+        InstanceIdentifier<RenderedServicePath> rspIid = sfcUtils.getRspId(RSPNAME);
+        final NotifyingDataChangeListener rspOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, rspIid, waitList);
+        rspOperationalListener.registerDataChangeListener(dataBroker);
+
+        OvsdbBridgeAugmentation bridgeAugmentation = southbound.extractBridgeAugmentation(nodeInfo.bridgeNode);
+        OvsdbNodeRef ovsdbNodeRef = null;
+        if (bridgeAugmentation != null) {
+            ovsdbNodeRef = bridgeAugmentation.getManagedBy();
+        }
+
+        testModelPut(serviceFunctionsBuilder(), ServiceFunctions.class);
+        testModelPut(serviceFunctionForwardersBuilder(ovsdbNodeRef), ServiceFunctionForwarders.class);
+        testModelPut(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
+        testModelPut(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
+
+        testModelPut(accessListsBuilder(false), AccessLists.class);
+        testModelPut(classifiersBuilder(), Classifiers.class);
+        ServiceFunctionPathBuilder serviceFunctionPathBuilder =
+                serviceFunctionPathUtils.serviceFunctionPathBuilder(
+                        new ServiceFunctionPathBuilder(), sfpName, sfcName, startingIndex, false);
+        SfcProviderRenderedPathAPI.createRenderedServicePathAndState(serviceFunctionPathBuilder.build(),
+                renderedServicePathUtils.createRenderedPathInputBuilder(new CreateRenderedPathInputBuilder(),
+                        SFCPATH, RSPNAME).build());
+
+        portOperationalListener.waitForCreation();
+        long vxGpeOfPort = southbound.getOFPort(nodeInfo.bridgeNode, SFFDPL1NAME);
+        assertNotEquals("vxGpePort was not found", 0, vxGpeOfPort);
+
+        rspOperationalListener.waitForCreation();
+        RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
+        assertNotNull("RSP was not found", rsp);
+
+        flowId = FlowNames.getSfcIngressClass(RULENAME, rsp.getPathId(), rsp.getStartingIndex());
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER));
+        RenderedServicePathHop lastHop = sfcUtils.getLastHop(rsp);
+        short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+        flowId = FlowNames.getSfcEgressClass(vxGpeOfPort, rsp.getPathId(), lastServiceindex);
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER));
+        flowId = FlowNames.getSfcEgressClassBypass(rsp.getPathId(), lastServiceindex, 1);
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.CLASSIFIER));
+        flowId = FlowNames.getArpResponder(SF1IP);
+        nvItUtils.verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.ARP_RESPONDER));
+        // Only verify these flows if NetVirt adds them and not SFC
+        //flowId = FlowNames.getSfEgress(GPEUDPPORT);
+        //verifyFlow(nodeInfo.datapathId, flowId, pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER));
+        //flowId = FlowNames.getSfIngress(GPEUDPPORT, SF1IP);
+        //verifyFlow(nodeInfo.datapathId, flowId, Service.CLASSIFIER.getTable());
+
+        LOG.info("check for flows!!!!!!!!!!!!!");
+        //Thread.sleep(30000);
+        InstanceIdentifier<Flow> flowIid = createFlowIid(nodeInfo.datapathId, flowId,
+                pipelineOrchestrator.getTable(Service.CLASSIFIER));
+
+        final NotifyingDataChangeListener flowConfigurationListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.CONFIGURATION, flowIid, waitList);
+        flowConfigurationListener.registerDataChangeListener(dataBroker);
+        final NotifyingDataChangeListener flowOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, flowIid, waitList);
+        flowOperationalListener.registerDataChangeListener(dataBroker);
+
+        deleteRsp(RSPNAME);
+        rspOperationalListener.waitForDeletion();
+        rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
+        assertNull("RSP should not be found", rsp);
+
+        flowConfigurationListener.waitForDeletion();
+        Flow flow = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, flowIid);
+        assertNull("Flow should not be found in CONFIGURATION " + flowIid, flow);
+
+        flowOperationalListener.waitForDeletion();
+        flow = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, flowIid);
+        assertNull("Flow should not be found in OPERATIONAL " + flowIid, flow);
+
+        nodeInfo.disconnect();
+    }
+
+    private void deleteRsp(String rspName) {
+        RenderedServicePathKey renderedServicePathKey =
+                new RenderedServicePathKey(RspName.getDefaultInstance(rspName));
+        InstanceIdentifier<RenderedServicePath> path =
+                InstanceIdentifier.create(RenderedServicePaths.class)
+                        .child(RenderedServicePath.class, renderedServicePathKey);
+        mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, path);
+    }
+
+    /**
+     * Test the standalone NetvirtSfc implementation
+     * NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
+     * @throws InterruptedException
+     */
+    @Ignore
+    @Test
+    public void testStandalone() throws InterruptedException {
+        String bridgeName = "sw1";
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+        Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+        assertNotNull("node is not connected", ovsdbNode);
+
+        String controllerTarget = "tcp:192.168.50.1:6653";
+        List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
+        Assert.assertTrue(southboundUtils.addBridge(connectionInfo, null, bridgeName, null, true,
+                SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
+                setControllerEntry, null, "00:00:00:00:00:00:00:01"));
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", itUtils.isControllerConnected(connectionInfo));
+
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
+        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
+        assertNotEquals("datapathId was not found", datapathId, 0);
+
+        SfcClassifier sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
+        //sfcClassifier.programLocalInPort(datapathId, "4096", (long)1, (short)0, (short)50, true);
+
+        NshUtils nshUtils = new NshUtils(new Ipv4Address("192.168.50.71"), new PortNumber(6633),
+                (long)10, (short)255, (long)4096, (long)4096);
+        MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
+        sfcClassifier.programSfcClassiferFlows(datapathId, (short)0, "test", matchesBuilder.build(),
+                nshUtils, (long)2, true);
+
+        //nshUtils = new NshUtils(null, null, (long)10, (short)253, 0, 0);
+        //sfcClassifier.programEgressSfcClassiferFlows(datapathId, (short)0, "test", null,
+        //        nshUtils, (long)2, (long)3, true);
+
+        //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        //FlowBuilder flowBuilder = getLocalInPortFlow(datapathId, "4096", (long) 1,
+        //                                             pipelineOrchestrator.getTable(Service.CLASSIFIER));
+        //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        //assertNotNull("Could not find flow in config", flow);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        //assertNotNull("Could not find flow in operational", flow);
+
+        //MatchBuilder matchBuilder = sfcClassifier.buildMatch(matchesBuilder.build());
+        //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        //FlowBuilder flowBuilder = getSfcClassifierFlow(datapathId,
+        //        pipelineOrchestrator.getTable(Service.CLASSIFIER), "test", null,
+        //        nshUtils, (long) 2, matchBuilder);
+        //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        //assertNotNull("Could not find flow in config", flow);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        //assertNotNull("Could not find flow in operational", flow);
+
+        //nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        //flowBuilder = getEgressSfcClassifierFlow(datapathId,
+                                                   //pipelineOrchestrator.getTable(Service.CLASSIFIER),
+                                                   //"test", nshUtils, (long) 2);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        //assertNotNull("Could not find flow in config", flow);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        //assertNotNull("Could not find flow in operational", flow);
+
+        LOG.info("***** Go look for flows *****");
+        Thread.sleep(30000);
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
+        Thread.sleep(1000);
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
+        Thread.sleep(1000);
+        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
+    }
+
+    private InstanceIdentifier<Flow> createFlowIid(long datapathId, String flowId, short table) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+                FlowUtils.createNodeBuilder(datapathId);
+        FlowBuilder flowBuilder =
+                FlowUtils.initFlowBuilder(new FlowBuilder(), flowId, table);
+        return FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
+    }
+
+    private Flow getFlow (
+            FlowBuilder flowBuilder,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
+            LogicalDatastoreType store) throws InterruptedException {
+
+        Flow flow = null;
+        for (int i = 0; i < 10; i++) {
+            LOG.info("getFlow try {} from {}: looking for flow: {}, node: {}",
+                    i, store, flowBuilder.build(), nodeBuilder.build());
+            flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
+            if (flow != null) {
+                LOG.info("getFlow try {} from {}: found flow: {}", i, store, flow);
+                break;
+            }
+            Thread.sleep(1000);
+        }
+        return flow;
+    }
+
+    private void readwait() {
+        if (ovsdb_wait) {
+            LOG.warn("Waiting, kill with ps -ef | grep java, kill xxx... ");
+            try {
+                System.in.read();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private List<NotifyingDataChangeListener> waitList = new ArrayList<>();
+
+    private void closeWaitFors() {
+        for (Iterator<NotifyingDataChangeListener> iterator = waitList.iterator(); iterator.hasNext();) {
+            NotifyingDataChangeListener listener = iterator.next();
+            iterator.remove();
+            try {
+                listener.close();
+            } catch (Exception ex) {
+                LOG.warn("Failed to close registration {}", listener, ex);
+            }
+        }
+        LOG.info("waitList size {}", waitList.size());
+    }
+
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/AbstractUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/AbstractUtils.java
new file mode 100644 (file)
index 0000000..2e54bcf
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.DataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.IpBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yangtools.concepts.Builder;
+
+public abstract class AbstractUtils {
+    public <T> List<T> list(List<T> list, Builder<T> builder) {
+        list.add(builder.build());
+        return list;
+    }
+
+    public IpBuilder ipBuilder(String ip, int port) {
+        return new IpBuilder()
+                .setIp(new IpAddress(ip.toCharArray()))
+                .setPort(new PortNumber(port));
+    }
+
+    public DataPlaneLocatorBuilder dataPlaneLocatorBuilder(DataPlaneLocatorBuilder dataPlaneLocatorBuilder,
+                                                           String ip, int port) {
+        return dataPlaneLocatorBuilder
+                .setLocatorType(ipBuilder(ip, port).build())
+                .setTransport(VxlanGpe.class);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/AclUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/AclUtils.java
new file mode 100644 (file)
index 0000000..7111a6c
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.PermitBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.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.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.DestinationPortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.SourcePortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfcBuilder;
+
+public class AclUtils extends AbstractUtils {
+    public MatchesBuilder matchesBuilder(MatchesBuilder matchesBuilder, int destPort) {
+        SourcePortRangeBuilder sourcePortRangeBuilder = new SourcePortRangeBuilder()
+                .setLowerPort(PortNumber.getDefaultInstance("0"))
+                .setUpperPort(PortNumber.getDefaultInstance("0"));
+
+        PortNumber portNumber = new PortNumber(destPort);
+        DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder()
+                .setLowerPort(portNumber)
+                .setUpperPort(portNumber);
+
+        AceIpBuilder aceIpBuilder = new AceIpBuilder()
+                .setSourcePortRange(sourcePortRangeBuilder.build())
+                .setDestinationPortRange(destinationPortRangeBuilder.build())
+                .setProtocol((short)6);
+
+        return matchesBuilder.setAceType(aceIpBuilder.build());
+    }
+
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, Boolean permit) {
+        return actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(permit).build());
+    }
+
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, String sfcName, boolean renderRsp) {
+        RedirectToSfcBuilder redirectToSfcBuilder = new RedirectToSfcBuilder()
+                .setSfcName(sfcName)
+                .setRenderRsp(renderRsp);
+
+        return actionsBuilder.addAugmentation(RedirectToSfc.class, redirectToSfcBuilder.build());
+    }
+
+    public AceBuilder aceBuilder(AceBuilder accessListEntryBuilder,
+                                 String ruleName,
+                                 MatchesBuilder matchesBuilder,
+                                 ActionsBuilder actionsBuilder) {
+        return accessListEntryBuilder
+                .setRuleName(ruleName)
+                .setMatches(matchesBuilder.build())
+                .setActions(actionsBuilder.build());
+    }
+
+    public AccessListEntriesBuilder accessListEntriesBuidler(AccessListEntriesBuilder accessListEntriesBuilder,
+                                                             AceBuilder aceBuilder) {
+        List<Ace> aceList = new ArrayList<>();
+        aceList.add(aceBuilder.build());
+
+        return accessListEntriesBuilder.setAce(aceList);
+    }
+
+    public AclBuilder aclBuilder(AclBuilder aclBuilder,
+                                 String aclName,
+                                 AccessListEntriesBuilder accessListEntriesBuilder) {
+        return aclBuilder
+                .setAclName(aclName)
+                .setAccessListEntries(accessListEntriesBuilder.build());
+    }
+
+    public AccessListsBuilder accesslistsbuilder(AccessListsBuilder accessListsBuilder,
+                                                 AclBuilder aclBuilder) {
+        List<Acl> aclList = new ArrayList<>();
+        aclList.add(aclBuilder.build());
+
+        return accessListsBuilder.setAcl(aclList);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ClassifierUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ClassifierUtils.java
new file mode 100644 (file)
index 0000000..7c9b254
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.SffsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.SffBuilder;
+
+public class ClassifierUtils extends AbstractUtils {
+    public SffBuilder sffBuilder(SffBuilder sffBuilder, String sffName) {
+        return sffBuilder.setName(sffName);
+    }
+
+    public SffsBuilder sffsBuilder(SffsBuilder sffsBuilder, SffBuilder sffBuilder) {
+        List<Sff> sffList = new ArrayList<>();
+        sffList.add(sffBuilder.build());
+        sffsBuilder.setSff(sffList);
+
+        return sffsBuilder;
+    }
+
+    public ClassifierBuilder classifierBuilder(ClassifierBuilder classifierBuilder,
+                                               String classifierName, String aclName,
+                                               SffsBuilder sffsBuilder) {
+        return classifierBuilder
+                .setName(classifierName)
+                .setAcl(aclName);
+    }
+
+    public ClassifiersBuilder classifiersBuilder(ClassifiersBuilder classifiersBuilder,
+                                                 ClassifierBuilder classifierBuilder) {
+        List<Classifier> classifierList = new ArrayList<>();
+        classifierList.add(classifierBuilder.build());
+        classifiersBuilder.setClassifier(classifierList);
+
+        return classifiersBuilder;
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/NetvirtConfigUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/NetvirtConfigUtils.java
new file mode 100644 (file)
index 0000000..9de7a24
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.NetvirtProvidersConfigBuilder;
+
+public class NetvirtConfigUtils {
+    public NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder(
+            NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder, short tableOffset) {
+        return netvirtProvidersConfigBuilder.setTableOffset(tableOffset);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/NetvirtSfcUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/NetvirtSfcUtils.java
new file mode 100644 (file)
index 0000000..8ed8d80
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
+
+public class NetvirtSfcUtils {
+    public SfcBuilder sfcBuilder(SfcBuilder sfcBuilder, String sfcName) {
+        return sfcBuilder.setName(sfcName);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/RenderedServicePathUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/RenderedServicePathUtils.java
new file mode 100644 (file)
index 0000000..5054f36
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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.openstack.netvirt.sfc.it.utils;
+
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+
+public class RenderedServicePathUtils extends AbstractUtils {
+
+    public CreateRenderedPathInputBuilder createRenderedPathInputBuilder(
+            CreateRenderedPathInputBuilder createRenderedPathInputBuilder, String sfpName, String rspName) {
+        return createRenderedPathInputBuilder
+                .setName(rspName)
+                .setParentServiceFunctionPath(sfpName)
+                .setSymmetric(false);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionChainUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionChainUtils.java
new file mode 100644 (file)
index 0000000..345ba5a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+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.SftType;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChainsBuilder;
+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.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;
+
+public class ServiceFunctionChainUtils extends AbstractUtils {
+    public SfcServiceFunctionBuilder sfcServiceFunctionBuilder(SfcServiceFunctionBuilder sfcServiceFunctionBuilder,
+                                                               String name,
+                                                               SftType type) {
+        return sfcServiceFunctionBuilder
+                .setName(name)
+                .setType(type);
+    }
+
+    public ServiceFunctionChainBuilder serviceFunctionChainBuilder(
+            ServiceFunctionChainBuilder serviceFunctionChainBuilder, String name, Boolean symmetric,
+            List<SfcServiceFunction> sfcServiceFunctionList) {
+
+        return serviceFunctionChainBuilder
+                .setName(SfcName.getDefaultInstance(name))
+                .setSymmetric(symmetric)
+                .setSfcServiceFunction(sfcServiceFunctionList);
+    }
+
+    public ServiceFunctionChainsBuilder serviceFunctionChainsBuilder(
+            ServiceFunctionChainsBuilder serviceFunctionChainsBuilder,
+            List<ServiceFunctionChain> serviceFunctionChainBuilderList) {
+
+        return serviceFunctionChainsBuilder.setServiceFunctionChain(serviceFunctionChainBuilderList);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionForwarderUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionForwarderUtils.java
new file mode 100644 (file)
index 0000000..ffa848c
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.common.rev151017.SnName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsLocatorOptionsAugmentation;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsLocatorOptionsAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsNodeAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.bridge.OvsBridgeBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.node.OvsNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.options.OvsOptionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwardersBuilder;
+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.SffDataPlaneLocator;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.SffDataPlaneLocatorBuilder;
+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.sff.rev140701.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.DataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
+
+public class ServiceFunctionForwarderUtils extends AbstractUtils {
+    public OvsOptionsBuilder ovsOptionsBuilder(OvsOptionsBuilder ovsOptionsBuilder, int port) {
+        String flow = "flow";
+        return ovsOptionsBuilder
+                .setDstPort(String.valueOf(port))
+                .setRemoteIp(flow)
+                .setKey(flow)
+                .setNsi(flow)
+                .setNsp(flow)
+                .setNshc1(flow)
+                .setNshc2(flow)
+                .setNshc3(flow)
+                .setNshc4(flow);
+    }
+
+    public SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder(SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder,
+                                                                 DataPlaneLocatorBuilder dataPlaneLocatorBuilder,
+                                                                 String dplName) {
+        SffOvsLocatorOptionsAugmentationBuilder sffOvsLocatorOptionsAugmentationBuilder =
+                new SffOvsLocatorOptionsAugmentationBuilder();
+        sffOvsLocatorOptionsAugmentationBuilder.setOvsOptions(
+                ovsOptionsBuilder(new OvsOptionsBuilder(), 6633).build());
+
+        return sffDataPlaneLocatorBuilder
+                .setName(new SffDataPlaneLocatorName(dplName))
+                .setDataPlaneLocator(dataPlaneLocatorBuilder.build())
+                .addAugmentation(SffOvsLocatorOptionsAugmentation.class,
+                        sffOvsLocatorOptionsAugmentationBuilder.build());
+    }
+
+    public SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder(
+            SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder, String sffDplName, String sfDplName) {
+        return sffSfDataPlaneLocatorBuilder
+                .setSfDplName(SfDataPlaneLocatorName.getDefaultInstance(sfDplName))
+                .setSffDplName(SffDataPlaneLocatorName.getDefaultInstance(sffDplName));
+    }
+
+    public ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder(
+            ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder,
+            SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder,
+            String sfName) {
+
+        return serviceFunctionDictionaryBuilder
+                .setName(SfName.getDefaultInstance(sfName))
+                .setSffSfDataPlaneLocator(sffSfDataPlaneLocatorBuilder.build());
+    }
+
+    public OvsBridgeBuilder ovsBridgeBuilder(OvsBridgeBuilder ovsBridgeBuilder, String bridgeName) {
+        return ovsBridgeBuilder.setBridgeName(bridgeName);
+    }
+
+    public ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder(
+            ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder,
+            String sffName, String serviceNodeName, String bridgeName,
+            List<SffDataPlaneLocator> sffDataPlaneLocatorList,
+            List<ServiceFunctionDictionary> serviceFunctionDictionaryList,
+            OvsdbNodeRef ovsdbNodeRef) {
+
+        SffOvsBridgeAugmentationBuilder sffOvsBridgeAugmentationBuilder = new SffOvsBridgeAugmentationBuilder();
+        sffOvsBridgeAugmentationBuilder.setOvsBridge(ovsBridgeBuilder(new OvsBridgeBuilder(), bridgeName).build());
+
+        SffOvsNodeAugmentationBuilder sffOvsNodeAugmentationBuilder = new SffOvsNodeAugmentationBuilder();
+        OvsNodeBuilder ovsNodeBuilder = new OvsNodeBuilder();
+        ovsNodeBuilder.setNodeId(ovsdbNodeRef);
+        sffOvsNodeAugmentationBuilder.setOvsNode(ovsNodeBuilder.build());
+
+        return serviceFunctionForwarderBuilder
+                .setName(new SffName(sffName))
+                .setServiceNode(new SnName(serviceNodeName))
+                .setServiceFunctionDictionary(serviceFunctionDictionaryList)
+                .setSffDataPlaneLocator(sffDataPlaneLocatorList)
+                .addAugmentation(SffOvsNodeAugmentation.class, sffOvsNodeAugmentationBuilder.build())
+                .addAugmentation(SffOvsBridgeAugmentation.class, sffOvsBridgeAugmentationBuilder.build());
+    }
+
+    public ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder(
+            ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder,
+            List<ServiceFunctionForwarder> serviceFunctionForwarderList) {
+        return serviceFunctionForwardersBuilder.setServiceFunctionForwarder(serviceFunctionForwarderList);
+    }
+
+    public ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder(
+            String sffName, String sffIp, int port, String sffDplName,
+            String sfIp, String snName, String bridgeName, String sfName, String sfDplName,
+            OvsdbNodeRef ovsdbNodeRef) {
+
+        DataPlaneLocatorBuilder dataPlaneLocatorBuilder =
+                dataPlaneLocatorBuilder(new DataPlaneLocatorBuilder(), sffIp, port);
+        SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder =
+                sffDataPlaneLocatorBuilder( new SffDataPlaneLocatorBuilder(), dataPlaneLocatorBuilder, sffDplName);
+        List<SffDataPlaneLocator> sffDataPlaneLocatorList =
+                list(new ArrayList<SffDataPlaneLocator>(), sffDataPlaneLocatorBuilder);
+
+        SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder =
+                sffSfDataPlaneLocatorBuilder(new SffSfDataPlaneLocatorBuilder(), sffDplName, sfDplName);
+        ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder =
+                serviceFunctionDictionaryBuilder(new ServiceFunctionDictionaryBuilder(),
+                        sffSfDataPlaneLocatorBuilder, sfName);
+        List<ServiceFunctionDictionary> serviceFunctionDictionaryList =
+                list(new ArrayList<ServiceFunctionDictionary>(), serviceFunctionDictionaryBuilder);
+
+        ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
+                serviceFunctionForwarderBuilder(
+                        new ServiceFunctionForwarderBuilder(), sffName, snName, bridgeName,
+                        sffDataPlaneLocatorList, serviceFunctionDictionaryList, ovsdbNodeRef);
+        return serviceFunctionForwarderBuilder;
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionPathUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionPathUtils.java
new file mode 100644 (file)
index 0000000..4df1ded
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+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.sfp.rev140701.ServiceFunctionPathsBuilder;
+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;
+
+public class ServiceFunctionPathUtils extends AbstractUtils {
+    public ServiceFunctionPathBuilder serviceFunctionPathBuilder(
+            ServiceFunctionPathBuilder serviceFunctionPathBuilder,
+            String sfpName, String sfcName, short startingIndex, Boolean symmetric) {
+
+        return serviceFunctionPathBuilder
+                .setSymmetric(symmetric)
+                .setName(SfpName.getDefaultInstance(sfpName))
+                .setServiceChainName(SfcName.getDefaultInstance(sfcName))
+                .setStartingIndex(startingIndex);
+    }
+
+    public ServiceFunctionPathsBuilder serviceFunctionPathsBuilder(
+            List<ServiceFunctionPath> serviceFunctionPathList) {
+
+        return new ServiceFunctionPathsBuilder().setServiceFunctionPath(serviceFunctionPathList);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/ServiceFunctionUtils.java
new file mode 100644 (file)
index 0000000..926a0b6
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2015 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.openstack.netvirt.sfc.it.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.SftType;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.entry.SfDataPlaneLocator;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.entry.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.sl.rev140701.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sf.ovs.rev160107.SfDplOvsAugmentation;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sf.ovs.rev160107.SfDplOvsAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sf.ovs.rev160107.connected.port.OvsPortBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+
+public class ServiceFunctionUtils extends AbstractUtils {
+    public SfDataPlaneLocatorBuilder sfDataPlaneLocatorBuilder(SfDataPlaneLocatorBuilder sfDataPlaneLocatorBuilder,
+                                                               String ip, int port, String dplName,
+                                                               String sf1DplPortName, String sffName) {
+        SfDplOvsAugmentationBuilder sfDplOvsAugmentationBuilder = new SfDplOvsAugmentationBuilder();
+        OvsPortBuilder ovsPortBuilder = new OvsPortBuilder().setPortId(sf1DplPortName);
+        sfDplOvsAugmentationBuilder.setOvsPort(ovsPortBuilder.build());
+
+        return sfDataPlaneLocatorBuilder
+                .addAugmentation(SfDplOvsAugmentation.class, sfDplOvsAugmentationBuilder.build())
+                .setLocatorType(ipBuilder(ip, port).build())
+                .setName(SfDataPlaneLocatorName.getDefaultInstance(dplName))
+                .setTransport(VxlanGpe.class)
+                .setServiceFunctionForwarder(SffName.getDefaultInstance(sffName));
+    }
+
+    public ServiceFunctionBuilder serviceFunctionBuilder(ServiceFunctionBuilder serviceFunctionBuilder,
+                                                         String ip, String sfName,
+                                                         List<SfDataPlaneLocator> sfDataPlaneLocatorList,
+                                                         SftType type) {
+        return serviceFunctionBuilder
+                .setSfDataPlaneLocator(sfDataPlaneLocatorList)
+                .setName(new SfName(sfName))
+                .setIpMgmtAddress(new IpAddress(ip.toCharArray()))
+                .setType(type)
+                .setNshAware(true);
+    }
+
+    public ServiceFunctionsBuilder serviceFunctionsBuilder(ServiceFunctionsBuilder serviceFunctionsBuilder,
+                                                           List<ServiceFunction> serviceFunctionList) {
+        return serviceFunctionsBuilder.setServiceFunction(serviceFunctionList);
+    }
+
+    public ServiceFunctionBuilder serviceFunctionBuilder(String sfIp, int port, String sf1DplName,
+                                                         String sf1DplPortName,
+                                                         String sffname, String sfName) {
+        SfDataPlaneLocatorBuilder sfDataPlaneLocator =
+                sfDataPlaneLocatorBuilder(new SfDataPlaneLocatorBuilder(), sfIp, port, sf1DplName,
+                        sf1DplPortName, sffname);
+        List<SfDataPlaneLocator> sfDataPlaneLocatorList =
+                list(new ArrayList<SfDataPlaneLocator>(), sfDataPlaneLocator);
+        return serviceFunctionBuilder(
+                new ServiceFunctionBuilder(), sfIp, sfName, sfDataPlaneLocatorList, new SftType("firewall"));
+    }
+
+
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/SfcConfigUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/sfc/it/utils/SfcConfigUtils.java
new file mode 100644 (file)
index 0000000..119c2d0
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.openstack.netvirt.sfc.it.utils;
+
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfig;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfigBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class SfcConfigUtils {
+    public SfcOfRendererConfigBuilder sfcOfRendererConfigBuilder(SfcOfRendererConfigBuilder sfcOfRendererConfigBuilder,
+                                                                 short tableOffset, short egressTable) {
+        return sfcOfRendererConfigBuilder
+                .setSfcOfTableOffset(tableOffset)
+                .setSfcOfAppEgressTableOffset(egressTable);
+    }
+
+    public InstanceIdentifier<SfcOfRendererConfig> getPath() {
+        return InstanceIdentifier.create(SfcOfRendererConfig.class);
+    }
+}
diff --git a/openstack/net-virt-sfc/karaf/pom.xml b/openstack/net-virt-sfc/karaf/pom.xml
new file mode 100644 (file)
index 0000000..9a94e9f
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>karaf-parent</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-karaf</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <properties>
+    <karaf.localFeature>odl-ovsdb-sfc-test</karaf.localFeature>
+  </properties>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>openstack.net-virt-sfc-artifacts</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <!-- scope is compile so all features (there is only one) are installed
+      into startup.properties and the feature repo itself is not installed -->
+      <groupId>org.apache.karaf.features</groupId>
+      <artifactId>framework</artifactId>
+      <type>kar</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-sfc-features</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+  </dependencies>
+  <!-- DO NOT install or deploy the karaf artifact -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/openstack/net-virt-sfc/pom.xml b/openstack/net-virt-sfc/pom.xml
new file mode 100644 (file)
index 0000000..64e73dc
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2015 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt-sfc-aggregator</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>api</module>
+    <module>impl</module>
+    <module>karaf</module>
+    <module>features</module>
+    <module>artifacts</module>
+    <module>it</module>
+  </modules>
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+</project>
diff --git a/openstack/net-virt/pom.xml b/openstack/net-virt/pom.xml
new file mode 100644 (file)
index 0000000..ee78bc9
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack.net-virt</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <properties>
+    <neutron.model.version>0.7.0-SNAPSHOT</neutron.model.version>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+    <sonar.jacoco.itReportPath>../net-virt-it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-api</artifactId>
+      <version>${ovsdb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.config</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.neutron-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>model</artifactId>
+      <version>${neutron.model.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-topology</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>opendaylight-l2-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types</artifactId>
+    </dependency>
+   <dependency>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar-plugins.java</groupId>
+      <artifactId>sonar-jacoco-listeners</artifactId>
+      <version>${sonar-jacoco-listeners.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-support</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-reflect</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>utils.config;type=!pom;inline=false</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+            <Export-Package>
+              org.opendaylight.netvirt.openstack.netvirt.translator,
+              org.opendaylight.netvirt.openstack.netvirt.api,
+              org.opendaylight.netvirt.openstack.netvirt
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <properties>
+            <property>
+              <name>listener</name>
+              <value>org.sonar.java.jacoco.JUnitListener</value>
+            </property>
+          </properties>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/openstack/net-virt/src/main/config/default-config.xml b/openstack/net-virt/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..819fb3e
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<snapshot>
+  <required-capabilities>
+    <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:southbound:impl?module=southbound-impl&amp;revision=2014-12-10</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:impl?module=netvirt-impl&amp;revision=2015-05-13</capability>
+  </required-capabilities>
+  <configuration>
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:impl">prefix:netvirt-impl</type>
+          <name>netvirt-default</name>
+          <conntrack-enabled>false</conntrack-enabled>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+          <clustering-entity-ownership-service>
+            <type xmlns:ns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">ns:entity-ownership-service</type>
+            <name>entity-ownership-service</name>
+          </clustering-entity-ownership-service>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/AbstractEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/AbstractEvent.java
new file mode 100644 (file)
index 0000000..8218cb6
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2014, 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+
+/**
+ * Abstract class for events used by neutron northbound and southbound events.
+ */
+public abstract class AbstractEvent {
+
+    public enum HandlerType {
+        SOUTHBOUND,
+        NEUTRON_FLOATING_IP,
+        NEUTRON_NETWORK,
+        NEUTRON_PORT,
+        NEUTRON_PORT_SECURITY,
+        NEUTRON_ROUTER,
+        NEUTRON_SUBNET,
+        NEUTRON_FWAAS,
+        NEUTRON_LOAD_BALANCER,
+        NEUTRON_LOAD_BALANCER_POOL,
+        NEUTRON_LOAD_BALANCER_POOL_MEMBER,
+        NODE,
+        NEUTRON_L3_ADAPTER,
+        DISTRIBUTED_ARP_SERVICE;
+
+        public static final int size = HandlerType.values().length;
+    }
+
+    private HandlerType handlerType;
+    private Action action;
+    private int transactionId;
+
+    public int getTransactionId() {
+        return transactionId;
+    }
+
+    private static int txId = 0;
+    private static int incTxId() {
+        return ++txId;
+    }
+    public static int getTxId() {
+        return txId;
+    }
+
+    private AbstractEvent() {
+        // this is private to force proper construction
+    }
+
+    protected AbstractEvent(HandlerType handlerType, Action action) {
+        this.handlerType = handlerType;
+        this.action = action;
+        this.transactionId = incTxId();
+    }
+
+    public HandlerType getHandlerType() {
+        return handlerType;
+    }
+
+    public Action getAction() {
+        return action;
+    }
+
+    @Override
+    public String toString() {
+        return "AbstractEvent [transactionId=" + transactionId
+                + " handlerType=" + handlerType + " action=" + action + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((handlerType == null) ? 0 : handlerType.hashCode());
+        result = prime * result + ((action == null) ? 0 : action.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AbstractEvent other = (AbstractEvent) obj;
+        if (handlerType == null) {
+            if (other.handlerType != null) {
+                return false;
+            }
+        } else if (!handlerType.equals(other.handlerType)) {
+            return false;
+        }
+        if (action == null) {
+            if (other.action != null) {
+                return false;
+            }
+        } else if (!action.equals(other.action)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/AbstractHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/AbstractHandler.java
new file mode 100644 (file)
index 0000000..6b1b6a2
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+
+import com.google.common.base.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.HttpURLConnection;
+
+/**
+ * OpenStack related events originate from multiple north callbacks as well as south.
+ * This interface provides a layer of abstraction between the event dispatcher and the
+ * handlers.
+ */
+public abstract class AbstractHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    protected volatile EventDispatcher eventDispatcher;
+
+    /**
+     * Convert failure status returned by the  manager into
+     * neutron API service errors.
+     *
+     * @param status  manager status
+     * @return  An error to be returned to neutron API service.
+     */
+    protected static int getException(Status status) {
+        assert !status.isSuccess();
+
+        StatusCode code = status.getCode();
+        LOG.debug(" Exception code - {}, description - {}",
+                code, status.getDescription());
+
+        switch(code) {
+            case BADREQUEST:
+                return HttpURLConnection.HTTP_BAD_REQUEST;
+            case CONFLICT:
+                return HttpURLConnection.HTTP_CONFLICT;
+            case NOTACCEPTABLE:
+                return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+            case NOTFOUND:
+                return HttpURLConnection.HTTP_NOT_FOUND;
+            default:
+                return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        }
+    }
+
+    /**
+     * Enqueue the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    protected void enqueueEvent(AbstractEvent abstractEvent) {
+        LOG.info("enqueueEvent: evenDispatcher: {} - {}", eventDispatcher, abstractEvent);
+        Preconditions.checkNotNull(eventDispatcher);
+        eventDispatcher.enqueueEvent(abstractEvent);
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    public abstract void processEvent(AbstractEvent abstractEvent);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ClusterAwareMdsalUtils.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ClusterAwareMdsalUtils.java
new file mode 100644 (file)
index 0000000..93a7507
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 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.openstack.netvirt;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * Class is a wrapper for MdsalUtils.java class. It wrap all the methods
+ * from MdsalUtils and call it only when *this* instance is net-virt master
+ * instances.
+ *
+ * Created by vishnoianil on 1/11/16.
+ */
+
+public class ClusterAwareMdsalUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClusterAwareMdsalUtils.class);
+    private final MdsalUtils mdsalUtils;
+
+    /**
+     * Class constructor setting the MdsalUtils instance.
+     *
+     * @param dataBroker the {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}
+     */
+    public ClusterAwareMdsalUtils(DataBroker dataBroker) {
+        mdsalUtils = new MdsalUtils(dataBroker);
+    }
+
+    /**
+     * Wrapper method to execute delete as a blocking transaction.
+     *
+     * @param store {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} to read from
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean delete(
+            final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
+        if (NetvirtProvider.isMasterProviderInstance()) {
+            return mdsalUtils.delete(store,path);
+        }
+        return true;
+    }
+
+    /**
+     * Wrapper method to execute merge as a blocking transaction.
+     *
+     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean merge(
+            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data) {
+        if (NetvirtProvider.isMasterProviderInstance()) {
+            return mdsalUtils.merge(logicalDatastoreType,path, data);
+        }
+        return true;
+    }
+
+    /**
+     * Wrapper method to execute put as a blocking transaction.
+     *
+     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean put(
+            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data) {
+        if (NetvirtProvider.isMasterProviderInstance()) {
+            return mdsalUtils.put(logicalDatastoreType,path, data);
+        }
+        return true;
+    }
+
+    /**
+     * Wrapper method to executes read as a blocking transaction.
+     * Read is open for all instances to execute their normal
+     * control flow. Because with current implementation all the
+     * net-virt instances execute in similar way, because they want
+     * to build their local caches so that all the instances has same
+     * state of internal cache.
+     *
+     * @param store {@link LogicalDatastoreType} to read
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result as the data object requested
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> D read(
+            final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
+        return mdsalUtils.read(store,path);
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ConfigActivator.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ConfigActivator.java
new file mode 100644 (file)
index 0000000..7623e8c
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2015, 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.openstack.netvirt;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolverListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.IcmpEchoProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.MultiTenantAwareRouter;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.VlanConfigurationCache;
+import org.opendaylight.netvirt.openstack.netvirt.impl.BridgeConfigurationManagerImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.ConfigurationServiceImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
+import org.opendaylight.netvirt.openstack.netvirt.impl.EventDispatcherImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NodeCacheManagerImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.OpenstackRouter;
+import org.opendaylight.netvirt.openstack.netvirt.impl.OvsdbInventoryServiceImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.ProviderNetworkManagerImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.SecurityGroupCacheManagerImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.SecurityServicesImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.SouthboundImpl;
+import org.opendaylight.netvirt.openstack.netvirt.impl.HostConfigService;
+import org.opendaylight.netvirt.openstack.netvirt.impl.VlanConfigurationCacheImpl;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronFirewallInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronFirewallPolicyInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronFirewallRuleInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronFloatingIPInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerListenerInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerPoolInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerPoolMemberInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronNetworkInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronPortInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronRouterInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronSecurityGroupInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronSecurityRuleInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronSubnetInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFirewallAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFirewallPolicyAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSubnetAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.openstack.netvirt.impl.TenantNetworkManagerImpl;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerHealthMonitorInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFirewallRuleAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronPortAware;
+import org.opendaylight.netvirt.utils.neutron.utils.NeutronModelsDataStoreHelper;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigActivator implements BundleActivator {
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigActivator.class);
+    private List<ServiceRegistration<?>> translatorCRUDRegistrations = new ArrayList<>();
+    private List<Pair<Object, ServiceRegistration>> servicesAndRegistrations = new ArrayList<>();
+    private ProviderContext providerContext;
+    private boolean conntrackEnabled = false;
+
+    public ConfigActivator(ProviderContext providerContext) {
+        this.providerContext = providerContext;
+    }
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        LOG.info("ConfigActivator start:");
+        registerCRUDServiceProviders(context, this.providerContext);
+
+        ConfigurationServiceImpl configurationService = new ConfigurationServiceImpl();
+        registerService(context, new String[] {ConfigurationService.class.getName()},
+                null, configurationService);
+
+        BridgeConfigurationManagerImpl bridgeConfigurationManager = new BridgeConfigurationManagerImpl();
+        registerService(context, new String[] {BridgeConfigurationManager.class.getName()},
+                null, bridgeConfigurationManager);
+
+        final TenantNetworkManagerImpl tenantNetworkManager = new TenantNetworkManagerImpl();
+        registerService(context, new String[] {TenantNetworkManager.class.getName()},
+                null, tenantNetworkManager);
+
+        VlanConfigurationCacheImpl vlanConfigurationCache = new VlanConfigurationCacheImpl();
+        registerService(context, new String[] {VlanConfigurationCache.class.getName()},
+                null, vlanConfigurationCache);
+
+        FloatingIPHandler floatingIPHandler = new FloatingIPHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronFloatingIPAware.class},
+                AbstractEvent.HandlerType.NEUTRON_FLOATING_IP, floatingIPHandler);
+
+        final NetworkHandler networkHandler = new NetworkHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronNetworkAware.class},
+                AbstractEvent.HandlerType.NEUTRON_NETWORK, networkHandler);
+
+        SubnetHandler subnetHandler = new SubnetHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronSubnetAware.class},
+                AbstractEvent.HandlerType.NEUTRON_SUBNET, subnetHandler);
+
+        PortHandler portHandler = new PortHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronPortAware.class},
+                AbstractEvent.HandlerType.NEUTRON_PORT, portHandler);
+
+        RouterHandler routerHandler = new RouterHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronRouterAware.class},
+                AbstractEvent.HandlerType.NEUTRON_ROUTER, routerHandler);
+
+        SouthboundHandler southboundHandler = new SouthboundHandler();
+        registerAbstractHandlerService(context, new Class[] {OvsdbInventoryListener.class, NodeCacheListener.class},
+                AbstractEvent.HandlerType.SOUTHBOUND, southboundHandler);
+
+        final LBaaSHandler lBaaSHandler = new LBaaSHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronLoadBalancerAware.class, NodeCacheListener.class},
+                AbstractEvent.HandlerType.NEUTRON_LOAD_BALANCER, lBaaSHandler);
+
+        final LBaaSPoolHandler lBaaSPoolHandler = new LBaaSPoolHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronLoadBalancerPoolAware.class},
+                AbstractEvent.HandlerType.NEUTRON_LOAD_BALANCER_POOL, lBaaSPoolHandler);
+
+        final LBaaSPoolMemberHandler lBaaSPoolMemberHandler = new LBaaSPoolMemberHandler();
+        registerAbstractHandlerService(context, new Class[] {INeutronLoadBalancerPoolMemberAware.class},
+                AbstractEvent.HandlerType.NEUTRON_LOAD_BALANCER_POOL_MEMBER, lBaaSPoolMemberHandler);
+
+        PortSecurityHandler portSecurityHandler = new PortSecurityHandler();
+        registerAbstractHandlerService(context,
+                new Class[] {INeutronSecurityRuleAware.class, INeutronSecurityGroupAware.class},
+                AbstractEvent.HandlerType.NEUTRON_PORT_SECURITY, portSecurityHandler);
+
+        final SecurityServicesImpl securityServices = new SecurityServicesImpl(conntrackEnabled);
+        registerService(context,
+                new String[]{SecurityServicesManager.class.getName()}, null, securityServices);
+
+        final SecurityGroupCacheManger securityGroupCacheManger = new SecurityGroupCacheManagerImpl();
+        registerService(context,
+                        new String[]{SecurityGroupCacheManger.class.getName()}, null, securityGroupCacheManger);
+
+        registerService(context,
+                new String[]{SecurityServicesManager.class.getName()}, null, securityServices);
+
+        FWaasHandler fWaasHandler = new FWaasHandler();
+        registerAbstractHandlerService(context,
+                new Class[] {INeutronFirewallAware.class, INeutronFirewallRuleAware.class, INeutronFirewallPolicyAware.class},
+                AbstractEvent.HandlerType.NEUTRON_FWAAS, fWaasHandler);
+
+        ProviderNetworkManagerImpl providerNetworkManager = new ProviderNetworkManagerImpl();
+        registerService(context,
+                new String[]{NetworkingProviderManager.class.getName()}, null, providerNetworkManager);
+
+        EventDispatcherImpl eventDispatcher = new EventDispatcherImpl();
+        registerService(context,
+                new String[]{EventDispatcher.class.getName()}, null, eventDispatcher);
+
+        final NeutronL3Adapter neutronL3Adapter = new NeutronL3Adapter(
+                new NeutronModelsDataStoreHelper(this.providerContext.getSALService(DataBroker.class)));
+        registerAbstractHandlerService(context, new Class[] {NeutronL3Adapter.class, GatewayMacResolverListener.class},
+                AbstractEvent.HandlerType.NEUTRON_L3_ADAPTER, neutronL3Adapter);
+
+        // TODO Why is DistributedArpService registered as an event handler without being an AbstractHandlerService?
+        Dictionary<String, Object> distributedArpServiceProperties = new Hashtable<>();
+        distributedArpServiceProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY,
+                AbstractEvent.HandlerType.DISTRIBUTED_ARP_SERVICE);
+        final DistributedArpService distributedArpService = new DistributedArpService();
+        registerService(context,
+                new String[] {DistributedArpService.class.getName()},
+                distributedArpServiceProperties, distributedArpService);
+
+        OpenstackRouter openstackRouter = new OpenstackRouter();
+        registerService(context,
+                new String[]{MultiTenantAwareRouter.class.getName()}, null, openstackRouter);
+
+        Southbound southbound = new SouthboundImpl(providerContext.getSALService(DataBroker.class));
+        registerService(context,
+                new String[]{Southbound.class.getName()}, null, southbound);
+
+        HostConfigService hostConfigService = new HostConfigService(providerContext.getSALService(DataBroker.class));
+        registerService(context,
+                new String[]{HostConfigService.class.getName()}, null, hostConfigService);
+
+        NodeCacheManagerImpl nodeCacheManager = new NodeCacheManagerImpl();
+        registerAbstractHandlerService(context, new Class[] {NodeCacheManager.class},
+                AbstractEvent.HandlerType.NODE, nodeCacheManager);
+
+        OvsdbInventoryServiceImpl ovsdbInventoryService = new OvsdbInventoryServiceImpl(providerContext);
+        registerService(context,
+                new String[] {OvsdbInventoryService.class.getName()}, null, ovsdbInventoryService);
+
+        // Call .setDependencies() starting with the last service registered
+        for (int i = servicesAndRegistrations.size() - 1; i >= 0; i--) {
+            Pair<Object, ServiceRegistration> serviceAndRegistration = servicesAndRegistrations.get(i);
+            Object service = serviceAndRegistration.getLeft();
+            ServiceRegistration<?> serviceRegistration = serviceAndRegistration.getRight();
+            LOG.info("Setting dependencies on service {}/{}, {}", i, servicesAndRegistrations.size(),
+                    service.getClass());
+            if (service instanceof ConfigInterface) {
+                ((ConfigInterface) service).setDependencies(
+                        serviceRegistration != null ? serviceRegistration.getReference() : null);
+                LOG.info("Dependencies set");
+            } else {
+                LOG.warn("Service isn't a ConfigInterface");
+            }
+        }
+
+        // TODO check if services are already available and setDependencies
+        // addingService may not be called if the service is already available when the ServiceTracker
+        // is started
+        trackService(context, INeutronNetworkCRUD.class, tenantNetworkManager, networkHandler, lBaaSHandler,
+                lBaaSPoolHandler, lBaaSPoolMemberHandler, neutronL3Adapter, distributedArpService);
+        trackService(context, INeutronSubnetCRUD.class, lBaaSHandler, lBaaSPoolHandler, lBaaSPoolMemberHandler,
+                securityServices, neutronL3Adapter);
+        trackService(context, INeutronPortCRUD.class, tenantNetworkManager, lBaaSHandler, lBaaSPoolHandler,
+                lBaaSPoolMemberHandler, securityServices, neutronL3Adapter, distributedArpService);
+        trackService(context, INeutronFloatingIPCRUD.class, neutronL3Adapter);
+        trackService(context, INeutronLoadBalancerCRUD.class, lBaaSHandler, lBaaSPoolHandler, lBaaSPoolMemberHandler);
+        trackService(context, INeutronLoadBalancerPoolCRUD.class, lBaaSHandler, lBaaSPoolMemberHandler);
+        trackService(context, LoadBalancerProvider.class, lBaaSHandler, lBaaSPoolHandler, lBaaSPoolMemberHandler);
+        trackService(context, ArpProvider.class, neutronL3Adapter, distributedArpService);
+        trackService(context, InboundNatProvider.class, neutronL3Adapter);
+        trackService(context, OutboundNatProvider.class, neutronL3Adapter);
+        trackService(context, RoutingProvider.class, neutronL3Adapter);
+        trackService(context, L3ForwardingProvider.class, neutronL3Adapter);
+        trackService(context, GatewayMacResolver.class, neutronL3Adapter);
+        trackService(context, IngressAclProvider.class, securityServices);
+        trackService(context, EgressAclProvider.class, securityServices);
+        trackService(context, IcmpEchoProvider.class, neutronL3Adapter);
+
+        // We no longer need to track the services, avoid keeping references around
+        servicesAndRegistrations.clear();
+    }
+
+    private void registerCRUDServiceProviders(BundleContext context,
+            ProviderContext providerContext) {
+        LOG.debug("Registering CRUD service providers");
+        NeutronRouterInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronPortInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronSubnetInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronNetworkInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronSecurityGroupInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronSecurityRuleInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFirewallInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFirewallPolicyInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFirewallRuleInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerPoolInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerListenerInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerHealthMonitorInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerPoolMemberInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFloatingIPInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+    }
+
+    private void trackService(BundleContext context, final Class<?> clazz, final ConfigInterface... dependents) {
+        @SuppressWarnings("unchecked")
+        ServiceTracker tracker = new ServiceTracker(context, clazz, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService " + clazz.getName());
+                Object service = context.getService(reference);
+                if (service != null) {
+                    for (ConfigInterface dependent : dependents) {
+                        dependent.setDependencies(service);
+                    }
+                }
+                return service;
+            }
+        };
+        tracker.open();
+    }
+
+    private void registerAbstractHandlerService(BundleContext context, Class[] interfaces,
+                                                AbstractEvent.HandlerType handlerType, AbstractHandler handler) {
+        Dictionary<String, Object> properties = new Hashtable<>();
+        properties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY, handlerType);
+        String[] interfaceNames = new String[interfaces.length + 1];
+        for (int i = 0; i < interfaces.length; i++) {
+            interfaceNames[i] = interfaces[i].getName();
+        }
+        interfaceNames[interfaces.length] = AbstractHandler.class.getName();
+        registerService(context, interfaceNames, properties, handler);
+    }
+
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        LOG.info("ConfigActivator stop");
+        // ServiceTrackers and services are already released when bundle stops,
+        // so we don't need to close the trackers or unregister the services
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String[] interfaces,
+                                                   Dictionary<String, Object> properties, Object impl) {
+        ServiceRegistration serviceRegistration = bundleContext.registerService(interfaces, impl, properties);
+        if (serviceRegistration == null) {
+            LOG.warn("Service registration for {} failed to return a ServiceRegistration instance", impl.getClass());
+        }
+        servicesAndRegistrations.add(Pair.of(impl, serviceRegistration));
+        return serviceRegistration;
+    }
+
+    public void setConntrackEnabled(boolean conntrackEnabled) {
+        this.conntrackEnabled = conntrackEnabled;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ConfigInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/ConfigInterface.java
new file mode 100644 (file)
index 0000000..66ef437
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt;
+
+import org.osgi.framework.ServiceReference;
+
+public interface ConfigInterface {
+    void setDependencies(ServiceReference serviceReference);
+    void setDependencies(Object impl);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/FWaasHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/FWaasHandler.java
new file mode 100644 (file)
index 0000000..ce8d7cf
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFirewallPolicyAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFirewallAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFirewallRuleAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for OpenStack Neutron v2.0 Port Firewall API calls.
+ */
+public class FWaasHandler extends AbstractHandler
+        implements INeutronFirewallAware, INeutronFirewallRuleAware,
+        INeutronFirewallPolicyAware, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FWaasHandler.class);
+
+    /**
+     * Invoked when a Firewall Rules creation is requested
+     * to indicate if the specified Rule can be created.
+     *
+     * @param neutronFirewall  An instance of proposed new Neutron Firewall object.
+     * @return HttpURLConnection A HTTP status code to the creation request.
+     */
+    @Override
+    public int canCreateNeutronFirewall(NeutronFirewall neutronFirewall) {
+        return HttpURLConnection.HTTP_CREATED;
+    }
+
+    @Override
+    public void neutronFirewallCreated(NeutronFirewall neutronFirewall) {
+        LOG.debug("Neutron Firewall created by Neutron: {}", neutronFirewall);
+
+        int result = canCreateNeutronFirewall(neutronFirewall);
+        if (result != HttpURLConnection.HTTP_CREATED) {
+            LOG.error("Neutron Firewall creation failed: {} ", result);
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronFirewall(NeutronFirewall delta, NeutronFirewall original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronFirewallUpdated(NeutronFirewall neutronFirewall) {
+        LOG.debug("NeutronFirewall updated from Neutron: {}", neutronFirewall);
+    }
+
+    @Override
+    public int canDeleteNeutronFirewall(NeutronFirewall neutronFirewall) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronFirewallDeleted(NeutronFirewall neutronFirewall) {
+        //TODO: Trigger flowmod removals
+        int result = canDeleteNeutronFirewall(neutronFirewall);
+        if  (result != HttpURLConnection.HTTP_OK) {
+            LOG.error(" delete Neutron Firewall validation failed for result - {} ", result);
+        }
+    }
+
+    /**
+     * Invoked when a Firewall Rule creation is requested
+     * to indicate if the specified Rule can be created.
+     *
+     * @param neutronFirewallRule  An instance of proposed new Neutron Firewall Rule object.
+     * @return HttpURLConnection A HTTP status code to the creation request.
+     */
+    @Override
+    public int canCreateNeutronFirewallRule(NeutronFirewallRule neutronFirewallRule) {
+        return HttpURLConnection.HTTP_CREATED;
+    }
+
+    @Override
+    public void neutronFirewallRuleCreated(NeutronFirewallRule neutronFirewallRule) {
+        LOG.debug("NeutronFirewallRule created by Neutron: {}", neutronFirewallRule);
+
+        int result = canCreateNeutronFirewallRule(neutronFirewallRule);
+        if (result != HttpURLConnection.HTTP_CREATED) {
+            LOG.error("Neutron Firewall Rule creation failed {} ", result);
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronFirewallRule(NeutronFirewallRule delta, NeutronFirewallRule original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronFirewallRuleUpdated(NeutronFirewallRule neutronFirewallRule) {
+        LOG.debug("Neutron Firewall Rule updated from Neutron: {}", neutronFirewallRule);
+    }
+
+    @Override
+    public int canDeleteNeutronFirewallRule(NeutronFirewallRule neutronFirewallRule) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronFirewallRuleDeleted(NeutronFirewallRule neutronFirewallRule) {
+        int result = canDeleteNeutronFirewallRule(neutronFirewallRule);
+        if  (result != HttpURLConnection.HTTP_OK) {
+            LOG.error(" delete Neutron Firewall Rule validation failed for result - {} ", result);
+        }
+    }
+
+    /**
+     * Invoked when a Firewall Policy creation is requested
+     * to indicate if the specified Rule can be created.
+     *
+     * @param neutronFirewallPolicy  An instance of proposed new Neutron Firewall Policy object.
+     * @return HttpURLConnection A HTTP status code to the creation request.
+     */
+    @Override
+    public int canCreateNeutronFirewallPolicy(NeutronFirewallPolicy neutronFirewallPolicy) {
+        return HttpURLConnection.HTTP_CREATED;
+    }
+
+    @Override
+    public void neutronFirewallPolicyCreated(NeutronFirewallPolicy neutronFirewallPolicy) {
+        LOG.debug("Neutron Firewall Policy created by Neutron: {}", neutronFirewallPolicy);
+
+        int result = canCreateNeutronFirewallPolicy(neutronFirewallPolicy);
+        if (result != HttpURLConnection.HTTP_CREATED) {
+            LOG.debug("Neutron Firewall Policy creation failed: {} ", result);
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronFirewallPolicy(NeutronFirewallPolicy delta, NeutronFirewallPolicy original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronFirewallPolicyUpdated(NeutronFirewallPolicy neutronFirewallPolicy) {
+        LOG.debug("Neutron Firewall Policy updated from Neutron: {}", neutronFirewallPolicy);
+    }
+
+    @Override
+    public int canDeleteNeutronFirewallPolicy(NeutronFirewallPolicy neutronFirewallPolicy) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronFirewallPolicyDeleted(NeutronFirewallPolicy neutronFirewallPolicy) {
+        int result = canDeleteNeutronFirewallPolicy(neutronFirewallPolicy);
+        if  (result != HttpURLConnection.HTTP_OK) {
+            LOG.error(" delete Neutron Firewall Policy validation failed for result - {} ", result);
+        }
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent new FWaas Event@see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            // TODO: add handling of events here, once callbacks do something
+            //       other than logging.
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/FloatingIPHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/FloatingIPHandler.java
new file mode 100644 (file)
index 0000000..231b003
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for Neutron Floating IP.
+ */
+public class FloatingIPHandler extends AbstractHandler
+        implements INeutronFloatingIPAware, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FloatingIPHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile NeutronL3Adapter neutronL3Adapter;
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be created
+     *
+     * @param floatingIP
+     *            instance of proposed new Neutron FloatingIP object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canCreateFloatingIP(NeutronFloatingIP floatingIP) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been created
+     *
+     * @param floatingIP
+     *            instance of new Neutron FloatingIP object
+     */
+    @Override
+    public void neutronFloatingIPCreated(NeutronFloatingIP floatingIP) {
+        enqueueEvent(new NorthboundEvent(floatingIP, Action.ADD));
+    }
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the floatingIP object using patch semantics
+     * @param original
+     *            instance of the Neutron FloatingIP object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canUpdateFloatingIP(NeutronFloatingIP delta, NeutronFloatingIP original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been updated
+     *
+     * @param floatingIP
+     *            instance of modified Neutron FloatingIP object
+     */
+    @Override
+    public void neutronFloatingIPUpdated(NeutronFloatingIP floatingIP) {
+        enqueueEvent(new NorthboundEvent(floatingIP, Action.UPDATE));
+    }
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be deleted
+     *
+     * @param floatingIP
+     *            instance of the Neutron FloatingIP object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canDeleteFloatingIP(NeutronFloatingIP floatingIP) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been deleted
+     *
+     * @param floatingIP
+     *            instance of deleted Neutron FloatingIP object
+     */
+    @Override
+    public void neutronFloatingIPDeleted(NeutronFloatingIP floatingIP) {
+        enqueueEvent(new NorthboundEvent(floatingIP, Action.DELETE));
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                // fall through
+            case DELETE:
+                // fall through
+            case UPDATE:
+                neutronL3Adapter.handleNeutronFloatingIPEvent(ev.getNeutronFloatingIP(), ev.getAction());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSHandler.java
new file mode 100644 (file)
index 0000000..6e3c941
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2014, 2015 SDN Hub, LLC. 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for /v2.0/loadbalancers.
+ */
+
+//TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware, INeutronLoadBalancerPoolMemberAware,
+
+public class LBaaSHandler extends AbstractHandler
+        implements INeutronLoadBalancerAware, ConfigInterface, NodeCacheListener {
+    private static final Logger LOG = LoggerFactory.getLogger(LBaaSHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile INeutronLoadBalancerCRUD neutronLBCache;
+    private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
+    private volatile LoadBalancerProvider loadBalancerProvider;
+    private volatile NodeCacheManager nodeCacheManager;
+
+    @Override
+    public int canCreateNeutronLoadBalancer(NeutronLoadBalancer neutronLB) {
+        //Always allowed and not wait for pool and members to be created
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronLoadBalancerCreated(NeutronLoadBalancer neutronLB) {
+        LOG.debug("Neutron LB Creation : {}", neutronLB.toString());
+        enqueueEvent(new NorthboundEvent(neutronLB, Action.ADD));
+    }
+
+    /**
+     * Assuming that the pool information is fully populated before this call is made,
+     * we go with creating the LoadBalancerConfiguration object for this call with
+     * all information that is necessary to insert flow_mods
+     */
+    private void doNeutronLoadBalancerCreate(NeutronLoadBalancer neutronLB) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+
+        if (!lbConfig.isValid()) {
+            LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB {} creation because no nodes available.", lbConfig.getName());
+        } else {
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
+            }
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original) {
+        //Update allowed anytime, even when the LB has no active pool yet
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronLoadBalancerUpdated(NeutronLoadBalancer neutronLB) {
+        LOG.debug("Neutron LB Update : {}", neutronLB.toString());
+        enqueueEvent(new NorthboundEvent(neutronLB, Action.UPDATE));
+    }
+
+    @Override
+    public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer neutronLB) {
+        //Always allowed and not wait for pool to stop using it
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronLoadBalancerDeleted(NeutronLoadBalancer neutronLB) {
+        LOG.debug("Neutron LB Deletion : {}", neutronLB.toString());
+        enqueueEvent(new NorthboundEvent(neutronLB, Action.DELETE));
+    }
+
+    private void doNeutronLoadBalancerDelete(NeutronLoadBalancer neutronLB) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+
+        if (!lbConfig.isValid()) {
+            LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB {} deletion because no nodes available.", lbConfig.getName());
+        } else {
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
+            }
+        }
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        LOG.debug("Processing Loadbalancer event {}", abstractEvent);
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                doNeutronLoadBalancerCreate(ev.getLoadBalancer());
+                break;
+            case DELETE:
+                doNeutronLoadBalancerDelete(ev.getLoadBalancer());
+                break;
+            case UPDATE:
+                /**
+                 * Currently member update requires delete and re-adding
+                 * Also, weights and weight updates are not supported
+                 */
+                doNeutronLoadBalancerDelete(ev.getLoadBalancer());
+                doNeutronLoadBalancerCreate(ev.getLoadBalancer());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    /**
+     * Useful utility for extracting the loadbalancer instance
+     * configuration from the neutron LB cache
+     * @param neutronLB neutron load balancer object
+     * @return returns load balancer configuration
+     */
+    public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancer neutronLB) {
+        String loadBalancerName = neutronLB.getLoadBalancerName();
+        String loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
+        String loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
+
+        LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
+        Map.Entry<String,String> providerInfo =
+                NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, loadBalancerSubnetID);
+        if (providerInfo != null) {
+            lbConfig.setProviderNetworkType(providerInfo.getKey());
+            lbConfig.setProviderSegmentationId(providerInfo.getValue());
+        }
+        lbConfig.setVmac(NeutronCacheUtils.getMacAddress(neutronPortCache, loadBalancerSubnetID, loadBalancerVip));
+
+        for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
+            List<NeutronLoadBalancerPoolMember> members = neutronLBPool.getLoadBalancerPoolMembers();
+            String memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+            if (memberProtocol == null) {
+                continue;
+            }
+
+            if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
+                  memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+                  memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
+                continue;
+            }
+            for (NeutronLoadBalancerPoolMember neutronLBPoolMember: members) {
+                Boolean memberAdminStateIsUp = neutronLBPoolMember.getPoolMemberAdminStateIsUp();
+                String memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
+                if (memberSubnetID != null && memberAdminStateIsUp != null &&
+                        memberSubnetID.equals(loadBalancerSubnetID) && memberAdminStateIsUp) {
+                    String memberID = neutronLBPoolMember.getID();
+                    String memberIP = neutronLBPoolMember.getPoolMemberAddress();
+                    Integer memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
+                    if (memberID == null || memberIP == null || memberPort == null) {
+                        LOG.debug("Neutron LB pool member details incomplete: {}", neutronLBPoolMember);
+                        continue;
+                    }
+                    String memberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, memberSubnetID, memberIP);
+                    if (memberMAC == null) {
+                        continue;
+                    }
+                    lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
+                }
+            }
+        }
+        return lbConfig;
+    }
+
+    /**
+     * On the addition of a new node, we iterate through all existing loadbalancer
+     * instances and program the node for all of them. It is sufficient to do that only
+     * when a node is added, and only for the LB instances (and not individual members).
+     */
+    @Override
+    public void notifyNode(Node node, Action type) {
+        LOG.debug("notifyNode: Node {} update {} from Controller's inventory Service", node, type);
+        Preconditions.checkNotNull(loadBalancerProvider);
+
+        for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
+            LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
+            if (!lbConfig.isValid()) {
+                LOG.debug("Neutron LB configuration invalid for {} ", lbConfig.getName());
+            } else {
+               if (type.equals(Action.ADD)) {
+                   loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
+
+               /* When node disappears, we do nothing for now. Making a call to
+                * loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE)
+                * can lead to TransactionCommitFailedException. Similarly when node is changed,
+                * because of remove followed by add, we do nothing.
+                */
+
+                 //(type.equals(UpdateType.REMOVED) || type.equals(UpdateType.CHANGED))
+               }
+            }
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        loadBalancerProvider =
+                (LoadBalancerProvider) ServiceHelper.getGlobalInstance(LoadBalancerProvider.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        nodeCacheManager.cacheListenerAdded(serviceReference, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        } else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerCRUD) {
+            neutronLBCache = (INeutronLoadBalancerCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerPoolCRUD) {
+            neutronLBPoolCache = (INeutronLoadBalancerPoolCRUD)impl;
+        } else if (impl instanceof LoadBalancerProvider) {
+            loadBalancerProvider = (LoadBalancerProvider)impl;
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolHandler.java
new file mode 100755 (executable)
index 0000000..7a28fc6
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2014, 2015 SDN Hub, LLC. 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+/**
+ * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for
+ * /v2.0/pools . It is possible that each pool spans multiple subnets.
+ * In that case, the user should be creating a separate VIP for each subnet.
+ */
+
+public class LBaaSPoolHandler extends AbstractHandler
+        implements INeutronLoadBalancerPoolAware, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LBaaSPoolHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile INeutronLoadBalancerCRUD neutronLBCache;
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
+    private volatile LoadBalancerProvider loadBalancerProvider;
+    private volatile NodeCacheManager nodeCacheManager;
+
+    @Override
+    public int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool neutronLBPool) {
+        String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+        if (poolProtocol == null) {
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        } else if (!(poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
+                poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+                poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
+            return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+        } else {
+            return HttpURLConnection.HTTP_OK;
+        }
+    }
+
+    @Override
+    public void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool neutronLBPool) {
+        LOG.debug("Neutron LB Pool Creation : {}", neutronLBPool.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPool, Action.ADD));
+    }
+
+    /**
+     * Assuming that the pool information is fully populated before this call is made,
+     * we go with creating the LoadBalancerConfiguration object for this call with
+     * all information that is necessary to insert flow_mods
+     */
+    private void doNeutronLoadBalancerPoolCreate(NeutronLoadBalancerPool neutronLBPool) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+        List<LoadBalancerConfiguration> lbConfigList = extractLBConfiguration(neutronLBPool);
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (lbConfigList == null) {
+            LOG.debug("Neutron LB configuration invalid for pool {} ", neutronLBPool.getID());
+        } else if (lbConfigList.size() == 0) {
+            LOG.debug("No Neutron LB VIP not created yet for pool {} ", neutronLBPool.getID());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB pool {} creation because no nodes available.", neutronLBPool.getID());
+        } else {
+            for (LoadBalancerConfiguration lbConfig: lbConfigList) {
+                if (!lbConfig.isValid()) {
+                    LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+                } else {
+                    for (Node node : nodes) {
+                        loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original) {
+        return HttpURLConnection.HTTP_NOT_IMPLEMENTED;
+    }
+
+    @Override
+    public void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool neutronLBPool) {
+        LOG.debug("Neutron LB Pool Update : {}", neutronLBPool.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPool, Action.UPDATE));
+    }
+
+    @Override
+    public int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool neutronLBPool) {
+        String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+        if (poolProtocol == null) {
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        } else if (!(poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
+                poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+                poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
+            return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+        } else {
+            return HttpURLConnection.HTTP_OK;
+        }
+    }
+
+    @Override
+    public void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool neutronLBPool) {
+        LOG.debug("Neutron LB Pool Deletion : {}", neutronLBPool.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPool, Action.DELETE));
+    }
+
+    private void doNeutronLoadBalancerPoolDelete(NeutronLoadBalancerPool neutronLBPool) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+
+        List<LoadBalancerConfiguration> lbConfigList = extractLBConfiguration(neutronLBPool);
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (lbConfigList == null) {
+            LOG.debug("Neutron LB configuration invalid for pool {} ", neutronLBPool.getID());
+        } else if (lbConfigList.size() == 0) {
+            LOG.debug("No Neutron LB VIP not created yet for pool {} ", neutronLBPool.getID());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB pool {} deletion because no nodes available.", neutronLBPool.getID());
+        } else {
+            for (LoadBalancerConfiguration lbConfig: lbConfigList) {
+                if (!lbConfig.isValid()) {
+                    LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+                } else {
+                    for (Node node : nodes) {
+                        loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        LOG.debug("Processing Loadbalancer Pool event {}", abstractEvent);
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                doNeutronLoadBalancerPoolCreate(ev.getLoadBalancerPool());
+                break;
+            case DELETE:
+                doNeutronLoadBalancerPoolDelete(ev.getLoadBalancerPool());
+                break;
+            case UPDATE:
+                /**
+                 * Typical upgrade involves changing algorithm. Right now
+                 * we do not support this flexibility. TODO
+                 */
+                LOG.warn("Load balancer pool update is not supported");
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    /**
+     * Useful utility for extracting the loadbalancer instance. With
+     * each LB pool, we allow multiple VIP and LB to be instantiated.
+     * @param neutronLBPool Neutron load balancer pool object
+     * @return list of loadbalancer configuration of pool members
+     */
+    public List<LoadBalancerConfiguration> extractLBConfiguration(NeutronLoadBalancerPool neutronLBPool) {
+        String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+        if (poolProtocol == null) {
+            return null;
+        }
+        if (!(poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+                poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
+            return null;
+        }
+
+        List<NeutronLoadBalancerPoolMember> poolMembers = neutronLBPool.getLoadBalancerPoolMembers();
+        if (poolMembers.size() == 0) {
+            LOG.debug("Neutron LB pool is empty: {}", neutronLBPool);
+            return null;
+        }
+
+        List<LoadBalancerConfiguration> lbConfigList = Lists.newLinkedList();
+
+        /* Iterate over all the Loadbalancers created so far and identify VIP
+         */
+        for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
+            String loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
+            String loadBalancerName = neutronLB.getLoadBalancerName();
+            String loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
+
+            LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
+            Map.Entry<String,String> providerInfo = NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, loadBalancerSubnetID);
+            if (providerInfo != null) {
+                lbConfig.setProviderNetworkType(providerInfo.getKey());
+                lbConfig.setProviderSegmentationId(providerInfo.getValue());
+            }
+            lbConfig.setVmac(NeutronCacheUtils.getMacAddress(neutronPortCache, loadBalancerSubnetID, loadBalancerVip));
+
+            /* Iterate over all the members in this pool and find those in same
+             * subnet as the VIP. Those will be included in the lbConfigList
+             */
+            String memberSubnetID, memberIP, memberID, memberMAC;
+            Integer memberPort;
+            Boolean memberAdminStateIsUp;
+            for (NeutronLoadBalancerPoolMember neutronLBPoolMember: neutronLBPool.getLoadBalancerPoolMembers()) {
+                memberAdminStateIsUp = neutronLBPoolMember.getPoolMemberAdminStateIsUp();
+                memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
+                if (memberSubnetID != null && memberAdminStateIsUp != null &&
+                        memberSubnetID.equals(loadBalancerSubnetID) && memberAdminStateIsUp) {
+                    memberID = neutronLBPoolMember.getID();
+                    memberIP = neutronLBPoolMember.getPoolMemberAddress();
+                    memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
+                    if (memberID == null || memberIP == null || memberPort == null) {
+                        LOG.debug("Neutron LB pool member details incomplete: {}", neutronLBPoolMember);
+                        continue;
+                    }
+                    memberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, memberSubnetID, memberIP);
+                    if (memberMAC == null) {
+                        continue;
+                    }
+                    lbConfig.addMember(memberID, memberIP, memberMAC, poolProtocol, memberPort);
+                }
+            }
+
+            if (lbConfig.getMembers().size() > 0) {
+                lbConfigList.add(lbConfig);
+            }
+        }
+
+        return lbConfigList;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        loadBalancerProvider =
+                (LoadBalancerProvider) ServiceHelper.getGlobalInstance(LoadBalancerProvider.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        } else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerCRUD) {
+            neutronLBCache = (INeutronLoadBalancerCRUD)impl;
+        } else if (impl instanceof LoadBalancerProvider) {
+            loadBalancerProvider = (LoadBalancerProvider)impl;
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolMemberHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolMemberHandler.java
new file mode 100755 (executable)
index 0000000..fd251dc
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2014, 2015 SDN Hub, LLC. 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for
+ * /v2.0/pools/{pool_id}/members
+ */
+
+public class LBaaSPoolMemberHandler extends AbstractHandler
+        implements INeutronLoadBalancerPoolMemberAware, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(LBaaSPoolMemberHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
+    private volatile INeutronLoadBalancerCRUD neutronLBCache;
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
+    private volatile LoadBalancerProvider loadBalancerProvider;
+    private volatile NodeCacheManager nodeCacheManager;
+
+    @Override
+    public int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
+        if (lbConfig == null) {
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        } else if (!lbConfig.isValid()) {
+            return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+        } else {
+            return HttpURLConnection.HTTP_OK;
+        }
+    }
+
+    @Override
+    public void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        LOG.debug("Neutron LB Pool Member Creation : {}", neutronLBPoolMember.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.ADD));
+    }
+
+    /**
+     * Assuming that the pool information is fully populated before this call is made,
+     * we go with creating the LoadBalancerConfiguration object for this call with
+     * all information that is necessary to insert flow_mods
+     */
+    private void doNeutronLoadBalancerPoolMemberCreate(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
+        final List<Node> nodes =
+                nodeCacheManager.getBridgeNodes();
+        if (lbConfig == null) {
+            LOG.debug("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
+        } else if (lbConfig.getVip() == null) {
+            LOG.debug("Neutron LB VIP not created yet for member {} ", neutronLBPoolMember.getID());
+        } else if (!lbConfig.isValid()) {
+            LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB pool member {} creation because no nodes available.", neutronLBPoolMember.getID());
+        } else {
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerPoolMemberRules(node,
+                        lbConfig,
+                        lbConfig.getMembers().get(neutronLBPoolMember.getID()), Action.ADD);
+            }
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta, NeutronLoadBalancerPoolMember original) {
+        return HttpURLConnection.HTTP_NOT_IMPLEMENTED;
+    }
+
+    @Override
+    public void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        LOG.debug("Neutron LB Pool Member Update : {}", neutronLBPoolMember.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.UPDATE));
+    }
+
+    @Override
+    public int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
+        if (lbConfig == null) {
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        } else if (!lbConfig.isValid()) {
+            return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+        } else {
+            return HttpURLConnection.HTTP_OK;
+        }
+    }
+
+    @Override
+    public void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        LOG.debug("Neutron LB Pool Member Deletion : {}", neutronLBPoolMember.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.DELETE));
+    }
+
+    private void doNeutronLoadBalancerPoolMemberDelete(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (lbConfig == null) {
+            LOG.debug("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
+        } else if (lbConfig.getVip() == null) {
+            LOG.debug("Neutron LB VIP not created yet for member {} ", neutronLBPoolMember.getID());
+        } else if (!lbConfig.isValid()) {
+            LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB pool member {} deletion because no nodes available.", neutronLBPoolMember.getID());
+        } else {
+            /* As of now, deleting a member involves recomputing member indices.
+             * This is best done through a complete update of the load balancer instance.
+             */
+            LoadBalancerConfiguration newLBConfig = new LoadBalancerConfiguration(lbConfig);
+            newLBConfig.removeMember(neutronLBPoolMember.getID());
+
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
+                loadBalancerProvider.programLoadBalancerRules(node, newLBConfig, Action.ADD);
+            }
+        }
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        LOG.debug("Processing Loadbalancer member event {}", abstractEvent);
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                doNeutronLoadBalancerPoolMemberCreate(ev.getLoadBalancerPoolMember());
+                break;
+            case DELETE:
+                doNeutronLoadBalancerPoolMemberDelete(ev.getLoadBalancerPoolMember());
+                break;
+            case UPDATE:
+                /**
+                 * Typical upgrade involves changing weights. Since weights are not
+                 * supported yet, updates are not supported either. TODO
+                 */
+                LOG.warn("Load balancer pool member update is not supported");
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    /**
+     * Useful utility for extracting the loadbalancer instance
+     * configuration from the neutron LB cache based on member info
+     * @param neutronLBPoolMember Neutron LB pool member object
+     * @return load balancer configuration of the pool member
+     */
+    public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        String memberID = neutronLBPoolMember.getID();
+        String memberIP = neutronLBPoolMember.getPoolMemberAddress();
+        String memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
+        Integer memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
+        String memberPoolID = neutronLBPoolMember.getPoolID();
+
+        if (memberSubnetID == null || memberID == null || memberPoolID == null) {
+            LOG.debug("Neutron LB pool member details incomplete [id={}, pool_id={},subnet_id={}",
+                    memberID, memberPoolID, memberSubnetID);
+            return null;
+        }
+        String memberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, memberSubnetID, memberIP);
+        if (memberMAC == null) {
+            LOG.debug("Neutron LB pool member {} MAC address unavailable", memberID);
+            return null;
+        }
+        NeutronLoadBalancerPool neutronLBPool = neutronLBPoolCache.getNeutronLoadBalancerPool(memberPoolID);
+        if (neutronLBPool == null) {
+            LOG.debug("Neutron LB pool {} unavailable", memberPoolID);
+            return null;
+        }
+        String memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+        if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
+                memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+                memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
+            return null;
+        }
+
+        String loadBalancerSubnetID=null, loadBalancerVip=null, loadBalancerName=null;
+        for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
+            loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
+            if (memberSubnetID.equals(loadBalancerSubnetID)) {
+                loadBalancerName = neutronLB.getLoadBalancerName();
+                loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
+                break;
+            }
+        }
+
+        /**
+         * It is possible that the VIP has not been created yet.
+         * In that case, we create dummy configuration that will not program rules.
+         */
+        LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
+        Map.Entry<String,String> providerInfo = NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, memberSubnetID);
+        if (providerInfo != null) {
+            lbConfig.setProviderNetworkType(providerInfo.getKey());
+            lbConfig.setProviderSegmentationId(providerInfo.getValue());
+        }
+        lbConfig.setVmac(NeutronCacheUtils.getMacAddress(neutronPortCache, loadBalancerSubnetID, loadBalancerVip));
+
+        /* Extract all other active members and include in LB config
+         */
+        String otherMemberID, otherMemberSubnetID, otherMemberIP, otherMemberMAC, otherMemberProtocol;
+        Boolean otherMemberAdminStateIsUp;
+        Integer otherMemberPort;
+
+        for (NeutronLoadBalancerPoolMember otherMember: neutronLBPool.getLoadBalancerPoolMembers()) {
+            otherMemberID = otherMember.getID();
+            if (otherMemberID.equals(memberID)) {
+                continue; //skip
+            }
+
+            otherMemberIP = otherMember.getPoolMemberAddress();
+            otherMemberAdminStateIsUp = otherMember.getPoolMemberAdminStateIsUp();
+            otherMemberSubnetID = otherMember.getPoolMemberSubnetID();
+            otherMemberPort = otherMember.getPoolMemberProtoPort();
+            otherMemberProtocol = memberProtocol;
+
+            if (otherMemberIP != null && otherMemberSubnetID != null && otherMemberAdminStateIsUp != null &&
+                    otherMemberAdminStateIsUp) {
+                otherMemberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, otherMemberSubnetID, otherMemberIP);
+                if (otherMemberMAC == null) {
+                    continue;
+                }
+                lbConfig.addMember(otherMemberID, otherMemberIP, otherMemberMAC, otherMemberProtocol, otherMemberPort);
+            }
+        }
+
+        lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
+        return lbConfig;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        loadBalancerProvider =
+                (LoadBalancerProvider) ServiceHelper.getGlobalInstance(LoadBalancerProvider.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        } else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerCRUD) {
+            neutronLBCache = (INeutronLoadBalancerCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerPoolCRUD) {
+            neutronLBPoolCache = (INeutronLoadBalancerPoolCRUD)impl;
+        } else if (impl instanceof LoadBalancerProvider) {
+            loadBalancerProvider = (LoadBalancerProvider)impl;
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/MdsalHelper.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/MdsalHelper.java
new file mode 100644 (file)
index 0000000..8451bef
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+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.InterfaceTypeDpdk;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkr;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhost;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhostuser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGeneve;
+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.InterfaceTypeGre64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeIpsecGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeIpsecGre64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeLisp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypePatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeSystem;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeTap;
+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.OvsdbBridgeProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow10;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow11;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow12;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow13;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow14;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow15;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeSecure;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeStandalone;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class MdsalHelper {
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalHelper.class);
+    public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
+    public static final String OVSDB_URI_PREFIX = "ovsdb";
+    public static final String BRIDGE_URI_PREFIX = "bridge";
+    public static final String TP_URI_PREFIX = "termination-point";
+    public static final String DISABLE_IN_BAND = "disable-in-band";
+
+    public static final ImmutableBiMap<Class<? extends OvsdbBridgeProtocolBase>,String> OVSDB_PROTOCOL_MAP
+            = new ImmutableBiMap.Builder<Class<? extends OvsdbBridgeProtocolBase>,String>()
+            .put(OvsdbBridgeProtocolOpenflow10.class,"OpenFlow10")
+            .put(OvsdbBridgeProtocolOpenflow11.class,"OpenFlow11")
+            .put(OvsdbBridgeProtocolOpenflow12.class,"OpenFlow12")
+            .put(OvsdbBridgeProtocolOpenflow13.class,"OpenFlow13")
+            .put(OvsdbBridgeProtocolOpenflow14.class,"OpenFlow14")
+            .put(OvsdbBridgeProtocolOpenflow15.class,"OpenFlow15")
+            .build();
+
+    public static final ImmutableBiMap<Class<? extends OvsdbFailModeBase>,String> OVSDB_FAIL_MODE_MAP
+            = new ImmutableBiMap.Builder<Class<? extends OvsdbFailModeBase>,String>()
+            .put(OvsdbFailModeStandalone.class,"standalone")
+            .put(OvsdbFailModeSecure.class,"secure")
+            .build();
+
+    public static final ImmutableBiMap<String, Class<? extends InterfaceTypeBase>> OVSDB_INTERFACE_TYPE_MAP
+    = new ImmutableBiMap.Builder<String, Class<? extends InterfaceTypeBase>>()
+        .put("internal", InterfaceTypeInternal.class)
+        .put("vxlan", InterfaceTypeVxlan.class)
+        .put("patch", InterfaceTypePatch.class)
+        .put("system", InterfaceTypeSystem.class)
+        .put("tap", InterfaceTypeTap.class)
+        .put("geneve", InterfaceTypeGeneve.class)
+        .put("gre", InterfaceTypeGre.class)
+        .put("ipsec_gre", InterfaceTypeIpsecGre.class)
+        .put("gre64", InterfaceTypeGre64.class)
+        .put("ipsec_gre64", InterfaceTypeIpsecGre64.class)
+        .put("lisp", InterfaceTypeLisp.class)
+        .put("dpdk", InterfaceTypeDpdk.class)
+        .put("dpdkr", InterfaceTypeDpdkr.class)
+        .put("dpdkvhost", InterfaceTypeDpdkvhost.class)
+        .put("dpdkvhostuser", InterfaceTypeDpdkvhostuser.class)
+        .build();
+
+
+    public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
+        NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
+        return nodeKey.getNodeId();
+    }
+
+    public static InstanceIdentifier<Topology> createInstanceIdentifier() {
+        return InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID));
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
+        return InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
+                .child(Node.class,new NodeKey(nodeId));
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier(NodeKey ovsdbNodeKey, String bridgeName) {
+       return createInstanceIdentifier(createManagedNodeId(ovsdbNodeKey.getNodeId(), bridgeName));
+    }
+
+    public static NodeId createManagedNodeId(NodeId ovsdbNodeId, String bridgeName) {
+        return new NodeId(ovsdbNodeId.getValue()
+                + "/" + BRIDGE_URI_PREFIX + "/" + bridgeName);
+    }
+
+    public static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node, String portName){
+
+        InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
+                .child(Node.class,node.getKey())
+                .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+
+        LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
+        return terminationPointPath;
+    }
+
+    public static String createOvsdbInterfaceType(Class<? extends InterfaceTypeBase> mdsaltype) {
+        Preconditions.checkNotNull(mdsaltype);
+        ImmutableBiMap<Class<? extends InterfaceTypeBase>, String> mapper =
+                OVSDB_INTERFACE_TYPE_MAP.inverse();
+        return mapper.get(mdsaltype);
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NetvirtProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NetvirtProvider.java
new file mode 100644 (file)
index 0000000..7971094
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class NetvirtProvider implements BindingAwareProvider, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtProvider.class);
+    private BundleContext bundleContext = null;
+    private static DataBroker dataBroker = null;
+    private ConfigActivator activator;
+    private static EntityOwnershipService entityOwnershipService;
+    private static final Entity ownerInstanceEntity = new Entity(
+            Constants.NETVIRT_OWNER_ENTITY_TYPE, Constants.NETVIRT_OWNER_ENTITY_TYPE);
+    private boolean conntrackEnabled = false;
+
+    public NetvirtProvider(BundleContext bundleContext, EntityOwnershipService eos) {
+        LOG.info("NetvirtProvider: bundleContext: {}", bundleContext);
+        this.bundleContext = bundleContext;
+        entityOwnershipService = eos;
+    }
+
+    public static boolean isMasterProviderInstance() {
+        if (entityOwnershipService != null) {
+            Optional<EntityOwnershipState> state = entityOwnershipService.getOwnershipState(ownerInstanceEntity);
+            return state.isPresent() && state.get().isOwner();
+        }
+        return false;
+    }
+
+    public static boolean isMasterElected(){
+        if (entityOwnershipService != null) {
+            Optional<EntityOwnershipState> state = entityOwnershipService.getOwnershipState(ownerInstanceEntity);
+            return state.isPresent() && state.get().hasOwner();
+        }
+        return false;
+    }
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("NetvirtProvider closed");
+        activator.stop(bundleContext);
+    }
+
+    @Override
+    public void onSessionInitiated(ProviderContext providerContext) {
+        dataBroker = providerContext.getSALService(DataBroker.class);
+        LOG.info("NetvirtProvider: onSessionInitiated dataBroker: {}", dataBroker);
+        LOG.info("NetvirtProvider: onSessionInitiated isConntrackEnabled: {}", this.conntrackEnabled);
+        this.activator = new ConfigActivator(providerContext);
+        activator.setConntrackEnabled(this.conntrackEnabled);
+        try {
+            activator.start(bundleContext);
+        } catch (Exception e) {
+            LOG.warn("Failed to start Netvirt: ", e);
+        }
+    }
+
+    public boolean isConntrackEnabled() {
+        return conntrackEnabled;
+    }
+
+    public void setConntrackEnabled(boolean conntackEnabled) {
+        this.conntrackEnabled = conntackEnabled;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NetworkHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NetworkHandler.java
new file mode 100644 (file)
index 0000000..9daa5fe
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for Neutron Network.
+ */
+public class NetworkHandler extends AbstractHandler implements INeutronNetworkAware, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(NetworkHandler.class);
+    public static final String NETWORK_TYPE_VXLAN = "vxlan";
+    public static final String NETWORK_TYPE_GRE = "gre";
+    public static final String NETWORK_TYPE_VLAN = "vlan";
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile BridgeConfigurationManager bridgeConfigurationManager;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+    private volatile Southbound southbound;
+
+    /**
+     * Invoked when a network creation is requested
+     * to indicate if the specified network can be created.
+     *
+     * @param network  An instance of proposed new Neutron Network object.
+     * @return A HTTP status code to the creation request.
+     */
+    @Override
+    public int canCreateNetwork(NeutronNetwork network) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Invoked to take action after a network has been created.
+     *
+     * @param network  An instance of new Neutron Network object.
+     */
+    @Override
+    public void neutronNetworkCreated(NeutronNetwork network) {
+        enqueueEvent(new NorthboundEvent(network, Action.ADD));
+    }
+    private void doNeutronNetworkCreated(NeutronNetwork network) {
+        neutronL3Adapter.handleNeutronNetworkEvent(network, Action.ADD);
+    }
+
+    /**
+     * Invoked when a network update is requested
+     * to indicate if the specified network can be changed
+     * using the specified delta.
+     *
+     * @param delta     Updates to the network object using patch semantics.
+     * @param original  An instance of the Neutron Network object
+     *                  to be updated.
+     * @return A HTTP status code to the update request.
+     */
+    @Override
+    public int canUpdateNetwork(NeutronNetwork delta,
+                                NeutronNetwork original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Invoked to take action after a network has been updated.
+     *
+     * @param network An instance of modified Neutron Network object.
+     */
+    @Override
+    public void neutronNetworkUpdated(NeutronNetwork network) {
+        enqueueEvent(new NorthboundEvent(network, Action.UPDATE));
+    }
+    private void doNeutronNetworkUpdated(NeutronNetwork network) {
+        neutronL3Adapter.handleNeutronNetworkEvent(network, Action.UPDATE);
+    }
+
+    /**
+     * Invoked when a network deletion is requested
+     * to indicate if the specified network can be deleted.
+     *
+     * @param network  An instance of the Neutron Network object to be deleted.
+     * @return A HTTP status code to the deletion request.
+     */
+    @Override
+    public int canDeleteNetwork(NeutronNetwork network) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Invoked to take action after a network has been deleted.
+     *
+     * @param network  An instance of deleted Neutron Network object.
+     */
+    @Override
+    public void neutronNetworkDeleted(NeutronNetwork network) {
+        enqueueEvent(new NorthboundEvent(network, Action.DELETE));
+    }
+    private void doNeutronNetworkDeleted(NeutronNetwork network) {
+        neutronL3Adapter.handleNeutronNetworkEvent(network, Action.DELETE);
+
+        /* Is this the last Neutron tenant network */
+        List <NeutronNetwork> networks;
+        if (neutronNetworkCache != null) {
+            networks = neutronNetworkCache.getAllNetworks();
+            if (networks.isEmpty()) {
+                LOG.trace("neutronNetworkDeleted: last tenant network, delete tunnel ports...");
+                List<Node> nodes = nodeCacheManager.getNodes();
+
+                for (Node node : nodes) {
+                    List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
+                    try {
+                        List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(node);
+                        for (OvsdbTerminationPointAugmentation port : ports) {
+                            if (southbound.isTunnel(port)) {
+                                LOG.trace("Delete tunnel interface {}", port.getName());
+                                southbound.deleteTerminationPoint(node, port.getName());
+                            } else if (!phyIfName.isEmpty() && phyIfName.contains(port.getName())) {
+                                LOG.trace("Delete physical interface {}", port.getName());
+                                southbound.deleteTerminationPoint(node, port.getName());
+                            }
+                        }
+                    } catch (Exception e) {
+                        LOG.error("Exception during handlingNeutron network delete", e);
+                    }
+                }
+            }
+        }
+        tenantNetworkManager.networkDeleted(network.getID());
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                doNeutronNetworkCreated(ev.getNeutronNetwork());
+                break;
+            case UPDATE:
+                doNeutronNetworkUpdated(ev.getNeutronNetwork());
+                break;
+            case DELETE:
+                doNeutronNetworkDeleted(ev.getNeutronNetwork());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
+        bridgeConfigurationManager =
+                (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NeutronCacheUtils.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NeutronCacheUtils.java
new file mode 100755 (executable)
index 0000000..d568182
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014, 2015 SDN Hub, LLC. 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Map;
+
+public class NeutronCacheUtils {
+
+    /**
+     * Look up in the NeutronPortsCRUD cache and return the MAC address for a corresponding IP address
+     * @param neutronPortsCache Reference to port cache to get existing port related data. This interface
+     * basically read data from the md-sal data store.
+     * @param subnetID subnet to which given port is attached
+     * @param ipAddr IP address of a member or VM
+     * @return MAC address registered with that IP address
+     */
+    public static String getMacAddress(INeutronPortCRUD neutronPortsCache, String subnetID, String ipAddr) {
+        if (ipAddr == null || subnetID == null) {
+            return null;
+        }
+
+        List<NeutronPort> allPorts = neutronPortsCache.getAllPorts();
+        for (NeutronPort port : allPorts) {
+            List<Neutron_IPs> fixedIPs = port.getFixedIPs();
+            if (fixedIPs != null && !fixedIPs.isEmpty()) {
+                for (Neutron_IPs ip : fixedIPs) {
+                    if (ip.getIpAddress().equals(ipAddr) && ip.getSubnetUUID().equals(subnetID)) {
+                        return port.getMacAddress();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Look up in the NeutronNetworkCRUD cache and NeutronSubnetCRUD cache for
+     * extracting the provider segmentation_type and segmentation_id
+     * @param neutronNetworkCache Reference to neutron network cache to get existing network related data.
+     * This interface basically read data from the md-sal data store.
+     * @param neutronSubnetCache Reference to neutron subnet cache to get existing subnet related data.
+     * This interface basically read data from the md-sal data store.
+     * @param subnetID Subnet UUID
+     * @return {Type: ID} pair for that subnet ID
+     */
+    public static Map.Entry<String,String> getProviderInformation(INeutronNetworkCRUD neutronNetworkCache,
+                INeutronSubnetCRUD neutronSubnetCache, String subnetID) {
+
+        String networkID = null;
+
+        List<NeutronSubnet> allSubnets = neutronSubnetCache.getAllSubnets();
+        for (NeutronSubnet subnet: allSubnets) {
+            if (subnet.getID().equals(subnetID)) {
+                networkID = subnet.getNetworkUUID();
+                break;
+            }
+        }
+        if (networkID == null) {
+            return null;
+        }
+
+        List<NeutronNetwork> allNetworks = neutronNetworkCache.getAllNetworks();
+        for (NeutronNetwork network: allNetworks) {
+            if (network.getID().equals(networkID)) {
+                return new AbstractMap.SimpleEntry<>(
+                        network.getProviderNetworkType(), network.getProviderSegmentationID());
+            }
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NeutronL3AdapterEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NeutronL3AdapterEvent.java
new file mode 100644 (file)
index 0000000..f8b8c28
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+public class NeutronL3AdapterEvent extends AbstractEvent {
+    public enum SubType {
+        SUBTYPE_EXTERNAL_MAC_UPDATE;  // TODO: Add more subtypes as they come here
+
+        public static final int size = HandlerType.values().length;
+    }
+
+    private final SubType subtype;
+
+    private final Long bridgeDpid;
+    private final IpAddress gatewayIpAddress;
+    private final MacAddress macAddress;
+
+    public NeutronL3AdapterEvent(final Long bridgeDpid, final IpAddress gatewayIpAddress, final MacAddress macAddress) {
+        super(HandlerType.NEUTRON_L3_ADAPTER, Action.UPDATE);
+
+        this.subtype = SubType.SUBTYPE_EXTERNAL_MAC_UPDATE;
+        this.bridgeDpid = bridgeDpid;
+        this.gatewayIpAddress = gatewayIpAddress;
+        this.macAddress = macAddress;
+    }
+
+    public SubType getSubType() {
+        return subtype;
+    }
+
+    public Long getBridgeDpid() {
+        return bridgeDpid;
+    }
+    public IpAddress getGatewayIpAddress() {
+        return gatewayIpAddress;
+    }
+    public MacAddress getMacAddress() {
+        return macAddress;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronL3AdapterEvent [handler=" + super.getHandlerType()
+                + ", action=" + super.getAction()
+                + ", subtype=" + subtype
+                + ", bridgeDpid=" + bridgeDpid
+                + ", gatewayIpAddress=" + gatewayIpAddress
+                + ", macAddress=" + macAddress
+                + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((subtype == null) ? 0 : subtype.hashCode());
+        result = prime * result + ((bridgeDpid == null) ? 0 : bridgeDpid.hashCode());
+        result = prime * result + ((gatewayIpAddress == null) ? 0 : gatewayIpAddress.hashCode());
+        result = prime * result + ((macAddress == null) ? 0 : macAddress.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        NeutronL3AdapterEvent other = (NeutronL3AdapterEvent) obj;
+        if (subtype == null) {
+            if (other.subtype != null) {
+                return false;
+            }
+        } else if (!subtype.equals(other.subtype)) {
+            return false;
+        }
+        if (bridgeDpid == null) {
+            if (other.bridgeDpid != null) {
+                return false;
+            }
+        } else if (!bridgeDpid.equals(other.bridgeDpid)) {
+            return false;
+        }
+        if (gatewayIpAddress == null) {
+            if (other.gatewayIpAddress != null) {
+                return false;
+            }
+        } else if (!gatewayIpAddress.equals(other.gatewayIpAddress)) {
+            return false;
+        }
+        if (macAddress == null) {
+            if (other.macAddress != null) {
+                return false;
+            }
+        } else if (!macAddress.equals(other.macAddress)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NodeCacheManagerEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NodeCacheManagerEvent.java
new file mode 100644 (file)
index 0000000..1984995
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * @author Flavio Fernandes (ffernand@redhat.com)
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class NodeCacheManagerEvent extends AbstractEvent {
+    private Node node;
+
+    public NodeCacheManagerEvent(Node node, Action action) {
+        super(HandlerType.NODE, action);
+        this.node = node;
+    }
+
+    public Node getNode() {
+        return node;
+    }
+
+    public String getNodeIdentifier() {
+        return node.getNodeId().getValue();
+    }
+
+    @Override
+    public String toString() {
+        return "NodeCacheManagerEvent [action=" + super.getAction()
+               + ", node=" + node
+               + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((node == null) ? 0 : node.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        NodeCacheManagerEvent other = (NodeCacheManagerEvent) obj;
+        if (node == null) {
+            if (other.node != null) {
+                return false;
+            }
+        } else if (!node.equals(other.node)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NodeConfiguration.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NodeConfiguration.java
new file mode 100644 (file)
index 0000000..3901750
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentMap;
+
+public class NodeConfiguration {
+    private java.util.Queue<Integer> internalVlans = Lists.newLinkedList();
+    private ConcurrentMap<String, Integer> tenantVlanMap = Maps.newConcurrentMap();
+
+    public NodeConfiguration() {
+        for (int i = 1; i < Constants.MAX_VLAN; i++) {
+            internalVlans.add(i);
+
+        }
+    }
+
+    public Queue<Integer> getInternalVlans() {
+        return internalVlans;
+    }
+
+    public ConcurrentMap<String, Integer> getTenantVlanMap() {
+        return tenantVlanMap;
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NorthboundEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/NorthboundEvent.java
new file mode 100644 (file)
index 0000000..daa5905
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+
+public class NorthboundEvent extends AbstractEvent {
+
+    private NeutronPort port;
+    private NeutronSubnet subnet;
+    private NeutronRouter router;
+    private NeutronRouter_Interface routerInterface;
+    private NeutronFloatingIP neutronFloatingIP;
+    private NeutronNetwork neutronNetwork;
+    private NeutronLoadBalancer loadBalancer;
+    private NeutronLoadBalancerPool loadBalancerPool;
+    private NeutronLoadBalancerPoolMember loadBalancerPoolMember;
+    private NeutronSecurityRule neutronSecurityRule;
+
+    NorthboundEvent(NeutronPort port, Action action) {
+        super(HandlerType.NEUTRON_PORT, action);
+        this.port = port;
+    }
+
+    NorthboundEvent(NeutronSubnet subnet, Action action) {
+        super(HandlerType.NEUTRON_SUBNET, action);
+        this.subnet = subnet;
+    }
+
+    NorthboundEvent(NeutronRouter router, Action action) {
+        super(HandlerType.NEUTRON_ROUTER, action);
+        this.router = router;
+    }
+
+    NorthboundEvent(NeutronRouter router, NeutronRouter_Interface routerInterface, Action action) {
+        super(HandlerType.NEUTRON_ROUTER, action);
+        this.router = router;
+        this.routerInterface = routerInterface;
+    }
+
+    NorthboundEvent(NeutronFloatingIP neutronFloatingIP, Action action) {
+        super(HandlerType.NEUTRON_FLOATING_IP, action);
+        this.neutronFloatingIP = neutronFloatingIP;
+    }
+
+    NorthboundEvent(NeutronNetwork neutronNetwork, Action action) {
+        super(HandlerType.NEUTRON_NETWORK, action);
+        this.neutronNetwork = neutronNetwork;
+    }
+
+    NorthboundEvent(NeutronLoadBalancer loadBalancer, Action action) {
+        super(HandlerType.NEUTRON_LOAD_BALANCER, action);
+        this.loadBalancer = loadBalancer;
+    }
+
+    NorthboundEvent(NeutronLoadBalancerPool loadBalancerPool, Action action) {
+        super(HandlerType.NEUTRON_LOAD_BALANCER_POOL, action);
+        this.loadBalancerPool = loadBalancerPool;
+    }
+
+    NorthboundEvent(NeutronLoadBalancerPoolMember loadBalancerPoolMember, Action action) {
+        super(HandlerType.NEUTRON_LOAD_BALANCER_POOL_MEMBER, action);
+        this.loadBalancerPoolMember = loadBalancerPoolMember;
+    }
+
+    NorthboundEvent(NeutronSecurityRule neutronSecurityRule, Action action) {
+        super(HandlerType.NEUTRON_PORT_SECURITY, action);
+        this.neutronSecurityRule = neutronSecurityRule;
+    }
+
+    public NeutronPort getPort() {
+        return port;
+    }
+    public NeutronSubnet getSubnet() {
+        return subnet;
+    }
+    public NeutronRouter getRouter() {
+        return router;
+    }
+    public NeutronRouter_Interface getRouterInterface() {
+        return routerInterface;
+    }
+    public NeutronFloatingIP getNeutronFloatingIP() {
+        return neutronFloatingIP;
+    }
+    public NeutronNetwork getNeutronNetwork() {
+        return neutronNetwork;
+    }
+    public NeutronLoadBalancer getLoadBalancer() {
+        return loadBalancer;
+    }
+    public NeutronLoadBalancerPool getLoadBalancerPool() {
+        return loadBalancerPool;
+    }
+    public NeutronLoadBalancerPoolMember getLoadBalancerPoolMember() {
+        return loadBalancerPoolMember;
+    }
+    public NeutronSecurityRule getNeutronSecurityRule() {
+        return neutronSecurityRule;
+    }
+
+    @Override
+    public String toString() {
+        return "NorthboundEvent [handler=" + super.getHandlerType()
+               + ", action=" + super.getAction()
+               + ", port=" + port
+               + ", subnet=" + subnet
+               + ", router=" + router
+               + ", routerInterface=" + routerInterface
+               + ", floatingIP=" + neutronFloatingIP
+               + ", network=" + neutronNetwork
+               + ", loadBalancer=" + loadBalancer
+               + ", loadBalancerPool=" + loadBalancerPool
+               + ", loadBalancerPoolMember=" + loadBalancerPoolMember
+               + ", neutronsecurityRule=" + neutronSecurityRule
+               + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((port == null) ? 0 : port.hashCode());
+        result = prime * result + ((subnet == null) ? 0 : subnet.hashCode());
+        result = prime * result + ((router == null) ? 0 : router.hashCode());
+        result = prime * result + ((routerInterface == null) ? 0 : routerInterface.hashCode());
+        result = prime * result + ((neutronFloatingIP == null) ? 0 : neutronFloatingIP.hashCode());
+        result = prime * result + ((neutronNetwork == null) ? 0 : neutronNetwork.hashCode());
+        result = prime * result + ((neutronSecurityRule == null) ? 0 : neutronSecurityRule.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        NorthboundEvent other = (NorthboundEvent) obj;
+        if (port == null) {
+            if (other.port != null) {
+                return false;
+            }
+        } else if (!port.equals(other.port)) {
+            return false;
+        }
+        if (subnet == null) {
+            if (other.subnet != null) {
+                return false;
+            }
+        } else if (!subnet.equals(other.subnet)) {
+            return false;
+        }
+        if (router == null) {
+            if (other.router != null) {
+                return false;
+            }
+        } else if (!router.equals(other.router)) {
+            return false;
+        }
+        if (routerInterface == null) {
+            if (other.routerInterface != null) {
+                return false;
+            }
+        } else if (!routerInterface.equals(other.routerInterface)) {
+            return false;
+        }
+        if (neutronFloatingIP == null) {
+            if (other.neutronFloatingIP != null) {
+                return false;
+            }
+        } else if (!neutronFloatingIP.equals(other.neutronFloatingIP)) {
+            return false;
+        }
+        if (neutronNetwork == null) {
+            if (other.neutronNetwork != null) {
+                return false;
+            }
+        } else if (!neutronNetwork.equals(other.neutronNetwork)) {
+            return false;
+        }
+        if (loadBalancer == null) {
+            if (other.loadBalancer != null) {
+                return false;
+            }
+        } else if (!loadBalancer.equals(other.loadBalancer)) {
+            return false;
+        }
+        if (loadBalancerPool == null) {
+            if (other.loadBalancerPool != null) {
+                return false;
+            }
+        } else if (!loadBalancerPool.equals(other.loadBalancerPool)) {
+            return false;
+        }
+        if (loadBalancerPoolMember == null) {
+            if (other.loadBalancerPoolMember != null) {
+                return false;
+            }
+        } else if (!loadBalancerPoolMember.equals(other.loadBalancerPoolMember)) {
+            return false;
+        }
+        if (neutronSecurityRule == null) {
+            if (other.neutronSecurityRule != null) {
+                return false;
+            }
+        } else if (!neutronSecurityRule.equals(other.neutronSecurityRule)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortHandler.java
new file mode 100644 (file)
index 0000000..952a4b9
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013, 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronPortAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for Neutron Port.
+ */
+public class PortHandler extends AbstractHandler implements INeutronPortAware, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(PortHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+    private volatile DistributedArpService distributedArpService;
+    private volatile Southbound southbound;
+
+    /**
+     * Invoked when a port creation is requested
+     * to indicate if the specified port can be created.
+     *
+     * @param port     An instance of proposed new Port object.
+     * @return A HTTP status code to the creation request.
+     */
+    @Override
+    public int canCreatePort(NeutronPort port) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Invoked to take action after a port has been created.
+     *
+     * @param neutronPort An instance of new Neutron Port object.
+     */
+    @Override
+    public void neutronPortCreated(NeutronPort neutronPort) {
+        enqueueEvent(new NorthboundEvent(neutronPort, Action.ADD));
+    }
+    private void doNeutronPortCreated(NeutronPort neutronPort) {
+        LOG.debug(" Port-ADD successful for tenant-id - {}, network-id - {}, port-id - {}",
+                     neutronPort.getTenantID(), neutronPort.getNetworkUUID(),
+                     neutronPort.getID());
+        distributedArpService.handlePortEvent(neutronPort, Action.ADD);
+        neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.ADD);
+    }
+
+    /**
+     * Invoked when a port update is requested
+     * to indicate if the specified port can be changed
+     * using the specified delta.
+     *
+     * @param delta    Updates to the port object using patch semantics.
+     * @param original An instance of the Neutron Port object
+     *                  to be updated.
+     * @return A HTTP status code to the update request.
+     */
+    @Override
+    public int canUpdatePort(NeutronPort delta,
+                             NeutronPort original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Invoked to take action after a port has been updated.
+     *
+     * @param neutronPort An instance of modified Neutron Port object.
+     */
+    @Override
+    public void neutronPortUpdated(NeutronPort neutronPort) {
+        enqueueEvent(new NorthboundEvent(neutronPort, Action.UPDATE));
+    }
+    private void doNeutronPortUpdated(NeutronPort neutronPort) {
+        LOG.debug("Handling neutron update port {}", neutronPort);
+        distributedArpService.handlePortEvent(neutronPort, Action.UPDATE);
+        neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.UPDATE);
+    }
+
+    /**
+     * Invoked when a port deletion is requested
+     * to indicate if the specified port can be deleted.
+     *
+     * @param port     An instance of the Neutron Port object to be deleted.
+     * @return A HTTP status code to the deletion request.
+     */
+    @Override
+    public int canDeletePort(NeutronPort port) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Invoked to take action after a port has been deleted.
+     *
+     * @param neutronPort  An instance of deleted Neutron Port object.
+     */
+    @Override
+    public void neutronPortDeleted(NeutronPort neutronPort) {
+        enqueueEvent(new NorthboundEvent(neutronPort, Action.DELETE));
+    }
+    private void doNeutronPortDeleted(NeutronPort neutronPort) {
+        LOG.debug("Handling neutron delete port {}", neutronPort);
+        distributedArpService.handlePortEvent(neutronPort, Action.DELETE);
+        neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.DELETE);
+        //TODO: Need to implement getNodes
+        List<Node> nodes = nodeCacheManager.getNodes();
+        for (Node node : nodes) {
+            try {
+                List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(node);
+                for (OvsdbTerminationPointAugmentation port : ports) {
+                    String neutronPortId =
+                            southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_INTERFACE_ID);
+                    if (neutronPortId != null && neutronPortId.equalsIgnoreCase(neutronPort.getPortUUID())) {
+                        LOG.trace("neutronPortDeleted: Delete interface {}", port.getName());
+                        southbound.deleteTerminationPoint(node, port.getName());
+                        break;
+                    }
+                }
+            } catch (Exception e) {
+                LOG.error("Exception during handlingNeutron port delete", e);
+            }
+        }
+        LOG.debug(" PORT delete successful for tenant-id - {}, network-id - {}, port-id - {}",
+                     neutronPort.getTenantID(), neutronPort.getNetworkUUID(),
+                     neutronPort.getID());
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                doNeutronPortCreated(ev.getPort());
+                break;
+            case DELETE:
+                doNeutronPortDeleted(ev.getPort());
+                break;
+            case UPDATE:
+                doNeutronPortUpdated(ev.getPort());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        distributedArpService =
+                (DistributedArpService) ServiceHelper.getGlobalInstance(DistributedArpService.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandler.java
new file mode 100644 (file)
index 0000000..78e1c42
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for OpenStack Neutron v2.0 Port Security API calls.
+ */
+public class PortSecurityHandler extends AbstractHandler
+        implements INeutronSecurityGroupAware, INeutronSecurityRuleAware, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PortSecurityHandler.class);
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile SecurityServicesManager securityServicesManager;
+
+    @Override
+    public int canCreateNeutronSecurityGroup(NeutronSecurityGroup neutronSecurityGroup) {
+        return HttpURLConnection.HTTP_CREATED;
+    }
+
+    @Override
+    public void neutronSecurityGroupCreated(NeutronSecurityGroup neutronSecurityGroup) {
+        int result = canCreateNeutronSecurityGroup(neutronSecurityGroup);
+        if (result != HttpURLConnection.HTTP_CREATED) {
+            LOG.debug("Neutron Security Group creation failed {} ", result);
+        }
+    }
+
+    @Override
+    public int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSecurityGroupUpdated(NeutronSecurityGroup neutronSecurityGroup) {
+        // Nothing to do
+    }
+
+    @Override
+    public int canDeleteNeutronSecurityGroup(NeutronSecurityGroup neutronSecurityGroup) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSecurityGroupDeleted(NeutronSecurityGroup neutronSecurityGroup) {
+        //TODO: Trigger flowmod removals
+        int result = canDeleteNeutronSecurityGroup(neutronSecurityGroup);
+        if  (result != HttpURLConnection.HTTP_OK) {
+            LOG.error(" delete Neutron Security Rule validation failed for result - {} ", result);
+        }
+    }
+
+    /**
+     * Invoked when a Security Rules creation is requested
+     * to indicate if the specified Rule can be created.
+     *
+     * @param neutronSecurityRule  An instance of proposed new Neutron Security Rule object.
+     * @return A HTTP status code to the creation request.
+     */
+
+    @Override
+    public int canCreateNeutronSecurityRule(NeutronSecurityRule neutronSecurityRule) {
+        return HttpURLConnection.HTTP_CREATED;
+    }
+
+    @Override
+    public void neutronSecurityRuleCreated(NeutronSecurityRule neutronSecurityRule) {
+        enqueueEvent(new NorthboundEvent(neutronSecurityRule, Action.ADD));
+    }
+
+    @Override
+    public int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSecurityRuleUpdated(NeutronSecurityRule neutronSecurityRule) {
+        // Nothing to do
+    }
+
+    @Override
+    public int canDeleteNeutronSecurityRule(NeutronSecurityRule neutronSecurityRule) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSecurityRuleDeleted(NeutronSecurityRule neutronSecurityRule) {
+        enqueueEvent(new NorthboundEvent(neutronSecurityRule, Action.DELETE));
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                processNeutronSecurityRuleAdded(ev.getNeutronSecurityRule());
+                break;
+            case DELETE:
+                processNeutronSecurityRuleDeleted(ev.getNeutronSecurityRule());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    private void processNeutronSecurityRuleAdded(NeutronSecurityRule neutronSecurityRule) {
+        List<NeutronPort> portList = getPortWithSecurityGroup(neutronSecurityRule.getSecurityRuleGroupID());
+        for (NeutronPort port:portList) {
+            syncSecurityGroup(neutronSecurityRule,port,true);
+        }
+    }
+
+    private void processNeutronSecurityRuleDeleted(NeutronSecurityRule neutronSecurityRule) {
+        List<NeutronPort> portList = getPortWithSecurityGroup(neutronSecurityRule.getSecurityRuleGroupID());
+        for (NeutronPort port:portList) {
+            syncSecurityGroup(neutronSecurityRule,port,false);
+        }
+    }
+
+    private void syncSecurityGroup(NeutronSecurityRule  securityRule,NeutronPort port,
+                                   boolean write) {
+        if (!port.getPortSecurityEnabled()) {
+            LOG.info("Port security not enabled port", port);
+            return;
+        }
+        if (null != securityRule.getSecurityRemoteGroupID()) {
+            List<Neutron_IPs> vmIpList  = securityServicesManager
+                    .getVmListForSecurityGroup(port.getID(), securityRule.getSecurityRemoteGroupID());
+            for (Neutron_IPs vmIp :vmIpList ) {
+                securityServicesManager.syncSecurityRule(port, securityRule, vmIp, write);
+            }
+        } else {
+            securityServicesManager.syncSecurityRule(port, securityRule, null, write);
+        }
+    }
+
+    private List<NeutronPort> getPortWithSecurityGroup(String securityGroupUuid) {
+
+        List<NeutronPort> neutronPortList = neutronPortCache.getAllPorts();
+        List<NeutronPort> neutronPortInSg = new ArrayList<NeutronPort>();
+        for (NeutronPort neutronPort:neutronPortList) {
+            List<NeutronSecurityGroup> securityGroupList = neutronPort.getSecurityGroups();
+            for (NeutronSecurityGroup neutronSecurityGroup:securityGroupList) {
+                if (neutronSecurityGroup.getID().equals(securityGroupUuid)) {
+                    neutronPortInSg.add(neutronPort);
+                    break;
+                }
+            }
+        }
+        return neutronPortInSg;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+        neutronPortCache =
+                (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/RouterHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/RouterHandler.java
new file mode 100644 (file)
index 0000000..cb2470e
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for Neutron Router.
+ */
+public class RouterHandler extends AbstractHandler implements INeutronRouterAware, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(RouterHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile NeutronL3Adapter neutronL3Adapter;
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be created
+     *
+     * @param router
+     *            instance of proposed new Neutron Router object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canCreateRouter(NeutronRouter router) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after a router has been created
+     *
+     * @param router
+     *            instance of new Neutron Router object
+     */
+    @Override
+    public void neutronRouterCreated(NeutronRouter router) {
+        enqueueEvent(new NorthboundEvent(router, Action.ADD));
+    }
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the router object using patch semantics
+     * @param original
+     *            instance of the Neutron Router object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after a router has been updated
+     *
+     * @param router
+     *            instance of modified Neutron Router object
+     */
+    @Override
+    public void neutronRouterUpdated(NeutronRouter router) {
+        enqueueEvent(new NorthboundEvent(router, Action.UPDATE));
+    }
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be deleted
+     *
+     * @param router
+     *            instance of the Neutron Router object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canDeleteRouter(NeutronRouter router) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after a router has been deleted
+     *
+     * @param router
+     *            instance of deleted Router Network object
+     */
+    @Override
+    public void neutronRouterDeleted(NeutronRouter router) {
+        enqueueEvent(new NorthboundEvent(router, Action.DELETE));
+    }
+
+    /**
+     * Services provide this interface method to indicate if the specified interface can be attached to the specified
+     * route
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface to be attached to the router
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the attach operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        LOG.debug(" Router {} asked if it can attach interface {}. Subnet {}",
+                     router.getName(),
+                     routerInterface.getPortUUID(),
+                     routerInterface.getSubnetUUID());
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after an interface has been added to a router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface being attached to the router
+     */
+    @Override
+    public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        enqueueEvent(new NorthboundEvent(router, routerInterface, Action.ADD));
+    }
+
+    /**
+     * Services provide this interface method to indicate if the specified interface can be detached from the specified
+     * router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface to be detached to the router
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the detach operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    @Override
+    public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        LOG.debug(" Router {} asked if it can detach interface {}. Subnet {}",
+                     router.getName(),
+                     routerInterface.getPortUUID(),
+                     routerInterface.getSubnetUUID());
+
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    /**
+     * Services provide this interface method for taking action after an interface has been removed from a router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface being detached from the router
+     */
+    @Override
+    public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        enqueueEvent(new NorthboundEvent(router, routerInterface, Action.DELETE));
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                // fall through
+            case DELETE:
+                // fall through
+            case UPDATE:
+                if (ev.getRouterInterface() == null) {
+                    neutronL3Adapter.handleNeutronRouterEvent(ev.getRouter(), ev.getAction());
+                } else {
+                    neutronL3Adapter.handleNeutronRouterInterfaceEvent(ev.getRouter(),
+                                                                      ev.getRouterInterface(),
+                                                                      ev.getAction());
+                }
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundEvent.java
new file mode 100644 (file)
index 0000000..fd85f9b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+public class SouthboundEvent extends AbstractEvent {
+    public enum Type { NODE, OPENVSWITCH, BRIDGE, CONTROLLER, PORT }
+    private Type type;
+    private Node node;
+    private String tableName;
+    private String uuid;
+    private Object context;
+    private DataObject augmentationData;
+    private OvsdbBridgeAugmentation bridge;
+    private OvsdbTerminationPointAugmentation port;
+    private String portName;
+    public SouthboundEvent(Node node, Action action) {
+        super(HandlerType.SOUTHBOUND, action);
+        this.type = Type.NODE;
+        this.node = node;
+    }
+    public SouthboundEvent(Node node, OvsdbBridgeAugmentation bridge, Action action) {
+        super(HandlerType.SOUTHBOUND, action);
+        this.type = Type.BRIDGE;
+        this.node = node;
+        this.bridge = bridge;
+    }
+    public SouthboundEvent(Node node, OvsdbTerminationPointAugmentation port, String portName, Action action) {
+        super(HandlerType.SOUTHBOUND, action);
+        this.type = Type.PORT;
+        this.node = node;
+        this.port = port;
+        this.portName = portName;
+    }
+
+    public SouthboundEvent(Node node, Type type, Action action) {
+        super(HandlerType.SOUTHBOUND, action);
+        this.type = type;
+        this.node = node;
+    }
+
+    public SouthboundEvent(Node node, DataObject resourceAugmentationData, Type type, Action action) {
+        super(HandlerType.SOUTHBOUND, action);
+        this.type = type;
+        this.node = node;
+        this.augmentationData = resourceAugmentationData;
+    }
+
+
+    public Type getType() {
+        return type;
+    }
+    public Node getNode() {
+        return node;
+    }
+    public String getTableName() {
+        return tableName;
+    }
+    public String getUuid() {
+        return uuid;
+    }
+    public Object getContext() {
+        return context;
+    }
+    public OvsdbBridgeAugmentation getBridge() {
+        return bridge;
+    }
+    public OvsdbTerminationPointAugmentation getPort() {
+        return port;
+    }
+    public String getPortName() {
+        return portName;
+    }
+
+    public DataObject getAugmentationData() {
+        return augmentationData;
+    }
+
+    @Override
+    public String toString() {
+        //if (type == Type.NODE) {
+            return "SouthboundEvent [type=" + type
+                    + ", action=" + super.getAction()
+                    + ", augmentationData=" + augmentationData
+                    + ", node=" + node + "]";
+        //} else {
+        //    return "SouthboundEvent [type=" + type + "]";
+        //}
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((node == null) ? 0 : node.hashCode());
+        result = prime * result + ((tableName == null) ? 0 : tableName.hashCode());
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
+        result = prime * result + ((augmentationData == null) ? 0 : augmentationData.hashCode());
+        return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        SouthboundEvent other = (SouthboundEvent) obj;
+        if (node == null) {
+            if (other.node != null) {
+                return false;
+            }
+        } else if (!node.equals(other.node)) {
+            return false;
+        }
+        if (tableName == null) {
+            if (other.tableName != null) {
+                return false;
+            }
+        } else if (!tableName.equals(other.tableName)) {
+            return false;
+        }
+        if (type == null) {
+            if (other.type != null) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        if (uuid == null) {
+            if (other.uuid != null) {
+                return false;
+            }
+        } else if (!uuid.equals(other.uuid)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandler.java
new file mode 100644 (file)
index 0000000..f37cdc0
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2013, 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.openstack.netvirt;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Madhu Venugopal
+ * @author Brent Salisbury
+ * @author Dave Tucker
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class SouthboundHandler extends AbstractHandler
+        implements ConfigInterface, NodeCacheListener, OvsdbInventoryListener {
+    private static final Logger LOG = LoggerFactory.getLogger(SouthboundHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile ConfigurationService configurationService;
+    private volatile BridgeConfigurationManager bridgeConfigurationManager;
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile NetworkingProviderManager networkingProviderManager;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+    private volatile DistributedArpService distributedArpService;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile OvsdbInventoryService ovsdbInventoryService;
+    private volatile Southbound southbound;
+
+    private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
+        SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
+
+        switch (ovsdbType) {
+            case NODE:
+                type = SouthboundEvent.Type.NODE;
+                break;
+            case BRIDGE:
+                type = SouthboundEvent.Type.BRIDGE;
+                break;
+            case PORT:
+                type = SouthboundEvent.Type.PORT;
+                break;
+            case CONTROLLER:
+                type = SouthboundEvent.Type.CONTROLLER;
+                break;
+            case OPENVSWITCH:
+                type = SouthboundEvent.Type.OPENVSWITCH;
+                break;
+            default:
+                LOG.warn("Invalid OvsdbType: {}", ovsdbType);
+                break;
+        }
+        return type;
+    }
+
+    @Override
+    public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
+        LOG.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
+        enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
+                ovsdbTypeToSouthboundEventType(ovsdbType), action));
+    }
+
+    private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
+        LOG.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
+        NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
+        if (network != null && !network.getRouterExternal()) {
+            LOG.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
+            if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
+                networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
+            }
+        } else {
+            LOG.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
+        }
+        distributedArpService.processInterfaceEvent(node, tp, network, Action.UPDATE);
+        neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
+    }
+
+    private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
+                                        boolean isLastInstanceOnNode, NeutronNetwork network) {
+        LOG.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
+                node, isLastInstanceOnNode, intf);
+
+        distributedArpService.processInterfaceEvent(node, intf, network, Action.DELETE);
+        neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
+        List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
+        if (isInterfaceOfInterest(intf, phyIfName)) {
+            // delete tunnel or physical interfaces
+            networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
+                    network, node, intf, isLastInstanceOnNode);
+        } else if (network != null) {
+            // vlan doesn't need a tunnel endpoint
+            if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
+                    configurationService.getTunnelEndPoint(node) == null) {
+                LOG.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
+                return;
+            }
+            networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
+                    network, node, intf, isLastInstanceOnNode);
+        }
+    }
+
+    @Override
+    public void triggerUpdates() {
+        LOG.info("triggerUpdates");
+        List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
+        for (Node node : ovsdbNodes) {
+            ovsdbUpdate(node, node.getAugmentation(OvsdbNodeAugmentation.class),
+                    OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
+        }
+    }
+
+    private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
+                                   Object context) {
+        LOG.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
+        NeutronNetwork network;
+        if (context == null) {
+            network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
+        } else {
+            network = (NeutronNetwork)context;
+        }
+        List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
+        if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
+            if (network != null) {
+                this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
+            } else {
+                LOG.warn("processPortDelete: network was null, ignoring update");
+            }
+        } else if (network != null && !network.getRouterExternal()) {
+            LOG.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
+                    ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
+            try {
+                OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(node);
+                if (ovsdbBridgeAugmentation != null) {
+                    List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+                    if (!terminationPoints.isEmpty()){
+                        boolean isLastInstanceOnNode = true;
+                        for (TerminationPoint terminationPoint : terminationPoints) {
+                            OvsdbTerminationPointAugmentation tpAugmentation =
+                                    terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
+                            if (tpAugmentation.getInterfaceUuid().equals(
+                                    ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
+                                continue;
+                            }
+                            NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
+                            if (neutronNetwork != null && neutronNetwork.equals(network)) {
+                                isLastInstanceOnNode = false;
+                                break;
+                            }
+                        }
+                        this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
+                                isLastInstanceOnNode, network);
+                    }
+                }
+            } catch (Exception e) {
+                LOG.error("Error fetching Interface Rows for node {}", node, e);
+            }
+        }
+        //remove neutronPort from the CleanupCache, if it has the entry.
+        NeutronPort neutronPort = null;
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId != null) {
+            LOG.trace("Clean up the NeutronPortCache for {} ", neutronPortId);
+            neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+        }
+        if (neutronPort != null) {
+            LOG.debug("Clean up the NeutronPortCache ");
+            neutronL3Adapter.removePortFromCleanupCache(neutronPort);
+            neutronL3Adapter.removeNetworkFromCleanupCache(neutronPort.getNetworkUUID());
+        } else {
+            LOG.trace("Nothing to Clean up in the NeutronPortCache ");
+        }
+
+    }
+
+    private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
+        LOG.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
+
+        if(terminationPoint.getInterfaceType() == null){
+            // This is OK since eth ports don't have an interface type
+            LOG.info("No type found for the interface : {}", terminationPoint);
+            return false;
+        }
+        return MdsalHelper.createOvsdbInterfaceType(
+                terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
+               ||
+               MdsalHelper.createOvsdbInterfaceType(
+                       terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
+               ||
+               phyIfName.contains(terminationPoint.getName());
+    }
+
+    /**
+     * Notification about an OpenFlow Node
+     *
+     * @param node the {@link Node Node} of interest in the notification
+     * @param action the {@link Action}
+     * @see NodeCacheListener#notifyNode
+     */
+    @Override
+    public void notifyNode (Node node, Action action) {
+        LOG.info("notifyNode: action: {}, Node <{}>", action, node);
+
+        if ((action.equals(Action.ADD)) && (southbound.getBridge(node) != null)) {
+            networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
+        }
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof SouthboundEvent)) {
+            LOG.error("processEvent: Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        SouthboundEvent ev = (SouthboundEvent) abstractEvent;
+        LOG.trace("processEvent ({}): {}", ev, ev.getTransactionId());
+        switch (ev.getType()) {
+            case NODE:
+                processOvsdbNodeEvent(ev);
+                break;
+
+            case BRIDGE:
+                processBridgeEvent(ev);
+                break;
+
+            case PORT:
+                processPortEvent(ev);
+                break;
+
+            case OPENVSWITCH:
+                processOpenVSwitchEvent(ev);
+                break;
+
+            default:
+                LOG.warn("Unable to process type {} action {} for node {}", ev.getType(), ev.getAction(), ev.getNode());
+                break;
+        }
+        LOG.trace("processEvent exit ({}): {}", ev, ev.getTransactionId());
+    }
+
+    private void processOvsdbNodeEvent(SouthboundEvent ev) {
+        switch (ev.getAction()) {
+            case ADD:
+                processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
+                break;
+            case UPDATE:
+                processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
+                break;
+            case DELETE:
+                processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
+                break;
+        }
+    }
+
+    private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
+        LOG.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
+        nodeCacheManager.nodeAdded(node);
+        bridgeConfigurationManager.prepareNode(node);
+    }
+
+    private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
+        LOG.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
+        nodeCacheManager.nodeAdded(node);
+    }
+
+    private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
+        LOG.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
+        nodeCacheManager.nodeRemoved(node);
+        /* TODO SB_MIGRATION
+        * I don't think we want to do this yet
+        InstanceIdentifier<Node> bridgeNodeIid =
+                MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
+                        Constants.INTEGRATION_BRIDGE);
+        southbound.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
+        */
+    }
+
+    private void processPortEvent(SouthboundEvent ev) {
+        switch (ev.getAction()) {
+            case ADD:
+            case UPDATE:
+                processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
+                break;
+            case DELETE:
+                processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
+                break;
+        }
+    }
+
+    private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
+        LOG.debug("processPortUpdate <{}> <{}>", node, port);
+        NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
+        if (network != null && !network.getRouterExternal()) {
+            this.handleInterfaceUpdate(node, port);
+        }
+    }
+
+    private void processOpenVSwitchEvent(SouthboundEvent ev) {
+        switch (ev.getAction()) {
+            case ADD:
+            case UPDATE:
+                processOpenVSwitchUpdate(ev.getNode());
+                break;
+            case DELETE:
+                break;
+        }
+    }
+
+    private void processOpenVSwitchUpdate(Node node) {
+        LOG.debug("processOpenVSwitchUpdate {}", node);
+        // TODO this node might be the OvsdbNode and not have termination points
+        // Would need to change listener or grab tp nodes in here.
+        List<TerminationPoint> terminationPoints = southbound.extractTerminationPoints(node);
+        for (TerminationPoint terminationPoint : terminationPoints) {
+            processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
+        }
+    }
+
+    private void processBridgeEvent(SouthboundEvent ev) {
+        switch (ev.getAction()) {
+            case ADD:
+                processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
+                break;
+            case UPDATE:
+                processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
+                break;
+            case DELETE:
+                processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
+                break;
+        }
+    }
+
+    private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
+        LOG.debug("processBridgeCreate <{}> <{}>", node, bridge);
+        String datapathId = southbound.getDatapathId(bridge);
+        // Having a datapathId means the ovsdb node has connected to ODL
+        if (datapathId != null) {
+            nodeCacheManager.nodeAdded(node);
+        } else {
+            LOG.info("processBridgeCreate datapathId not found");
+        }
+    }
+
+    private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
+        LOG.debug("processBridgeUpdate <{}> <{}>", node, bridge);
+        String datapathId = southbound.getDatapathId(bridge);
+        // Having a datapathId means the ovsdb node has connected to ODL
+        if (datapathId != null) {
+            nodeCacheManager.nodeAdded(node);
+        } else {
+            LOG.info("processBridgeUpdate datapathId not found");
+        }
+    }
+
+    private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
+        LOG.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
+                node, bridge);
+        nodeCacheManager.nodeRemoved(node);
+        // TODO SB_MIGRATION
+        // Not sure if we want to do this yet
+        southbound.deleteBridge(node);
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        networkingProviderManager =
+                (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
+        bridgeConfigurationManager =
+                (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        nodeCacheManager.cacheListenerAdded(serviceReference, this);
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        distributedArpService =
+                (DistributedArpService) ServiceHelper.getGlobalInstance(DistributedArpService.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+        ovsdbInventoryService =
+                (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
+        ovsdbInventoryService.listenerAdded(this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SubnetHandler.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SubnetHandler.java
new file mode 100644 (file)
index 0000000..1d37708
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt;
+
+import java.net.HttpURLConnection;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSubnetAware;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class SubnetHandler extends AbstractHandler implements INeutronSubnetAware, ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SubnetHandler.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile NeutronL3Adapter neutronL3Adapter;
+
+    @Override
+    public int canCreateSubnet(NeutronSubnet subnet) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSubnetCreated(NeutronSubnet subnet) {
+        enqueueEvent(new NorthboundEvent(subnet, Action.ADD));
+    }
+
+    @Override
+    public int canUpdateSubnet(NeutronSubnet delta, NeutronSubnet original) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSubnetUpdated(NeutronSubnet subnet) {
+        enqueueEvent(new NorthboundEvent(subnet, Action.UPDATE));
+    }
+
+    @Override
+    public int canDeleteSubnet(NeutronSubnet subnet) {
+        return HttpURLConnection.HTTP_OK;
+    }
+
+    @Override
+    public void neutronSubnetDeleted(NeutronSubnet subnet) {
+        enqueueEvent(new NorthboundEvent(subnet, Action.DELETE));
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                // fall through
+            case DELETE:
+                // fall through
+            case UPDATE:
+                Preconditions.checkNotNull(neutronL3Adapter);
+                neutronL3Adapter.handleNeutronSubnetEvent(ev.getSubnet(), ev.getAction());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Action.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Action.java
new file mode 100644 (file)
index 0000000..03862b9
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+/**
+ * This enumeration represents the type of action being performed
+ */
+public enum Action {
+    ADD,
+    UPDATE,
+    DELETE
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ArpProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ArpProvider.java
new file mode 100644 (file)
index 0000000..27422a7
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ * This interface allows ARP flows to be written to devices
+ */
+public interface ArpProvider {
+
+    Status programStaticArpEntry(Long dpid, String segmentationId,
+                                 String macAddress, InetAddress ipAddress, Action action);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/BridgeConfigurationManager.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/BridgeConfigurationManager.java
new file mode 100644 (file)
index 0000000..ff5d4c7
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import java.util.List;
+
+/**
+ * OpenStack Neutron with the Open vSwitch plugin relies on a typical bridge configuration that
+ * consists of br-int (Integration Bridge), br-net (Network bridge), br-ex (External bridge).
+ *
+ * This class ensures that the bridges on each {@link Node}
+ * are correctly configured for OpenStack Neutron
+ *
+ */
+public interface BridgeConfigurationManager {
+
+    /**
+     * A helper function to get the UUID of a given Bridge
+     * @param node the {@link Node} where the bridge is configured
+     * @param bridgeName the name of the bridge
+     * @return the UUID of the bridge
+     */
+    String getBridgeUuid(Node node, String bridgeName);
+
+    /**
+     * Checks for the existence of the Integration Bridge on a given Node
+     * @param node the {@link Node} where the bridge should be configured
+     * @return True if the bridge exists, False if it does not
+     */
+    boolean isNodeNeutronReady(Node node);
+
+    /**
+     * Checks for the existence of the Network Bridge on a given Node
+     * @param node the {@link Node} where the bridge should be configured
+     * @return True if the bridge exists, False if it does not
+     */
+    boolean isNodeOverlayReady(Node node);
+
+    /**
+     * Checks for the existence of the Network Bridge on a given Node
+     * @param node the {@link Node} where the bridge should be configured
+     * @return True if the bridge exists, False if it does not
+     */
+
+    /**
+     * Checks that a Node is ready for a Tunnel Network Provider
+     * For OpenFlow 1.0 the Integration, Network Bridge and corresponding patch ports are required
+     * For OpenFlow 1.3 only the Integration Bridge is required
+     * @param bridgeNode the {@link Node} that represents bridge
+     * @param ovsdbNode the {@link Node} where the bridge is configured
+     * @return True or False
+     */
+    boolean isNodeTunnelReady(Node bridgeNode, Node ovsdbNode);
+
+    /* Determine if internal network is ready for vlan network types.
+     * - OF 1.0 requires br-int, br-net, a patch connecting them and
+     * physical device added to br-net.
+     * - OF 1.3 requires br-int and physical device added to br-int.
+     */
+
+    /**
+     * Checks that a Node is ready for a VLAN Network Provider for the given Network
+     * For OpenFlow 1.0 the Integration Bridge, Network Bridge, patch ports and a physical device connected to the
+     * Network Bridge are required.
+     * For OpenFlow 1.3 the Integration Bridge is required and must have a physical device connected.
+     * @param bridgeNode the {@link Node} that represents bridge
+     * @param ovsdbNode the {@link Node} where the bridge is configured
+     * @param network the {@link org.opendaylight.netvirt.openstack.netvirt.translator}
+     * @return True or False
+     */
+    boolean isNodeVlanReady(Node bridgeNode, Node ovsdbNode, NeutronNetwork network);
+
+    /**
+     * A helper function to determine if a port exists on a given bridge
+     * @param node the {@link Node} where the bridge is configured
+     * @param portName the name of the port to search for
+     * @return True if the port exists, otherwise False
+     */
+    boolean isPortOnBridge(Node node, String portName);
+
+
+    /**
+     * Returns true if the bridges required for the provider network type are created
+     * If the bridges are not created, this method will attempt to create them
+     * @param node the {@link Node} to query
+     * @param network the {@link org.opendaylight.netvirt.openstack.netvirt.translator}
+     * @return True or False
+     */
+    boolean createLocalNetwork(Node node, NeutronNetwork network);
+
+    /**
+     * Prepares the given Node for Neutron Networking by creating the Integration Bridge
+     * @param node the {@link Node} to prepare
+     */
+    void prepareNode(Node node);
+
+    /**
+     * Returns the physical interface mapped to the given neutron physical network.
+     * @param node the {@link Node} to query
+     * @param physicalNetwork neutron physical network
+     * @return name of the physical interface
+     */
+    String getPhysicalInterfaceName(Node node, String physicalNetwork);
+
+    /** Returns all physical interfaces configured in the bridge mapping
+     * Bridge mappings will be of the following format:
+     * @param node the {@link Node} to query
+     * @return a List in the format {eth1, eth2} given bridge_mappings=physnet1:eth1,physnet2:eth2
+     */
+    List<String> getAllPhysicalInterfaceNames(Node node);
+
+   /*
+     * Return br-ex interface configured in the bridge_mappings.
+     * Return null if br-ex is not configured in bridge_mappings.
+     * @param node the {@link Node} to query
+     * @param externalNetwork
+     * @return the interface as a string like eth3 given bridge_mappings=br-ex:eth3
+   */
+     String getExternalInterfaceName (Node node, String externalNetwork);
+
+
+    /**
+     *
+     * @param node the {@link Node} to query
+     * @return a list of controllers
+     */
+    List<String> getControllersFromOvsdbNode(Node node);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ClassifierProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ClassifierProvider.java
new file mode 100644 (file)
index 0000000..d770d40
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+
+/**
+ *  This interface allows Classifier flows to be written to devices
+ */
+public interface ClassifierProvider {
+    void programLocalInPort(Long dpidLong, String segmentationId, Long inPort, String attachedMac, boolean write);
+    void programLocalInPortSetVlan(Long dpidLong, String segmentationId, Long inPort, String attachedMac, boolean write);
+    void programDropSrcIface(Long dpidLong, Long inPort, boolean write);
+    void programTunnelIn(Long dpidLong, String segmentationId, Long ofPort, boolean write);
+    void programVlanIn(Long dpidLong, String segmentationId, Long ethPort, boolean write);
+    void programLLDPPuntRule(Long dpidLong);
+    void programGotoTable(Long dpidLong, boolean write);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ConfigurationService.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/ConfigurationService.java
new file mode 100644 (file)
index 0000000..9e36b10
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import java.net.InetAddress;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * The ConfigurationService handles the configuration of the OpenStack Neutron Integration
+ * It exposes a set of Configuration variables and helper functions for obtaining node-specific
+ * configuration from the Open_vSwitch table of an OVS instance.
+ */
+public interface ConfigurationService {
+
+    /**
+     * @return the name configured name of the Integration Bridge
+     */
+    String getIntegrationBridgeName();
+
+    /**
+     * Configures the name of the Integration Bridge
+     * @param integrationBridgeName name of integration bridge
+     */
+    void setIntegrationBridgeName(String integrationBridgeName);
+
+    /**
+     * @return the name configured name of the Network Bridge
+     */
+    String getNetworkBridgeName();
+
+    /**
+     * Configures the name of the Network Bridge
+     * @param networkBridgeName Name of the network bridge
+     */
+    void setNetworkBridgeName(String networkBridgeName);
+
+    /**
+     * @return the name configured name of the ExternalBridge
+     */
+    String getExternalBridgeName();
+
+    /**
+     * Configures the name of the External Bridge
+     * @param externalBridgeName Name of external bridge
+     */
+    void setExternalBridgeName(String externalBridgeName);
+
+    /**
+     * @return the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     */
+    String getTunnelEndpointKey();
+
+    /**
+     * Sets the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     * @param tunnelEndpointKey key of tunnel end point
+     */
+    void setTunnelEndpointKey(String tunnelEndpointKey);
+
+    /**
+     * @return a Map of patch port names where the key is a tuple of source bridge and destination bridge
+     */
+    Map<Pair<String, String>, String> getPatchPortNames();
+
+    /**
+     * Sets the Map of source/destination bridges to patch port name
+     * @param patchPortNames Map of source/destination bridges to patch port name
+     */
+    void setPatchPortNames(Map<Pair<String, String>, String> patchPortNames);
+
+    /**
+     * Get the name of a patch port
+     * @param portTuple a {@link org.apache.commons.lang3.tuple.Pair} where L
+     *                  is the source bridge and R the destination bridge
+     * @return the name of the patch port
+     */
+    String getPatchPortName(Pair portTuple);
+
+    /**
+     * @return the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     */
+    String getProviderMappingsKey();
+
+    /**
+     * Sets the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     * @param providerMappingsKey provide mapping key
+     */
+    void setProviderMappingsKey(String providerMappingsKey);
+
+    /**
+     * @return Gets the default provider mapping
+     */
+    String getDefaultProviderMapping();
+
+    /**
+     * Sets the default provider mapping
+     * @param providerMapping provider mapping
+     */
+    void setDefaultProviderMapping(String providerMapping);
+
+    /**
+     * Gets the tunnel endpoint address for a given Node
+     * @param node a {@link Node}
+     * @return the tunnel endpoint
+     * @see java.net.InetAddress
+     */
+    InetAddress getTunnelEndPoint(Node node);
+
+    /**
+     * Returns the OpenFlow version to be used by the {@link NetworkingProvider}
+     * Default is OpenFlow 1.0. OVS versions greater than 1.10.0 will use OpenFlow 1.3
+     * @param node the node to query
+     * @return the OpenFlow version to use
+     */
+    String getOpenflowVersion(Node node);
+
+    /**
+     * Determine if L3 forwarding is enabled
+     * @return true if ovsdb net-virt is configured to perform L3 forwarding
+     */
+    boolean isL3ForwardingEnabled();
+
+    /**
+     * Determine if Distributed ARP Responder is enabled
+     * @return true if ovsdb net-virt is configured for distributed arp responder
+     */
+    boolean isDistributedArpDisabled();
+
+    /**
+     * Returns the MacAddress to be used for the default gateway by the {@link L3ForwardingProvider}
+     * There is no default.
+     * @param node the node to query
+     * @return the MacAddress to use for the default gateway; or null if none is configured.
+     */
+    String getDefaultGatewayMacAddress(Node node);
+
+    boolean isUserSpaceEnabled();
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Constants.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Constants.java
new file mode 100644 (file)
index 0000000..102a16b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+/**
+ * A collection of configuration constants
+ */
+public final class Constants {
+
+    /*
+     * External ID's used by OpenStack Neutron
+     */
+    public static final String EXTERNAL_ID_VM_ID = "vm-id";
+    public static final String EXTERNAL_ID_INTERFACE_ID = "iface-id";
+    public static final String EXTERNAL_ID_VM_MAC = "attached-mac";
+    public static final String EXTERNAL_NETWORK = "external";
+
+    /*
+     * @see http://docs.openstack.org/grizzly/openstack-network/admin/content/ovs_quantum_plugin.html
+     */
+    public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
+    public static final String INTEGRATION_BRIDGE = "br-int";
+    public static final String NETWORK_BRIDGE = "br-net";
+    public static final String EXTERNAL_BRIDGE = "br-ex";
+    public static final String PATCH_PORT_TO_INTEGRATION_BRIDGE_NAME = "patch-int";
+    public static final String PATCH_PORT_TO_NETWORK_BRIDGE_NAME = "patch-net";
+    public static final String PATCH_PORT_TO_EXTERNAL_BRIDGE_NAME = "patch-ext";
+    public static final String PROVIDER_MAPPINGS_KEY = "provider_mappings";
+    public static final String PROVIDER_MAPPING = "physnet1:eth1";
+
+    /*
+     * Flow Priority Defaults
+     */
+    public static final int LLDP_PRIORITY = 1000;
+    public static final int NORMAL_PRIORITY = 0;
+
+    /*
+     * OpenFlow Versions
+     */
+    public static final String OPENFLOW13 = "OpenFlow13";
+
+    /*
+     * VLAN Constants
+     */
+    public static final int MAX_VLAN = 4094;
+
+    /*
+     * OSGi Service Properties
+     */
+    public static final String SOUTHBOUND_PROTOCOL_PROPERTY = "southboundProtocol";
+    public static final String PROVIDER_TYPE_PROPERTY = "providerType";
+    public static final String OPENFLOW_VERSION_PROPERTY = "openflowVersion";
+    public static final String EVENT_HANDLER_TYPE_PROPERTY = "eventHandlerType";
+    public static final String PROVIDER_NAME_PROPERTY = "providerName";
+    public static final String NAT_PROVIDER_DIRECTION = "natDirection";
+
+    /*
+     * MD-SAL
+     */
+
+    public static final String OPENFLOW_NODE_PREFIX = "openflow:";
+    public static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
+
+    /*
+     * Ethertypes
+     */
+    public static final long ARP_ETHERTYPE = 0x0806L;
+
+
+    /*
+     * ACL
+     */
+    public static final Integer PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP = 61011;
+    public static final Integer PROTO_MATCH_PRIORITY_DROP = 36006;
+    public static final Integer PROTO_PORT_MATCH_PRIORITY_DROP = 36005;
+    public static final Integer PREFIX_MATCH_PRIORITY_DROP = 36004;
+    public static final Integer PROTO_PREFIX_MATCH_PRIORITY_DROP = 36003;
+    public static final Integer PREFIX_PORT_MATCH_PRIORITY_DROP = 36002;
+
+    public static final Integer PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY = 61012;
+    public static final Integer PROTO_MATCH_PRIORITY = 61010;
+    public static final Integer PREFIX_MATCH_PRIORITY = 61009;
+    public static final Integer PROTO_PREFIX_MATCH_PRIORITY = 61008;
+    public static final Integer PROTO_PORT_MATCH_PRIORITY = 61007;
+    public static final Integer PROTO_PORT_PREFIX_MATCH_PRIORITY = 61007;
+    public static final Integer PROTO_DHCP_SERVER_MATCH_PRIORITY = 61006;
+    public static final Integer PROTO_VM_IP_MAC_MATCH_PRIORITY = 36001;
+    public static final Integer CT_STATE_UNTRACKED_PRIORITY = 62030;
+    public static final Integer CT_STATE_TRACKED_EXIST_PRIORITY = 62020;
+    public static final Integer CT_STATE_TRACKED_NEW_PRIORITY = 62010;
+    public static final Integer CT_STATE_NEW_PRIORITY_DROP = 36007;
+
+    public static final int TCP_SYN = 0x002;
+    public static final short INGRESS_ACL = 40; // Flows Destined to the VM Port go here
+    public static final short OUTBOUND_SNAT = 110; // Ingress ACL table drains traffic to this table
+
+    private static Long groupId = 1L;
+
+    //6653 is official openflow port.
+    public static short OPENFLOW_PORT = 6653;
+    public static String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
+
+    /*
+     * Clustering
+     */
+    public static final String NETVIRT_OWNER_ENTITY_TYPE = "ovsdb-netvirt-provider";
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/EgressAclProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/EgressAclProvider.java
new file mode 100644 (file)
index 0000000..1f049b0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+
+import java.util.List;
+
+/**
+ *  This interface allows egress Port Security flows to be written to devices.
+ */
+public interface EgressAclProvider {
+
+    /**
+     * Program port security Group.
+     *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param securityGroup the security group
+     * @param portUuid the uuid of the port.
+     * @param write  is this flow write or delete
+     */
+    void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac,
+                                       long localPort, NeutronSecurityGroup securityGroup,
+                                       String portUuid, boolean write);
+    /**
+     * Program port security rule.
+     *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param portSecurityRule the security rule
+     * @param vmIp the ip of the remote vm if it has a remote security group.
+     * @param write  is this flow write or delete
+     */
+    public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
+                                        long localPort, NeutronSecurityRule portSecurityRule,
+                                        Neutron_IPs vmIp, boolean write) ;
+    /**
+     *  Program fixed egress security group rules that will be associated with the VM port when a vm is spawned.
+     *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param srcAddressList the list of source ip address assigned to vm
+     * @param write is this flow writing or deleting
+     */
+    void programFixedSecurityGroup(Long dpid, String segmentationId,String attachedMac, long localPort,
+                                  List<Neutron_IPs> srcAddressList, boolean write);
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/EventDispatcher.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/EventDispatcher.java
new file mode 100644 (file)
index 0000000..5fffb3b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Openstack related events will be enqueued into a common event queue.
+ * This interface provides access to an event dispatcher, as well as registration to link dispatcher to which handlers
+ * dispatcher will utilize.
+ */
+public interface EventDispatcher {
+    /**
+     * Enqueue the event.
+     * @param event the {@link AbstractEvent} event to be handled.
+     */
+    void enqueueEvent(AbstractEvent event);
+    void eventHandlerAdded(final ServiceReference ref, AbstractHandler handler);
+    void eventHandlerRemoved(final ServiceReference ref);
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/GatewayMacResolver.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/GatewayMacResolver.java
new file mode 100644 (file)
index 0000000..7f48f10
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+*
+* @author Anil Vishnoi (avishnoi@Brocade.com)
+*
+*/
+
+public interface GatewayMacResolver {
+
+    /**
+     * Method will trigger the mac resolution for gateway IP. If user set periodicRefresh to true,
+     * it will periodically trigger the gateway resolution after a specific time interval using the
+     * given source IP and MAC addresses. It will also cache the source IP and MAC in case of periodicRefresh.
+     * If periodicRefresh is false, it will just do one time gateway resolution and won't cache any internal data.
+     * If user call the same method with different source ip and mac address, GatewayMacResolver service will
+     * update the internally cached data with these new source ip and mac address and will use it as per
+     * periodicRefresh flag.
+     * @param gatewayMacResolverListener An optional listener for mac update callback (can be null)
+     * @param externalNetworkBridgeDpid This bridge will be used for sending ARP request
+     * @param refreshExternalNetworkBridgeDpidIfNeeded Instructs resolver to change bridge dpid if resolve is failing
+     * @param gatewayIp ARP request will be send for this ip address
+     * @param sourceIpAddress Source IP address for the ARP request (localhost)
+     * @param sourceMacAddress Source MAC address for the ARP request (localhost)
+     * @param periodicRefresh Do you want to periodically refresh the gateway mac?
+     * @return ListenableFuture that contains the mac address of gateway ip.
+     */
+    public ListenableFuture<MacAddress> resolveMacAddress(
+            final GatewayMacResolverListener gatewayMacResolverListener,
+            final Long externalNetworkBridgeDpid, final Boolean refreshExternalNetworkBridgeDpidIfNeeded,
+            final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress,
+            final MacAddress sourceMacAddress, final Boolean periodicRefresh);
+
+    /**
+     * Method will stop the periodic refresh of the given gateway ip address.
+     * @param gatewayIp Gateway IP Address
+     */
+    public void stopPeriodicRefresh(final Ipv4Address gatewayIp);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/GatewayMacResolverListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/GatewayMacResolverListener.java
new file mode 100644 (file)
index 0000000..fc93286
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+/**
+ * This interface allows for notifications from GatewayMacResolver to a generic listener.
+ */
+public interface GatewayMacResolverListener {
+
+    /**
+     * Method will trigger when the mac for gateway IP is resolved or updated.
+     *
+     * @param externalNetworkBridgeDpid Bridge used for sending ARP request
+     * @param gatewayIpAddress Ip address that Mac Resolver ARPed for
+     * @param macAddress Mac Address associated with the gatewayIpAddress
+     */
+    void gatewayMacResolved(final Long externalNetworkBridgeDpid, final IpAddress gatewayIpAddress,
+                            final MacAddress macAddress);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/IcmpEchoProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/IcmpEchoProvider.java
new file mode 100644 (file)
index 0000000..bcea52b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ * @author Josh Hershberg (jhershbe@redhat.com)
+ */
+public interface IcmpEchoProvider {
+
+    Status programIcmpEchoEntry(Long dpid, String segmentationId,
+                                 String macAddress, InetAddress ipAddress, Action action);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/InboundNatProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/InboundNatProvider.java
new file mode 100644 (file)
index 0000000..7ed1a55
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ *  This interface allows NAT flows to be written to devices
+ */
+public interface InboundNatProvider {
+    Status programIpRewriteRule(Long dpid, Long inPort, String destSegId, InetAddress matchAddress,
+                                InetAddress rewriteAddress, Action action);
+
+    Status programIpRewriteExclusion(Long dpid, String segmentationId,
+                                     String excludedCidr, Action action);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/IngressAclProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/IngressAclProvider.java
new file mode 100644 (file)
index 0000000..b587a24
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+
+/**
+ *  This interface allows ingress Port Security flows to be written to devices.
+ */
+public interface IngressAclProvider {
+
+    /**
+     * Program port security Group.
+     *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param securityGroup the security group
+     * @param portUuid the uuid of the port.
+     * @param write  is this flow write or delete
+     */
+    void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac,
+                                       long localPort, NeutronSecurityGroup securityGroup,
+                                       String portUuid, boolean write);
+    /**
+     * Program port security rule.
+     *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param portSecurityRule the security rule
+     * @param vmIp the ip of the remote vm if it has a remote security group.
+     * @param write  is this flow write or delete
+     */
+    void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
+                                 long localPort, NeutronSecurityRule portSecurityRule,
+                                 Neutron_IPs vmIp, boolean write);
+    /**
+     * Program fixed ingress ACL rules that will be associated with the VM port when a vm is spawned.
+     * *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the dhcp mac
+     * @param localPort the local port
+     * @param attachedMac2 the src mac
+     * @param write is this flow writing or deleting
+     */
+    void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac, long localPort,
+                                  String attachedMac2, boolean write);
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L2ForwardingProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L2ForwardingProvider.java
new file mode 100644 (file)
index 0000000..92b95de
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+/**
+ *  This interface allows L2Forwarding flows to be written to devices
+ */
+public interface L2ForwardingProvider {
+    void programLocalUcastOut(Long dpidLong, String segmentationId, Long localPort, String attachedMac, boolean write);
+    void programLocalVlanUcastOut(Long dpidLong, String segmentationId, Long localPort, String attachedMac, boolean write);
+    void programLocalBcastOut(Long dpidLong, String segmentationId, Long localPort, boolean write);
+    void programLocalVlanBcastOut(Long dpidLong, String segmentationId, Long localPort, Long ethPort, boolean write);
+    void programLocalTableMiss(Long dpidLong, String segmentationId, boolean write);
+    void programLocalVlanTableMiss(Long dpidLong, String segmentationId, boolean write);
+    void programTunnelOut(Long dpidLong, String segmentationId, Long OFPortOut, String attachedMac, boolean write);
+    void programVlanOut(Long dpidLong, String segmentationId, Long ethPort, String attachedMac, boolean write);
+    void programTunnelFloodOut(Long dpidLong, String segmentationId, Long OFPortOut, boolean write);
+    void programVlanFloodOut(Long dpidLong, String segmentationId, Long ethPort, boolean write);
+    void programTunnelMiss(Long dpidLong, String segmentationId, boolean write);
+    void programVlanMiss(Long dpidLong, String segmentationId, Long ethPort, boolean write);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L2RewriteProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L2RewriteProvider.java
new file mode 100644 (file)
index 0000000..1293c1c
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+/**
+ *  This interface allows L2Rewrite flows to be written to devices
+ */
+public interface L2RewriteProvider {
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L3ForwardingProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/L3ForwardingProvider.java
new file mode 100644 (file)
index 0000000..9362b2f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ * This interface allows L3 Forwarding flows to be written to devices
+ */
+public interface L3ForwardingProvider {
+
+    Status programForwardingTableEntry(Long dpid, String segmentationId, InetAddress ipAddress,
+                                       String macAddress, Action action);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerConfiguration.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerConfiguration.java
new file mode 100755 (executable)
index 0000000..02e5039
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2014, 2015 SDN Hub, LLC. 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.openstack.netvirt.api;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Store configuration for each load balancer instance created.
+ */
+
+public class LoadBalancerConfiguration {
+    public static final String PROTOCOL_TCP = "TCP";
+    public static final String PROTOCOL_HTTP = "HTTP";
+    public static final String PROTOCOL_HTTPS = "HTTPS";
+
+    public class LoadBalancerPoolMember {
+        String ipAddr;
+        String macAddr;
+        String protocol;
+        Integer port;
+        int index;
+
+        public LoadBalancerPoolMember(String ipAddr, String macAddr, String protocol, Integer port) {
+            this.ipAddr = ipAddr;
+            this.macAddr = macAddr;
+            this.protocol = protocol;
+            this.port = port;
+            this.index = -1;
+        }
+        public LoadBalancerPoolMember(String ipAddr, String macAddr, String protocol, Integer port, int index) {
+            this.ipAddr = ipAddr;
+            this.macAddr = macAddr;
+            this.protocol = protocol;
+            this.port = port;
+            this.index = index;
+        }
+        public String getIP() {
+            return ipAddr;
+        }
+        public String getMAC() {
+            return macAddr;
+        }
+        public String getProtocol() {
+            return protocol;
+        }
+        public Integer getPort() {
+            return port;
+        }
+        public int getIndex() {
+            return index;
+        }
+        public void setIndex(int index) {
+            this.index = index;
+        }
+
+        /**
+         * Overridden equals() where index is not checked.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            LoadBalancerPoolMember other = (LoadBalancerPoolMember) obj;
+            if (ipAddr == null) {
+                if (other.ipAddr != null) {
+                    return false;
+                }
+            } else if (!ipAddr.equals(other.ipAddr)) {
+                return false;
+            }
+            if (macAddr == null) {
+                if (other.macAddr != null) {
+                    return false;
+                }
+            } else if (!macAddr.equals(other.macAddr)) {
+                return false;
+            }
+            if (port == null) {
+                if (other.port != null) {
+                    return false;
+                }
+            } else if (!port.equals(other.port)) {
+                return false;
+            }
+            if (protocol == null) {
+                if (other.protocol != null) {
+                    return false;
+                }
+            } else if (!protocol.equals(other.protocol)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "LoadBalancerPoolMember [ip=" + ipAddr + ", mac=" + macAddr +
+                    ", protocol=" + protocol + ", port=" + port + ", index=" + index + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((ipAddr == null) ? 0 : ipAddr.hashCode());
+            result = prime * result + ((macAddr == null) ? 0 : macAddr.hashCode());
+            result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
+            result = prime * result + ((port == null) ? 0 : port.hashCode());
+            return result;
+        }
+    }
+
+    private String name;
+    private String vip;
+    private String vmac; //Used when a dummy neutron port is created for the VIP
+    private String providerNetworkType;
+    private String providerSegmentationId;
+    private Map <String, LoadBalancerPoolMember> members;
+
+    public LoadBalancerConfiguration() {
+        this.members = Maps.newHashMap();
+    }
+
+    public LoadBalancerConfiguration(String name, String vip) {
+        this.members = Maps.newHashMap();
+        this.name = name;
+        this.vip = vip;
+        this.vmac = null;
+    }
+
+    public LoadBalancerConfiguration(String name, String vip, String vmac) {
+        this.members = Maps.newHashMap();
+        this.name = name;
+        this.vip = vip;
+        this.vmac = vmac;
+    }
+
+    public LoadBalancerConfiguration(LoadBalancerConfiguration lbConfig) {
+        this.members = Maps.newHashMap(lbConfig.getMembers());
+        this.name = lbConfig.getName();
+        this.vip = lbConfig.getVip();
+        this.vmac = lbConfig.getVmac();
+        this.providerNetworkType = lbConfig.getProviderNetworkType();
+        this.providerSegmentationId = lbConfig.getProviderSegmentationId();
+    }
+
+    public Map<String, LoadBalancerPoolMember> getMembers() {
+        return this.members;
+    }
+
+    public Map<String, LoadBalancerPoolMember> addMember(String uuid, LoadBalancerPoolMember member) {
+        //If index is not set for this object, update it before inserting
+        if (member.getIndex() == -1) {
+            member.setIndex(members.size());
+        }
+        this.members.put(uuid, member);
+        return this.members;
+    }
+    public Map<String, LoadBalancerPoolMember> addMember(String uuid, String ipAddr, String macAddr, String protocol, Integer port) {
+        this.members.put(uuid,
+                new LoadBalancerPoolMember(ipAddr, macAddr, protocol, port, members.size()));
+        return this.members;
+    }
+    public Map<String, LoadBalancerPoolMember> removeMember(String uuid) {
+        this.members.remove(uuid);
+        /* Update indices of all other members
+         */
+        int index = 0;
+        for(Map.Entry<String, LoadBalancerPoolMember> entry : this.getMembers().entrySet()) {
+            entry.getValue().setIndex(index++);
+        }
+        return this.members;
+    }
+
+    public boolean isValid() {
+        if (members.size() == 0) {
+            return false;
+        } else if (providerNetworkType == null) {
+            return false;
+        }
+        return true;
+    }
+
+    public void setVip(String vip) {
+        this.vip = vip;
+    }
+
+    public String getVip() {
+        return this.vip;
+    }
+
+    public void setVmac(String vmac) {
+        this.vmac = vmac;
+    }
+
+    public String getVmac() {
+        return this.vmac;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setProviderSegmentationId(String providerSegmentationId) {
+        this.providerSegmentationId = providerSegmentationId;
+    }
+
+    public String getProviderSegmentationId() {
+        return this.providerSegmentationId;
+    }
+    public void setProviderNetworkType(String providerNetworkType) {
+        this.providerNetworkType = providerNetworkType;
+    }
+
+    public String getProviderNetworkType() {
+        return this.providerNetworkType;
+    }
+
+    @Override
+    public String toString() {
+        return "LoadBalancerConfiguration [name=" + name +
+                ", vip=" + vip + ", vmac=" + vmac +
+                ", networkType=" + providerNetworkType +
+                ", segmentationId=" + providerSegmentationId +
+                ", members=" + members + "]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerProvider.java
new file mode 100755 (executable)
index 0000000..a2df57b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 SDN Hub, LLC. 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration.LoadBalancerPoolMember;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * This interface allows load-balancer flows to be written to nodes
+ */
+public interface LoadBalancerProvider {
+
+    Status programLoadBalancerRules(Node node,
+            LoadBalancerConfiguration lbConfig, Action action);
+
+    Status programLoadBalancerPoolMemberRules(Node node,
+            LoadBalancerConfiguration lbConfig, LoadBalancerPoolMember member, Action action);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/MultiTenantAwareRouter.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/MultiTenantAwareRouter.java
new file mode 100644 (file)
index 0000000..4e399fd
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+import java.util.UUID;
+
+/**
+ * A Router that is Multi-Tenant Aware
+ * Each tenant has a Unique Identifier which is used to isolate interfaces/routes
+ */
+public interface MultiTenantAwareRouter {
+
+    void addInterface(UUID tenantId, String interfaceName, InetAddress address, int mask);
+
+    void addInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask);
+
+    void updateInterface(UUID tenantId, String interfaceName, InetAddress address, int mask);
+
+    void updateInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask);
+
+    void removeInterface(UUID tenantId, String interfaceName);
+
+    void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop);
+
+    void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority);
+
+    void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop);
+
+    void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority);
+
+    void addDefaultRoute(UUID tenantId, InetAddress nextHop);
+
+    void addDefaultRoute(UUID tenantId, InetAddress nextHop, Integer priority);
+
+    void addNatRule(UUID tenantId, InetAddress matchAddress, InetAddress rewriteAddress);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProvider.java
new file mode 100644 (file)
index 0000000..791925a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * The NetworkingProvider interface is implemented by Neutron Networking Providers
+ */
+public interface NetworkingProvider {
+
+    /**
+     * @return the name of the NetworkingProvider
+     */
+    String getName();
+
+    /**
+     * @return true if the provider supports Network Service Instances
+     */
+    boolean supportsServices();
+
+    /**
+     * @return true if the provider supports per-tenant or "static" tunneling
+     */
+    boolean hasPerTenantTunneling();
+
+    /**
+     * Handle Interface Update Callback Method
+     * @param network Neutron Network attached to the interface
+     * @param source Source node where interface is attached
+     * @param intf Termination point attached to the node
+     * @return true if interface update handled successfully
+     */
+    boolean handleInterfaceUpdate(NeutronNetwork network, Node source, OvsdbTerminationPointAugmentation intf);
+
+    /**
+     * Handle Interface Delete Callback Method
+     * @param tunnelType Type of the tunnel (e.g. vxlan)
+     * @param network Neutron Network associated with the removed interface
+     * @param source Source node where interface was attached
+     * @param intf Termination point associated to the deleted interface
+     * @param isLastInstanceOnNode is last interface attached to the node ?
+     * @return true if interface delete handled successfully
+     */
+    boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node source,
+                                  OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode);
+
+    /**
+     * Initialize the Flow rules given the OVSDB node.
+     * This method provides a set of common functionalities to initialize the Flow rules of an OVSDB node
+     * that are Openflow Version specific. Hence we have this method in addition to the following
+     * Openflow Node specific initialization method.
+     * @param node Node on which flow rules are going to be installed
+     */
+    void initializeFlowRules(Node node);
+
+    /**
+     * Initialize the Flow rules for a given OpenFlow node
+     * @param openflowNode Node on which flow rules are going to be installed
+     */
+    void initializeOFFlowRules(Node openflowNode);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProviderManager.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProviderManager.java
new file mode 100644 (file)
index 0000000..d68724e
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The NetworkingProviderManager handles the mapping between {@link Node}
+ * and registered {@link NetworkingProvider} implementations
+ */
+public interface NetworkingProviderManager {
+    /**
+     * Returns the Networking Provider for a given node
+     * @param ovsdbNode a {@link Node}
+     * @return a NetworkProvider
+     * @see NetworkingProvider
+     */
+    NetworkingProvider getProvider(Node ovsdbNode);
+    void providerAdded(final ServiceReference ref, final NetworkingProvider provider);
+    void providerRemoved(final ServiceReference ref);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NodeCacheListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NodeCacheListener.java
new file mode 100644 (file)
index 0000000..2784fd4
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * When this interface is used, instance owner will get callbacks on
+ * changes that occur in NodeCacheManager
+ *
+ * @author Flavio Fernandes (ffernand@redhat.com)
+ * @author Sam Hague (shague@redhat.com)
+ */
+public interface NodeCacheListener {
+    void notifyNode(Node node, Action action);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NodeCacheManager.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NodeCacheManager.java
new file mode 100644 (file)
index 0000000..8f063fd
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This interface is used to cache ids of nodes that are needed by net-virt.
+ * The nodes are added and removed by an external listener.
+ *
+ * @author Flavio Fernandes (ffernand@redhat.com)
+ * @author Sam Hague (shague@redhat.com)
+ */
+public interface NodeCacheManager {
+    void nodeAdded(Node node);
+    void nodeRemoved(Node node);
+    List<Node> getNodes();
+    Map<NodeId, Node> getOvsdbNodes();
+    List<Node> getBridgeNodes();
+    List<Long> getBridgeDpids(final String bridgeName);
+    void cacheListenerAdded(final ServiceReference ref, NodeCacheListener handler);
+    void cacheListenerRemoved(final ServiceReference ref);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OutboundNatProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OutboundNatProvider.java
new file mode 100644 (file)
index 0000000..d0734d4
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ *  This interface allows NAT flows to be written to devices
+ */
+public interface OutboundNatProvider {
+    Status programIpRewriteRule(Long dpidLong,
+                                String matchSegmentationId,
+                                String matchDestMacAddress,
+                                InetAddress matchSrcAddress,
+                                String rewriteSrcMacAddress,
+                                String rewriteDestMacAddress,
+                                InetAddress rewriteSrcAddress,
+                                Long OutPort,
+                                Action action);
+
+    Status programIpRewriteExclusion(Long dpid, String segmentationId,
+                                     String excludedCidr, Action action);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbInventoryListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbInventoryListener.java
new file mode 100644 (file)
index 0000000..31b48aa
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+public interface OvsdbInventoryListener {
+    enum OvsdbType {
+        NODE,
+        ROW,
+        OPENVSWITCH,
+        BRIDGE,
+        CONTROLLER,
+        PORT
+    }
+    void ovsdbUpdate(Node node, DataObject augmentationDataChanges, OvsdbType type, Action action);
+    void triggerUpdates();
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbInventoryService.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbInventoryService.java
new file mode 100644 (file)
index 0000000..f8b5885
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+/**
+ * OvsdbInventoryService is the interface to the southbound for netvirt.
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+public interface OvsdbInventoryService {
+    void listenerAdded(OvsdbInventoryListener listener);
+    void listenerRemoved(OvsdbInventoryListener listener);
+    void providersReady();
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbPluginException.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbPluginException.java
new file mode 100644 (file)
index 0000000..a026213
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+public class OvsdbPluginException extends RuntimeException {
+    public OvsdbPluginException(String message){
+        super(message);
+    }
+
+    public OvsdbPluginException(String message, Throwable cause){
+        super(message, cause);
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbTables.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/OvsdbTables.java
new file mode 100644 (file)
index 0000000..6bef17b
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+/**
+ * Enum for OVSDB tables
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+public enum OvsdbTables {
+    BRIDGE,
+    CONTROLLER,
+    OPENVSWITCH,
+    PORT
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Router.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Router.java
new file mode 100644 (file)
index 0000000..ab1769d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ * A Router
+ */
+public interface Router {
+
+    void addInterface(String interfaceName, InetAddress address, int mask);
+
+    void addInterface(String interfaceName, String macAddress, InetAddress address, int mask);
+
+    void updateInterface(String interfaceName, InetAddress address, int mask);
+
+    void updateInterface(String interfaceName, String macAddress, InetAddress address, int mask);
+
+    void removeInterface(String interfaceName);
+
+    void addRoute(String destinationCidr, InetAddress nextHop);
+
+    void addRoute(String destinationCidr, InetAddress nextHop, Integer priority);
+
+    void removeRoute(String destinationCidr, InetAddress nextHop);
+
+    void removeRoute(String destinationCidr, InetAddress nextHop, Integer priority);
+
+    void addDefaultRoute(InetAddress nextHop);
+
+    void addDefaultRoute(InetAddress nextHop, Integer priority);
+
+    void addNatRule(InetAddress matchAddress, InetAddress rewriteAddress);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/RoutingProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/RoutingProvider.java
new file mode 100644 (file)
index 0000000..f5257c3
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import java.net.InetAddress;
+
+/**
+ * This interface allows Routing flows to be written to devices
+ */
+public interface RoutingProvider {
+
+    Status programRouterInterface(Long dpid, String srcSegId, String dstSegId, String macAddress,
+                                  InetAddress address, int mask, Action action);
+
+    Status programDefaultRouteEntry(Long dpid, String segmentationId, String macAddress,
+                                    InetAddress nextHop, Action action);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityGroupCacheManger.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityGroupCacheManger.java
new file mode 100644 (file)
index 0000000..85cc3fb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, 2015 HP, 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.openstack.netvirt.api;
+
+/**
+ *  This interface maintain a mapping between the security group and the ports
+ *  have this security group as a remote security group. Whenever a new port is
+ *  added with a security group associated with it, a rule will be added to allow
+ *  traffic from/to the vm from  the vms which has the former as a remote sg in its rule.
+ *
+ *  @author Aswin Suryanarayanan.
+ */
+
+public interface SecurityGroupCacheManger {
+
+    /**
+     * Notifies that a new port in the security group with securityGroupUuid.
+     * @param securityGroupUuid the uuid of the security group associated with the port.
+     * @param portUuid the uuid of the port.
+     */
+    void portAdded(String securityGroupUuid, String portUuid);
+    /**
+     * Notifies that a port is removed with the securityGroupUuid.
+     * @param securityGroupUuid the uuid of the security group associated with the port.
+     * @param portUuid the uuid of the port.
+     */
+    void portRemoved(String securityGroupUuid, String portUuid);
+    /**
+     * A port with portUuid has a reference remote security group remoteSgUuid will be added
+     * to the cache maintained.
+     * @param remoteSgUuid the remote security group uuid.
+     * @param portUuid the uuid of the port.
+     */
+    void addToCache(String remoteSgUuid, String portUuid);
+    /**A port with portUUID has a reference remote security group remoteSgUuid will be removed
+     * from the cache maintained.
+     * @param remoteSgUuid the remote security group uuid.
+     * @param portUuid portUUID the uuid of the port.
+     */
+    void removeFromCache(String remoteSgUuid, String portUuid);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityServicesManager.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityServicesManager.java
new file mode 100644 (file)
index 0000000..2418792
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import java.util.List;
+
+/**
+ * Open vSwitch isolates Tenant Networks using VLANs on the Integration Bridge.
+ * This class manages the provisioning of these VLANs
+ */
+public interface SecurityServicesManager {
+    /**
+     * Is port security ready.
+     *
+     * @param intf the intf
+     * @return the boolean
+     */
+    boolean isPortSecurityReady(OvsdbTerminationPointAugmentation intf);
+    /**
+     * Gets security group in port.
+     *
+     * @param intf the intf
+     * @return the list of security group in port, returns empty list if no group associated.
+     */
+    List<NeutronSecurityGroup> getSecurityGroupInPortList(OvsdbTerminationPointAugmentation intf);
+    /**
+     * Gets the DHCP server port corresponding to a network.
+     *
+     * @param intf the intf
+     * @return the dhcp server port
+     */
+    NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation intf);
+    /**
+     * Gets the NeutronPort from the cleanup cache.
+     *
+     * @param intf the intf
+     * @return the NeutronPort stored in the cleanupCache of NeutronL3Adapter
+     */
+    NeutronPort getNeutronPortFromCache(OvsdbTerminationPointAugmentation intf);
+
+    /**
+      * Check if the given interface corresponds to a DHCP server port.
+      *
+      * @param intf the intf
+      * @return Return the DHCP neutron port
+      */
+    NeutronPort getNeutronPortFromDhcpIntf(OvsdbTerminationPointAugmentation intf);
+
+    /**
+     * Is the port a compute port.
+     *
+     * @param intf the intf
+     * @return  whether it is a compute port or not
+     */
+    boolean isComputePort(OvsdbTerminationPointAugmentation intf);
+
+    /**
+     * Is this the last port in the subnet to which interface belongs to.
+     * @param node The node to which the intf is connected.
+     * @param intf the interface
+     * @return whether last port in the subnet
+     */
+    boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation intf);
+
+    /**
+     * Is this the last port in the bridge to which interface belongs to.
+     * @param node The node to which the intf is connected.
+     * @param intf the intf
+     * @return whether last port in bridge
+     */
+    boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation intf);
+    /**
+     * Returns the  list of ip address assigned to the interface.
+     * @param intf the intf
+     * @return the list of ip address associated with the vm
+     */
+    List<Neutron_IPs> getIpAddressList(OvsdbTerminationPointAugmentation intf);
+    /**
+     * Get the list of vm belonging to a security group.
+     * @param portUuid the uuid of the port.
+     * @param securityGroupUuid the UUID of the remote security group.
+     * @return the list of all vm belonging to the security group UUID passed.
+     */
+    List<Neutron_IPs> getVmListForSecurityGroup(String portUuid,
+                                                String securityGroupUuid);
+    /**
+     * Add or remove the security groups  from the port.
+     * @param port the neutron port.
+     * @param securityGroup the security group associated with the port.
+     * @param write whether to add/delete flow.
+     */
+    void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroup, boolean write);
+    /**
+     * Add or remove individual security  rules from the port.
+     * @param port the neutron port.
+     * @param securityRule the security group associated with the port.
+     * @param vmIp The list of remote vm ips.
+     * @param write whether to add/delete flow.
+     */
+    void syncSecurityRule(NeutronPort port, NeutronSecurityRule securityRule,Neutron_IPs vmIp, boolean write);
+    /**
+     * Is connection tracking enabled or not by the user (default is false).
+     * @return whether connection tracking enabled.
+     */
+    boolean isConntrackEnabled();
+    /**
+     * Is the port a PortSecurity Enabled.
+     *
+     * @param intf the port
+     * @return  whether it is a compute port or not
+     */
+    boolean isPortSecurityEnabled(OvsdbTerminationPointAugmentation intf);
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Southbound.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Southbound.java
new file mode 100644 (file)
index 0000000..b67b4db
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.api;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+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.node.attributes.ConnectionInfo;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+
+/**
+ * Utility class to wrap southbound transactions.
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+public interface Southbound {
+    ConnectionInfo getConnectionInfo(Node node);
+    OvsdbNodeAugmentation extractOvsdbNode(Node node);
+    NodeId extractBridgeOvsdbNodeId(Node bridgeNode);
+    List<Node> readOvsdbTopologyNodes();
+    List<Node> readOvsdbTopologyBridgeNodes();
+    Node readOvsdbNode(Node bridgeNode);
+    boolean isBridgeOnOvsdbNode(Node node, String bridgeName);
+    String getOvsdbNodeUUID(Node node);
+    String getOsdbNodeExternalIdsValue(OvsdbNodeAugmentation ovsdbNodeAugmentation, String key);
+    boolean addBridge(Node ovsdbNode, String bridgeName, List<String> controllersStr,
+                      final Class<? extends DatapathTypeBase> dpType);
+    boolean deleteBridge(Node ovsdbNode);
+    OvsdbBridgeAugmentation readBridge(Node node, String name);
+    Node readBridgeNode(Node node, String name);
+    Node getBridgeNode(Node node, String bridgeName);
+    String getBridgeUuid(Node node, String name);
+    long getDataPathId(Node node);
+    String getDatapathId(Node node);
+    String getDatapathId(OvsdbBridgeAugmentation ovsdbBridgeAugmentation);
+    OvsdbBridgeAugmentation getBridge(Node node, String name);
+    OvsdbBridgeAugmentation getBridge(Node node);
+    String getBridgeName(Node node);
+    String extractBridgeName(Node node);
+    OvsdbBridgeAugmentation extractBridgeAugmentation(Node node);
+    List<Node> getAllBridgesOnOvsdbNode(Node node);
+    OvsdbNodeAugmentation extractNodeAugmentation(Node node);
+    List<OvsdbTerminationPointAugmentation> getTerminationPointsOfBridge(Node node);
+    OvsdbTerminationPointAugmentation getTerminationPointOfBridge(Node node, String terminationPoint);
+    OvsdbTerminationPointAugmentation extractTerminationPointAugmentation(Node bridgeNode, String portName);
+    List<TerminationPoint> extractTerminationPoints(Node node);
+    List<OvsdbTerminationPointAugmentation> extractTerminationPointAugmentations(Node node);
+    List<OvsdbTerminationPointAugmentation> readTerminationPointAugmentations(Node node);
+    String getInterfaceExternalIdsValue(
+            OvsdbTerminationPointAugmentation terminationPointAugmentation, String key);
+    Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type);
+    Boolean deleteTerminationPoint(Node bridgeNode, String portName);
+    Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName,
+                                String type, Map<String, String> options);
+    TerminationPoint readTerminationPoint(Node bridgeNode, String bridgeName, String portName);
+    Boolean addTunnelTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type,
+                                      Map<String, String> options);
+    Boolean isTunnelTerminationPointExist(Node bridgeNode, String bridgeName, String portName);
+    Boolean addPatchTerminationPoint(Node node, String bridgeName, String portName, String peerPortName);
+    String getExternalId(Node node, OvsdbTables table, String key);
+    String getOtherConfig(Node node, OvsdbTables table, String key);
+    boolean addVlanToTp(long vlan);
+    boolean isTunnel(OvsdbTerminationPointAugmentation port);
+    String getOptionsValue(List<Options> options, String key);
+    Topology getOvsdbTopology();
+    Long getOFPort(OvsdbTerminationPointAugmentation port);
+    Long getOFPort(Node bridgeNode, String portName);
+    DataBroker getDatabroker();
+    OvsdbBridgeAugmentation getBridgeFromConfig(Node ovsdbNode, String bridgeName);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Status.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/Status.java
new file mode 100644 (file)
index 0000000..61919be
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.api;
+
+import java.io.Serializable;
+
+/**
+ * Represents the return object of the osgi service interfaces function calls.
+ * It contains a code {@code StatusCode} representing the result of the call and
+ * a string which describes a failure reason (if any) in human readable form.
+ */
+public class Status implements Serializable {
+    private static final long serialVersionUID = 0L;
+    private StatusCode code;
+    private String description;
+    private long requestId;
+
+    /**
+     * Generates an instance of the Status class. This is used as return code
+     * for internal API2 function calls. This constructor allows to specify,
+     * beside the Status Code, a custom human readable description to add more
+     * information about the status.
+     *
+     * @param errorCode
+     *            The status code. If passed as null, code will be stored as
+     *            {@code StatusCode.UNDEFINED}
+     * @param description
+     *            The human readable description of the status. If passed as
+     *            null, description will be inferred by the code
+     */
+    public Status(StatusCode errorCode, String description) {
+        this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
+        this.description = (description != null) ? description : this.code
+                .toString();
+        this.requestId = 0;
+    }
+
+    /**
+     * Generates an instance of the Status class based on the passed StatusCode
+     * only. The description field of the Status object will be inferred by the
+     * status code.
+     *
+     * @param errorCode
+     *            The status code. If passed as null, code will be stored as
+     *            {@code StatusCode.UNDEFINED}
+     */
+    public Status(StatusCode errorCode) {
+        this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
+        this.description = (description != null) ? description : this.code
+                .toString();
+        this.requestId = 0;
+    }
+
+    /**
+     * Generates an instance of the Status class to be used in case of
+     * asynchronous call. It is supposed to be created by the underlying
+     * infrastructure only when it was successful in allocating the asynchronous
+     * request id, hence caller should expect StatusCode to be successful.
+     *
+     * @param errorCode
+     *            The status code. If passed as null, code will be stored as
+     *            {@code StatusCode.UNDEFINED}
+     * @param requestId
+     *            The request id set by underlying infrastructure for this
+     *            request
+     */
+    public Status(StatusCode errorCode, long requestId) {
+        this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
+        this.description = (description != null) ? description : this.code
+                .toString();
+        this.requestId = requestId;
+    }
+
+    /**
+     * Returns the status code
+     *
+     * @return the {@code StatusCode} representing the status code
+     */
+    public StatusCode getCode() {
+        return code;
+    }
+
+    /**
+     * Returns a human readable description of the failure if any
+     *
+     * @return a string representing the reason of failure
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Tells whether the status is successful
+     *
+     * @return true if the Status code is {@code StatusCode.SUCCESS}
+     */
+    public boolean isSuccess() {
+        return code == StatusCode.SUCCESS || code == StatusCode.CREATED;
+    }
+
+    /**
+     * Return the request id assigned by underlying infrastructure in case of
+     * asynchronous request. In case of synchronous requests, the returned id
+     * is expected to be 0
+     *
+     * @return The request id assigned for this asynchronous request
+     */
+    public long getRequestId() {
+        return requestId;
+    }
+
+    @Override
+    public String toString() {
+        return code + ": " + description + " (" + requestId + ")";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((code == null) ? 0 : code.calculateConsistentHashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        Status other = (Status) obj;
+        if (code != other.code) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/StatusCode.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/StatusCode.java
new file mode 100644 (file)
index 0000000..24e21a1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.api;
+
+/**
+ * The enum which describes the generic error conditions.
+ * Each enum value is associated with a minimal description string.
+ *
+ */
+public enum StatusCode {
+    SUCCESS("Success"),
+    CREATED("Created"),
+
+    BADREQUEST("Bad Request"),
+    UNAUTHORIZED("UnAuthorized"),
+    FORBIDDEN("Forbidden"),
+    NOTFOUND("Not Found"),
+    NOTALLOWED("Method Not Allowed"),
+    NOTACCEPTABLE("Request Not Acceptable"),
+    TIMEOUT("Request Timeout"),
+    CONFLICT("Resource Conflict"),
+    GONE("Resource Gone"),
+    UNSUPPORTED("Unsupported"),
+
+    INTERNALERROR("Internal Error"),
+    NOTIMPLEMENTED("Not Implemented"),
+    NOSERVICE("Service Not Available"),
+
+    UNDEFINED("Undefined Error");
+
+    private String description;
+    private StatusCode(String description) {
+        this.description = description;
+    }
+
+    /**
+     * Prints the description associated to the code value
+     */
+    @Override
+    public String toString() {
+        return description;
+    }
+
+    public int calculateConsistentHashCode() {
+        if (this.description != null) {
+            return this.description.hashCode();
+        } else {
+            return 0;
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/TenantNetworkManager.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/TenantNetworkManager.java
new file mode 100644 (file)
index 0000000..08fa408
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * Open vSwitch isolates Tenant Networks using VLANs on the Integration Bridge
+ * This class manages the provisioning of these VLANs
+ *
+ * @author Dave Tucker
+ * @author Sam Hague (shague@redhat.com)
+ */
+public interface TenantNetworkManager {
+
+    /**
+     * Get the VLAN assigned to the provided Network
+     * @param node the {@link Node} to query
+     * @param networkId the Neutron Network ID
+     * @return the assigned VLAN ID or 0 in case of an error
+     */
+    int getInternalVlan(Node node, String networkId);
+
+    /**
+     * Reclaim the assigned VLAN for the given Network
+     * @param node the {@link Node} to query
+     * @param network the Neutron Network ID
+     */
+    void reclaimInternalVlan(Node node, NeutronNetwork network);
+
+    /**
+     * Configures the VLAN for a Tenant Network
+     * @param node the {@link Node} to configure
+     * @param tp the termination point
+     * @param network the Neutron Network ID
+     */
+    void programInternalVlan(Node node, OvsdbTerminationPointAugmentation tp, NeutronNetwork network);
+
+    /**
+     * Check is the given network is present on a Node
+     * @param node the {@link Node} to query
+     * @param segmentationId the Neutron Segementation ID
+     * @return True or False
+     */
+    boolean isTenantNetworkPresentInNode(Node node, String segmentationId);
+
+    /**
+     * Get the Neutron Network ID for a given Segmentation ID
+     * @param segmentationId segmentation id of the neutron network
+     * @return Neutron network id associated with the given segmentation id
+     */
+    String getNetworkId(String segmentationId);
+
+    /**
+     * Network Created Callback
+     * @param node target node
+     * @param networkId Id of neutron network
+     * @return vlan assigned to the network
+     */
+    int networkCreated(Node node, String networkId);
+
+    /**
+     * Network Deleted Callback
+     * @param id Id of the neutron network
+     */
+    void networkDeleted(String id);
+    NeutronNetwork getTenantNetwork(OvsdbTerminationPointAugmentation terminationPointAugmentation);
+    NeutronPort getTenantPort(OvsdbTerminationPointAugmentation terminationPointAugmentation);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/VlanConfigurationCache.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/VlanConfigurationCache.java
new file mode 100644 (file)
index 0000000..d3227a6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * This cache stores the VLAN assignments used for tenant separation within a vSwitch
+ * An assignment consists of a VLAN ID and a tenant network ID.
+ */
+public interface VlanConfigurationCache {
+
+    /**
+     * Assigns a free VLAN ID for the given tenant network
+     * @param node an Open vSwitch {@link Node}
+     * @param networkId the Neutron Network ID
+     * @return a VLAN ID or 0 in case of an error
+     */
+    Integer assignInternalVlan(Node node, String networkId);
+
+    /**
+     * Recovers an assigned VLAN ID when it is no longer required
+     * @param node an Open vSwitch {@link Node}
+     * @param networkId the Neutron Network ID
+     * @return the reclaimed VLAN ID or 0 in case of an error
+     */
+    Integer reclaimInternalVlan(Node node, String networkId);
+
+    /**
+     * Returns a VLAN ID assigned to a given tenant network
+     * @param node an Open vSwitch {@link Node}
+     * @param networkId the Neutron Network ID
+     * @return the VLAN ID or 0 in case of an error
+     */
+    Integer getInternalVlan(Node node, String networkId);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/BridgeConfigurationManagerImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/BridgeConfigurationManagerImpl.java
new file mode 100644 (file)
index 0000000..9252a46
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt.impl;
+
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.config.ConfigProperties;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeNetdev;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Madhu Venugopal
+ * @author Brent Salisbury
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile ConfigurationService configurationService;
+    private volatile NetworkingProviderManager networkingProviderManager;
+    private volatile Southbound southbound;
+
+    public void setConfigurationService(ConfigurationService configurationService) {
+        this.configurationService = configurationService;
+    }
+
+    public void setSouthbound(Southbound southbound) {
+        this.southbound = southbound;
+    }
+
+    @Override
+    public String getBridgeUuid(Node node, String bridgeName) {
+        return southbound.getBridgeUuid(node, bridgeName);
+    }
+
+    @Override
+    public boolean isNodeNeutronReady(Node node) {
+        Preconditions.checkNotNull(configurationService);
+        return southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null;
+    }
+
+    @Override
+    public boolean isNodeOverlayReady(Node node) {
+        Preconditions.checkNotNull(configurationService);
+        return isNodeNeutronReady(node)
+                && southbound.getBridge(node, configurationService.getNetworkBridgeName()) != null;
+    }
+
+    @Override
+    public boolean isPortOnBridge (Node bridgeNode, String portName) {
+        return southbound.extractTerminationPointAugmentation(bridgeNode, portName) != null;
+    }
+
+    @Override
+    public boolean isNodeTunnelReady(Node bridgeNode, Node ovsdbNode) {
+        Preconditions.checkNotNull(configurationService);
+        if (!southbound.isBridgeOnOvsdbNode(ovsdbNode, configurationService.getIntegrationBridgeName())) {
+            LOG.trace("isNodeTunnelReady: node: {}, {} missing",
+                    bridgeNode, configurationService.getIntegrationBridgeName());
+            return false;
+        }
+
+        return isNodeL3Ready(bridgeNode, ovsdbNode);
+    }
+
+    @Override
+    public boolean isNodeVlanReady(Node bridgeNode, Node ovsdbNode, NeutronNetwork network) {
+        Preconditions.checkNotNull(configurationService);
+
+        final String brInt = configurationService.getIntegrationBridgeName();
+        if (!southbound.isBridgeOnOvsdbNode(ovsdbNode, brInt)) {
+            LOG.trace("isNodeVlanReady: node: {}, {} missing", bridgeNode, brInt);
+            return false;
+        }
+
+        /* Check if physical device is added to br-int. */
+        String phyNetName = getPhysicalInterfaceName(ovsdbNode, network.getProviderPhysicalNetwork());
+        if (!isPortOnBridge(bridgeNode, phyNetName)) {
+            LOG.trace("isNodeVlanReady: node: {}, eth missing", bridgeNode);
+            return false;
+        }
+
+        return isNodeL3Ready(bridgeNode, ovsdbNode);
+    }
+
+    public boolean isNodeL3Ready(Node bridgeNode, Node ovsdbNode) {
+        Preconditions.checkNotNull(configurationService);
+        boolean ready = false;
+        if (configurationService.isL3ForwardingEnabled()) {
+            final String brInt = configurationService.getIntegrationBridgeName();
+            final String brExt = configurationService.getExternalBridgeName();
+            final String portNameInt = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brExt));
+            final String portNameExt = configurationService.getPatchPortName(new ImmutablePair<>(brExt, brInt));
+            Preconditions.checkNotNull(portNameInt);
+            Preconditions.checkNotNull(portNameExt);
+
+            if (southbound.isBridgeOnOvsdbNode(ovsdbNode, brExt)) {
+                ready = isNetworkPatchCreated(bridgeNode, southbound.readBridgeNode(ovsdbNode, brExt));
+            } else {
+                LOG.trace("isNodeL3Ready: node: {}, {} missing",
+                        bridgeNode, brExt);
+            }
+        } else {
+            ready = true;
+        }
+        return ready;
+    }
+
+    @Override
+    public void prepareNode(Node ovsdbNode) {
+        Preconditions.checkNotNull(configurationService);
+
+        try {
+            createIntegrationBridge(ovsdbNode);
+        } catch (Exception e) {
+            LOG.error("Error creating Integration Bridge on {}", ovsdbNode, e);
+            return;
+        }
+
+        try {
+            if (configurationService.isL3ForwardingEnabled()) {
+                createExternalBridge(ovsdbNode);
+            }
+        } catch (Exception e) {
+            LOG.error("Error creating External Bridge on {}", ovsdbNode, e);
+            return;
+        }
+        // this node is an ovsdb node so it doesn't have a bridge
+        // so either look up the bridges or just wait for the bridge update to come in
+        // and add the flows there.
+        //networkingProviderManager.getProvider(node).initializeFlowRules(node);
+    }
+
+    /**
+     * Check if the full network setup is available. If not, create it.
+     */
+    @Override
+    public boolean createLocalNetwork (Node bridgeNode, NeutronNetwork network) {
+        boolean isCreated = false;
+        Node ovsdbNode = southbound.readOvsdbNode(bridgeNode);
+        if (ovsdbNode == null) {
+            //this should never happen
+            LOG.error("createLocalNetwork could not find ovsdbNode from bridge node {}", bridgeNode);
+            return false;
+        }
+        if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            if (!isNodeVlanReady(bridgeNode, ovsdbNode, network)) {
+                try {
+                    isCreated = createBridges(bridgeNode, ovsdbNode, network);
+                } catch (Exception e) {
+                    LOG.error("Error creating internal vlan net network {}--{}", bridgeNode, network, e);
+                }
+            } else {
+                isCreated = true;
+            }
+        } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
+                   network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
+            if (!isNodeTunnelReady(bridgeNode, ovsdbNode)) {
+                try {
+                    isCreated = createBridges(bridgeNode, ovsdbNode, network);
+                } catch (Exception e) {
+                    LOG.error("Error creating internal vxlan/gre net network {}--{}", bridgeNode, network, e);
+                }
+            } else {
+                isCreated = true;
+            }
+        }
+        return isCreated;
+    }
+
+
+
+    @Override
+    public String getExternalInterfaceName (Node node, String extNetwork) {
+        String phyIf = null;
+        String providerMaps = southbound.getOtherConfig(node, OvsdbTables.OPENVSWITCH,
+                configurationService.getProviderMappingsKey());
+        if (providerMaps != null) {
+            for (String map : providerMaps.split(",")) {
+                String[] pair = map.split(":");
+                if (pair[0].equals(extNetwork)) {
+                    phyIf = pair[1];
+                    break;
+                }
+            }
+        }
+        if (phyIf == null) {
+            LOG.error("External interface not found for Node: {}, Network {}",
+                    node, extNetwork);
+        }
+        else {
+            LOG.info("External interface found for Node: {}, Network {} is {}",node,extNetwork,phyIf);
+        }
+        return phyIf;
+    }
+
+
+
+    @Override
+    public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
+        String phyIf = null;
+        String providerMaps = southbound.getOtherConfig(node, OvsdbTables.OPENVSWITCH,
+                configurationService.getProviderMappingsKey());
+        if (providerMaps == null) {
+            providerMaps = configurationService.getDefaultProviderMapping();
+        }
+
+        if (providerMaps != null) {
+            for (String map : providerMaps.split(",")) {
+                String[] pair = map.split(":");
+                if (pair[0].equals(physicalNetwork)) {
+                    phyIf = pair[1];
+                    break;
+                }
+            }
+        }
+
+        if (phyIf == null) {
+            LOG.error("Physical interface not found for Node: {}, Network {}",
+                    node, physicalNetwork);
+        }
+
+        return phyIf;
+    }
+
+    @Override
+    public List<String> getAllPhysicalInterfaceNames(Node node) {
+        List<String> phyIfName = Lists.newArrayList();
+        String providerMaps = southbound.getOtherConfig(node, OvsdbTables.OPENVSWITCH,
+                configurationService.getProviderMappingsKey());
+        if (providerMaps == null) {
+            providerMaps = configurationService.getDefaultProviderMapping();
+        }
+
+        if (providerMaps != null) {
+            for (String map : providerMaps.split(",")) {
+                String[] pair = map.split(":");
+                phyIfName.add(pair[1]);
+            }
+        }
+
+        return phyIfName;
+    }
+
+    /**
+     * Returns true if a patch port exists between the Integration Bridge and Network Bridge
+     */
+    private boolean isNetworkPatchCreated(Node intBridge, Node netBridge) {
+        Preconditions.checkNotNull(configurationService);
+
+        boolean isPatchCreated = false;
+
+        String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
+        if (isPortOnBridge(intBridge, portName)) {
+            portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
+            if (isPortOnBridge(netBridge, portName)) {
+                isPatchCreated = true;
+            }
+        }
+
+        return isPatchCreated;
+    }
+
+    /**
+     * Creates the Integration Bridge
+     */
+    private boolean createIntegrationBridge(Node ovsdbNode) {
+        Preconditions.checkNotNull(configurationService);
+
+        if (!addBridge(ovsdbNode, configurationService.getIntegrationBridgeName())) {
+            LOG.debug("Integration Bridge Creation failed");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean createExternalBridge(Node ovsdbNode) {
+        Preconditions.checkNotNull(configurationService);
+
+        if (!addBridge(ovsdbNode, configurationService.getExternalBridgeName())) {
+            LOG.debug("External Bridge Creation failed");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Create and configure bridges for all network types and OpenFlow versions.
+     *
+       OF 1.0 vlan:
+       Bridge br-int
+            Port patch-net
+                Interface patch-net
+                    type: patch
+                    options: {peer=patch-int}
+            Port br-int
+                Interface br-int
+                    type: internal
+       Bridge br-net
+            Port "eth1"
+                Interface "eth1"
+            Port patch-int
+                Interface patch-int
+                    type: patch
+                    options: {peer=patch-net}
+            Port br-net
+                Interface br-net
+                    type: internal
+
+       OF 1.0 tunnel:
+       Bridge br-int
+            Port patch-net
+                Interface patch-net
+                    type: patch
+                    options: {peer=patch-int}
+            Port br-int
+                Interface br-int
+                    type: internal
+       Bridge "br-net"
+            Port patch-int
+                Interface patch-int
+                    type: patch
+                    options: {peer=patch-net}
+            Port br-net
+                Interface br-net
+                    type: internal
+
+       OF 1.3 vlan:
+       Bridge br-int
+            Port "eth1"
+                Interface "eth1"
+            Port br-int
+                Interface br-int
+                    type: internal
+
+       OF 1.3 tunnel:
+       Bridge br-int
+            Port br-int
+                Interface br-int
+                    type: internal
+     */
+    private boolean createBridges(Node bridgeNode, Node ovsdbNode, NeutronNetwork network) {
+        Preconditions.checkNotNull(configurationService);
+        Preconditions.checkNotNull(networkingProviderManager);
+
+        LOG.debug("createBridges: node: {}, network type: {}", bridgeNode, network.getProviderNetworkType());
+
+        final String brInt = configurationService.getIntegrationBridgeName();
+        if (! createIntegrationBridge(ovsdbNode)) {
+            LOG.debug("{} Bridge creation failed", brInt);
+            return false;
+        }
+
+        if (configurationService.isL3ForwardingEnabled()) {
+            final String brExt = configurationService.getExternalBridgeName();
+            if (! createExternalBridge(ovsdbNode)) {
+                LOG.error("{} Bridge creation failed", brExt);
+                return false;
+            }
+
+            //get two patch port names
+            final String portNameInt = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brExt));
+            final String portNameExt = configurationService.getPatchPortName(new ImmutablePair<>(brExt, brInt));
+            Preconditions.checkNotNull(portNameInt);
+            Preconditions.checkNotNull(portNameExt);
+
+            if (!addPatchPort(bridgeNode, brInt, portNameInt, portNameExt)) {
+                LOG.error("Add Port {} to Bridge {} failed", portNameInt, brInt);
+                return false;
+            }
+            Node extBridgeNode = southbound.readBridgeNode(ovsdbNode, brExt);
+            Preconditions.checkNotNull(extBridgeNode);
+            if (!addPatchPort(extBridgeNode, brExt, portNameExt, portNameInt)) {
+                LOG.error("Add Port {} to Bridge {} failed", portNameExt, brExt);
+                return false;
+            }
+            String extNetName = getExternalInterfaceName(extBridgeNode, brExt);
+            if ( extNetName != null) {
+                if (!addPortToBridge(extBridgeNode, brExt, extNetName)) {
+                    LOG.error("Add External Port {} to Bridge {} failed", extNetName, brExt);
+                    return false;
+                }
+            LOG.info("Add External Port {} to Ext Bridge {} success", extNetName, brExt);
+            }
+        }
+        /* For vlan network types add physical port to br-int. */
+        if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            String phyNetName = this.getPhysicalInterfaceName(bridgeNode, network.getProviderPhysicalNetwork());
+            if (!addPortToBridge(bridgeNode, brInt, phyNetName)) {
+                LOG.debug("Add Port {} to Bridge {} failed", phyNetName, brInt);
+                return false;
+            }
+        }
+
+        LOG.info("createBridges: node: {}, status: success", bridgeNode);
+        return true;
+    }
+
+    /**
+     * Add a Port to a Bridge
+     */
+    private boolean addPortToBridge (Node node, String bridgeName, String portName) {
+        boolean rv = true;
+
+        if (southbound.extractTerminationPointAugmentation(node, portName) == null) {
+            rv = southbound.addTerminationPoint(node, bridgeName, portName, null);
+
+            if (rv) {
+                LOG.info("addPortToBridge: node: {}, bridge: {}, portname: {} status: success",
+                        node.getNodeId().getValue(), bridgeName, portName);
+            } else {
+                LOG.error("addPortToBridge: node: {}, bridge: {}, portname: {} status: FAILED",
+                        node.getNodeId().getValue(), bridgeName, portName);
+            }
+        } else {
+            LOG.trace("addPortToBridge: node: {}, bridge: {}, portname: {} status: not_needed",
+                    node.getNodeId().getValue(), bridgeName, portName);
+        }
+
+        return rv;
+    }
+
+    /**
+     * Add a Patch Port to a Bridge
+     */
+    private boolean addPatchPort (Node node, String bridgeName, String portName, String peerPortName) {
+        boolean rv = true;
+
+        if (southbound.extractTerminationPointAugmentation(node, portName) == null) {
+            rv = southbound.addPatchTerminationPoint(node, bridgeName, portName, peerPortName);
+
+            if (rv) {
+                LOG.info("addPatchPort: node: {}, bridge: {}, portname: {} peer: {} status: success",
+                        node.getNodeId().getValue(), bridgeName, portName, peerPortName);
+            } else {
+                LOG.error("addPatchPort: node: {}, bridge: {}, portname: {} peer: {} status: FAILED",
+                        node.getNodeId().getValue(), bridgeName, portName, peerPortName);
+            }
+        } else {
+            LOG.trace("addPatchPort: node: {}, bridge: {}, portname: {} peer: {} status: not_needed",
+                    node.getNodeId().getValue(), bridgeName, portName, peerPortName);
+        }
+
+        return rv;
+    }
+
+    /**
+     * Add Bridge to a Node
+     */
+    private boolean addBridge(Node ovsdbNode, String bridgeName) {
+        boolean rv = true;
+        if ((!southbound.isBridgeOnOvsdbNode(ovsdbNode, bridgeName)) ||
+                (southbound.getBridgeFromConfig(ovsdbNode, bridgeName) == null)) {
+            Class<? extends DatapathTypeBase> dpType = null;
+            if (configurationService.isUserSpaceEnabled()) {
+                dpType = DatapathTypeNetdev.class;
+            }
+            rv = southbound.addBridge(ovsdbNode, bridgeName, getControllersFromOvsdbNode(ovsdbNode), dpType);
+        }
+        return rv;
+    }
+
+    private String getControllerIPAddress() {
+        String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address");
+        if (addressString != null) {
+            try {
+                if (InetAddress.getByName(addressString) != null) {
+                    return addressString;
+                }
+            } catch (UnknownHostException e) {
+                LOG.error("Host {} is invalid", addressString, e);
+            }
+        }
+
+        addressString = ConfigProperties.getProperty(this.getClass(), "of.address");
+        if (addressString != null) {
+            try {
+                if (InetAddress.getByName(addressString) != null) {
+                    return addressString;
+                }
+            } catch (UnknownHostException e) {
+                LOG.error("Host {} is invalid", addressString, e);
+            }
+        }
+
+        return null;
+    }
+
+    private short getControllerOFPort() {
+        short openFlowPort = Constants.OPENFLOW_PORT;
+        String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort");
+        if (portString != null) {
+            try {
+                openFlowPort = Short.parseShort(portString);
+            } catch (NumberFormatException e) {
+                LOG.warn("Invalid port:{}, use default({})", portString,
+                        openFlowPort, e);
+            }
+        }
+        return openFlowPort;
+    }
+
+    public List<String> getControllersFromOvsdbNode(Node node) {
+        List<String> controllersStr = new ArrayList<>();
+
+        String controllerIpStr = getControllerIPAddress();
+        if (controllerIpStr != null) {
+            // If codepath makes it here, the ip address to be used was explicitly provided.
+            // Being so, also fetch openflowPort provided via ConfigProperties.
+            controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
+                    + ":" + controllerIpStr + ":" + getControllerOFPort());
+        } else {
+            // Check if ovsdb node has manager entries
+            OvsdbNodeAugmentation ovsdbNodeAugmentation = southbound.extractOvsdbNode(node);
+            if (ovsdbNodeAugmentation != null) {
+                List<ManagerEntry> managerEntries = ovsdbNodeAugmentation.getManagerEntry();
+                if (managerEntries != null && !managerEntries.isEmpty()) {
+                    for (ManagerEntry managerEntry : managerEntries) {
+                        if (managerEntry == null || managerEntry.getTarget() == null) {
+                            continue;
+                        }
+                        String[] tokens = managerEntry.getTarget().getValue().split(":");
+                        if (tokens.length == 3 && tokens[0].equalsIgnoreCase("tcp")) {
+                            controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
+                                    + ":" + tokens[1] + ":" + getControllerOFPort());
+                        } else if (tokens[0].equalsIgnoreCase("ptcp")) {
+                            ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
+                            if (connectionInfo != null && connectionInfo.getLocalIp() != null) {
+                                controllerIpStr = String.valueOf(connectionInfo.getLocalIp().getValue());
+                                controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
+                                        + ":" + controllerIpStr + ":" + Constants.OPENFLOW_PORT);
+                            } else {
+                                LOG.warn("Ovsdb Node does not contain connection info: {}", node);
+                            }
+                        } else {
+                            LOG.trace("Skipping manager entry {} for node {}",
+                                    managerEntry.getTarget(), node.getNodeId().getValue());
+                        }
+                    }
+                } else {
+                    LOG.warn("Ovsdb Node does not contain manager entries : {}", node);
+                }
+            }
+        }
+
+        if (controllersStr.isEmpty()) {
+            // Neither user provided ip nor ovsdb node has manager entries. Lets use local machine ip address.
+            LOG.debug("Use local machine ip address as a OpenFlow Controller ip address");
+            controllerIpStr = getLocalControllerHostIpAddress();
+            if (controllerIpStr != null) {
+                controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
+                        + ":" + controllerIpStr + ":" + Constants.OPENFLOW_PORT);
+            }
+        }
+
+        if (controllersStr.isEmpty()) {
+            LOG.warn("Failed to determine OpenFlow controller ip address");
+        } else if (LOG.isDebugEnabled()) {
+            controllerIpStr = "";
+            for (String currControllerIpStr : controllersStr) {
+                controllerIpStr += " " + currControllerIpStr;
+            }
+            LOG.debug("Found {} OpenFlow Controller(s) :{}", controllersStr.size(), controllerIpStr);
+        }
+
+        return controllersStr;
+    }
+
+    private String getLocalControllerHostIpAddress() {
+        String ipaddress = null;
+        try{
+            for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();ifaces.hasMoreElements();){
+                NetworkInterface iface = ifaces.nextElement();
+
+                for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
+                    InetAddress inetAddr = inetAddrs.nextElement();
+                    if (!inetAddr.isLoopbackAddress() && inetAddr.isSiteLocalAddress()) {
+                        ipaddress = inetAddr.getHostAddress();
+                        break;
+                    }
+                }
+            }
+        }catch (Exception e){
+            LOG.warn("Exception while fetching local host ip address ", e);
+        }
+        return ipaddress;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        networkingProviderManager =
+                (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/ConfigurationServiceImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/ConfigurationServiceImpl.java
new file mode 100644 (file)
index 0000000..36c9e8d
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt.impl;
+
+import com.google.common.collect.Maps;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.config.ConfigProperties;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigurationServiceImpl implements ConfigurationService, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationServiceImpl.class);
+
+    private String integrationBridgeName;
+    private String networkBridgeName;
+    private String externalBridgeName;
+    private String tunnelEndpointKey;
+
+    private Map<Pair<String, String>, String> patchPortNames = Maps.newHashMap();
+    private String providerMappingsKey;
+    private String providerMapping;
+    private Southbound southbound;
+
+    public ConfigurationServiceImpl() {
+        tunnelEndpointKey = Constants.TUNNEL_ENDPOINT_KEY;
+        integrationBridgeName = Constants.INTEGRATION_BRIDGE;
+        networkBridgeName = Constants.NETWORK_BRIDGE;
+        externalBridgeName = Constants.EXTERNAL_BRIDGE;
+        patchPortNames.put(new ImmutablePair<>(integrationBridgeName, networkBridgeName),
+                           Constants.PATCH_PORT_TO_NETWORK_BRIDGE_NAME);
+        patchPortNames.put(new ImmutablePair<>(networkBridgeName, integrationBridgeName),
+                           Constants.PATCH_PORT_TO_INTEGRATION_BRIDGE_NAME);
+        patchPortNames.put(new ImmutablePair<>(integrationBridgeName, externalBridgeName),
+                           Constants.PATCH_PORT_TO_EXTERNAL_BRIDGE_NAME);
+        patchPortNames.put(new ImmutablePair<>(externalBridgeName, integrationBridgeName),
+                           Constants.PATCH_PORT_TO_INTEGRATION_BRIDGE_NAME);
+        providerMappingsKey = Constants.PROVIDER_MAPPINGS_KEY;
+        providerMapping = Constants.PROVIDER_MAPPING;
+    }
+
+    @Override
+    public String getIntegrationBridgeName() {
+        return integrationBridgeName;
+    }
+
+    @Override
+    public void setIntegrationBridgeName(String integrationBridgeName) {
+        this.integrationBridgeName = integrationBridgeName;
+    }
+
+    @Override
+    public String getNetworkBridgeName() {
+        return networkBridgeName;
+    }
+
+    @Override
+    public void setNetworkBridgeName(String networkBridgeName) {
+        this.networkBridgeName = networkBridgeName;
+    }
+
+    @Override
+    public String getExternalBridgeName() {
+        return externalBridgeName;
+    }
+
+    @Override
+    public void setExternalBridgeName(String externalBridgeName) {
+        this.externalBridgeName = externalBridgeName;
+    }
+
+    @Override
+    public String getTunnelEndpointKey() {
+        return tunnelEndpointKey;
+    }
+
+    @Override
+    public void setTunnelEndpointKey(String tunnelEndpointKey) {
+        this.tunnelEndpointKey = tunnelEndpointKey;
+    }
+
+    @Override
+    public String getProviderMappingsKey() {
+        return providerMappingsKey;
+    }
+
+    @Override
+    public void setProviderMappingsKey(String providerMappingsKey) {
+        this.providerMappingsKey = providerMappingsKey;
+    }
+
+    @Override
+    public Map<Pair<String, String>, String> getPatchPortNames() {
+        return patchPortNames;
+    }
+
+    @Override
+    public void setPatchPortNames(Map<Pair<String, String>, String> patchPortNames) {
+        this.patchPortNames = patchPortNames;
+    }
+
+    @Override
+    public String getPatchPortName(Pair portTuple){
+        return this.patchPortNames.get(portTuple);
+    }
+
+    @Override
+    public String getDefaultProviderMapping() {
+        return providerMapping;
+    }
+
+    @Override
+    public void setDefaultProviderMapping(String providerMapping) {
+        this.providerMapping = providerMapping;
+    }
+
+    @Override
+    public InetAddress getTunnelEndPoint(Node node) {
+        InetAddress address = null;
+        String tunnelEndpoint = southbound.getOtherConfig(node, OvsdbTables.OPENVSWITCH, tunnelEndpointKey);
+        if (tunnelEndpoint != null) {
+            try {
+                address = InetAddress.getByName(tunnelEndpoint);
+                LOG.debug("Tunnel Endpoint for Node {} {}", node, address.getHostAddress());
+            } catch (UnknownHostException e) {
+                LOG.error("Error populating Tunnel Endpoint for Node {} ", node, e);
+            }
+        }
+        return address;
+    }
+
+    @Override
+    public String getOpenflowVersion(Node node) {
+        return Constants.OPENFLOW13;
+    }
+
+    @Override
+    public boolean isL3ForwardingEnabled() {
+        final String enabledPropertyStr = ConfigProperties.getProperty(this.getClass(), "ovsdb.l3.fwd.enabled");
+        return enabledPropertyStr != null && enabledPropertyStr.equalsIgnoreCase("yes");
+    }
+
+    @Override
+    public boolean isDistributedArpDisabled() {
+        final String strARPDisabled = ConfigProperties.getProperty(this.getClass(), "ovsdb.l3.arp.responder.disabled");
+        return strARPDisabled != null && strARPDisabled.equalsIgnoreCase("yes");
+    }
+
+    @Override
+    public String getDefaultGatewayMacAddress(Node node) {
+        String l3gatewayForNode = null;
+        if (node != null) {
+            l3gatewayForNode = ConfigProperties.getProperty(this.getClass(),
+                    "ovsdb.l3gateway.mac." + node.getNodeId().getValue());
+        }
+        if (l3gatewayForNode == null) {
+            l3gatewayForNode = ConfigProperties.getProperty(this.getClass(), "ovsdb.l3gateway.mac");
+        }
+        return l3gatewayForNode;
+    }
+
+    @Override
+    public boolean isUserSpaceEnabled() {
+        final String enabledPropertyStr = ConfigProperties.getProperty(this.getClass(), "ovsdb.userspace.enabled");
+        return enabledPropertyStr != null && enabledPropertyStr.equalsIgnoreCase("yes");
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpService.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpService.java
new file mode 100644 (file)
index 0000000..91b07a5
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2016 NEC Corporation 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.openstack.netvirt.impl;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.List;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ARP flows programmed for Neutron port.
+ */
+public class DistributedArpService implements ConfigInterface {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DistributedArpService.class);
+    private static final String DHCP_DEVICE_OWNER = "network:dhcp";
+    private static final String ROUTER_INTERFACE_DEVICE_OWNER = "network:router_interface";
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile ConfigurationService configurationService;
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile ArpProvider arpProvider;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+
+    private Southbound southbound;
+    private Boolean flgDistributedARPEnabled = true;
+
+    private HashMap<String, List<Neutron_IPs>> dhcpPortIpCache = new HashMap();
+
+    private void initMembers() {
+        Preconditions.checkNotNull(configurationService);
+        if (configurationService.isDistributedArpDisabled()) {
+            this.flgDistributedARPEnabled = false;
+            LOG.debug("Distributed ARP responder is disabled");
+        } else {
+            LOG.debug("Distributed ARP responder is enabled");
+        }
+    }
+
+     /**
+     * Process the port event to write Arp rules for neutron ports.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param neutronPort An instance of NeutronPort object.
+     */
+    public void handlePortEvent(NeutronPort neutronPort, Action action) {
+        LOG.debug("neutronPort Event {} action event {} ", neutronPort, action);
+        if (action == Action.DELETE) {
+            this.handleNeutronPortForArp(neutronPort, action);
+        } else {
+            for (NeutronPort neutronPort1 : neutronPortCache.getAllPorts()) {
+               this.handleNeutronPortForArp(neutronPort1, action);
+            }
+        }
+    }
+
+     /**
+     * Arp rules are added/removed based on neutron port event
+     *
+     */
+    boolean programStaticRuleStage1(Long dpid, String segOrOfPort,
+                                           String macAddress, String ipStr,
+                                           Action action) {
+        if (action == Action.DELETE ) {
+            LOG.trace("Deleting Flow : programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {}",
+                         dpid, segOrOfPort, macAddress, ipStr, action);
+        }
+        if (action == Action.ADD) {
+            LOG.trace("Adding Flow : programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {}",
+                         dpid, segOrOfPort, macAddress, ipStr, action);
+        }
+
+        Status status = this.programStaticRuleStage2(dpid, segOrOfPort, macAddress, ipStr, action);
+        return status.isSuccess();
+    }
+
+     /**
+     * Arp rules are programmed by invoke arpProvider
+     *
+     */
+    private Status programStaticRuleStage2(Long dpid,
+                                          String segOrOfPort,
+                                          String macAddress,
+                                          String address,
+                                          Action action) {
+        Status status;
+        try {
+            InetAddress inetAddress = InetAddress.getByName(address);
+            status = arpProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     arpProvider.programStaticArpEntry(dpid, segOrOfPort,
+                                                       macAddress, inetAddress, action);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            LOG.debug("programStaticRuleStage2 {} for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{}",
+                         arpProvider == null ? "skipped" : "programmed",
+                         macAddress, address, dpid, segOrOfPort, action);
+        } else {
+            LOG.error("programStaticRuleStage2 failed for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{} status:{}",
+                         macAddress, address, dpid, segOrOfPort, action, status);
+        }
+        return status;
+    }
+
+    /**
+     * Write Arp rules based on event for neutron port.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param neutronPort An instance of NeutronPort object.
+     */
+    private void handleNeutronPortForArp(NeutronPort neutronPort, Action action) {
+        if (!flgDistributedARPEnabled) {
+            return;
+        }
+
+        //treat UPDATE as ADD
+        final Action actionToPerform = action == Action.DELETE ? Action.DELETE : Action.ADD;
+
+        final String networkUUID = neutronPort.getNetworkUUID();
+        NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
+        if (null == neutronNetwork) {
+            neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(networkUUID);
+        }
+        final String providerSegmentationId = neutronNetwork != null ?
+                                              neutronNetwork.getProviderSegmentationID() : null;
+        final String macAddress = neutronPort.getMacAddress();
+        if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+            macAddress == null || macAddress.isEmpty()) {
+            // done: go no further w/out all the info needed...
+            return;
+        }
+
+        List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (nodes.isEmpty()) {
+            LOG.trace("updateL3ForNeutronPort has no nodes to work with");
+            //Do not exit, we still may need to clean up this entry from the dhcpPortToIpCache
+        }
+
+        //Neutron removes the DHCP port's IP before deleting it. As such,
+        //when it comes time to delete the port, the ARP rule can not
+        //be removed because we simply don't know the IP. To mitigate this,
+        //we cache the dhcp ports IPs (BUG 5408).
+        String owner = neutronPort.getDeviceOwner();
+        boolean isDhcpPort = owner != null && owner.equals(DHCP_DEVICE_OWNER);
+        List<Neutron_IPs> fixedIps = neutronPort.getFixedIPs();
+        if((null == fixedIps || fixedIps.isEmpty())
+                        && actionToPerform == Action.DELETE && isDhcpPort){
+            fixedIps = dhcpPortIpCache.get(neutronPort.getPortUUID());
+            if(fixedIps == null) {
+                return;
+            }
+        }
+
+        List<Neutron_IPs> network_Ips = neutronPort.getFixedIPs();
+        for (Node node : nodes) {
+            // Arp rule is only needed when segmentation exists in the given node (bug 4752)
+            // or in case the port is a router interface
+            boolean isRouterInterface = owner != null && owner.equals(ROUTER_INTERFACE_DEVICE_OWNER);
+            boolean arpNeeded = isRouterInterface ||
+                    tenantNetworkManager.isTenantNetworkPresentInNode(node, providerSegmentationId);
+            final Action actionForNode = arpNeeded ? actionToPerform : Action.DELETE;
+            final Long dpid = getDatapathIdIntegrationBridge(node);
+            if (dpid == null) {
+                continue;
+            }
+
+            for (Neutron_IPs neutronIP : fixedIps) {
+                final String ipAddress = neutronIP.getIpAddress();
+                if (ipAddress.isEmpty()) {
+                    continue;
+                }
+
+                // Arp rules for dhcp port should be removed from compute node
+                // when delete the last VM instance belongs to the network (bug 5456)
+                if (false == arpNeeded && Action.DELETE == actionForNode && null != network_Ips && !network_Ips.isEmpty()) {
+                    for (NeutronPort port : neutronPortCache.getAllPorts()) {
+                         if (!port.getDeviceOwner().equalsIgnoreCase(ROUTER_INTERFACE_DEVICE_OWNER)) {
+                             final String portMacAddress = port.getMacAddress();
+                             if ( null == portMacAddress || portMacAddress.isEmpty()) {
+                                continue;
+                             }
+                             for (Neutron_IPs neutronIPAddr : port.getFixedIPs()) {
+                                 final String portIPAddress = neutronIPAddr.getIpAddress();
+                                 if (null == portIPAddress || portIPAddress.isEmpty()) {
+                                     continue;
+                                 }
+                             programStaticRuleStage1(dpid, providerSegmentationId, portMacAddress, portIPAddress, Action.DELETE);
+                             }
+                          }
+                    }
+                 } else {
+                     programStaticRuleStage1(dpid, providerSegmentationId, macAddress, ipAddress, actionForNode);
+              }
+              }
+          }
+
+        //use action instead of actionToPerform - only write to the cache when the port is created
+        if(isDhcpPort && action == Action.ADD){
+            dhcpPortIpCache.put(neutronPort.getPortUUID(), fixedIps);
+        } else if (isDhcpPort && action == Action.DELETE) {
+            dhcpPortIpCache.remove(neutronPort.getPortUUID());
+        }
+    }
+
+    /**
+     * Check if node is integration bridge, then return its datapathID.
+     * @param node An instance of Node object.
+     */
+    private Long getDatapathIdIntegrationBridge(Node node) {
+        if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
+            return southbound.getDataPathId(node);
+        }
+        return null;
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param bridgeNode An instance of Node object.
+     * @param intf An {@link org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+     * .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
+     * @param neutronNetwork An {@link NeutronNetwork} instance of NeutronNetwork
+     * object.
+     * @param action the {@link Action} action to be handled.
+     */
+    public void processInterfaceEvent(final Node bridgeNode, final OvsdbTerminationPointAugmentation intf,
+                                     final NeutronNetwork neutronNetwork, Action action) {
+        LOG.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
+                     action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork);
+        final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+        if (neutronPort != null) {
+            this.handlePortEvent(neutronPort, action);
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        arpProvider =
+                (ArpProvider) ServiceHelper.getGlobalInstance(ArpProvider.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        initMembers();
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        } else if (impl instanceof ArpProvider) {
+            arpProvider = (ArpProvider)impl;
+        }
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/EventDispatcherImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/EventDispatcherImpl.java
new file mode 100644 (file)
index 0000000..132dfd9
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt.impl;
+
+import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class EventDispatcherImpl implements EventDispatcher, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(EventDispatcher.class);
+    private ExecutorService eventHandler;
+    private volatile BlockingQueue<AbstractEvent> events;
+    private AbstractHandler[] handlers;
+
+    public EventDispatcherImpl() {
+        events = new LinkedBlockingQueue<>();
+        handlers = new AbstractHandler[AbstractEvent.HandlerType.size];
+        eventHandler = Executors.newSingleThreadExecutor();
+        start();
+    }
+
+    void start() {
+        eventHandler.submit(new Runnable()  {
+            @Override
+            public void run() {
+                Thread t = Thread.currentThread();
+                t.setName("EventDispatcherImpl");
+                LOG.info("EventDispatcherImpl: started {}", t.getName());
+                while (true) {
+                    AbstractEvent ev;
+                    try {
+                        ev = events.take();
+                    } catch (InterruptedException e) {
+                        LOG.info("The event handler thread was interrupted, shutting down", e);
+                        return;
+                    }
+                    try {
+                        dispatchEvent(ev);
+                    } catch (Exception e) {
+                        LOG.error("Exception in dispatching event {}", ev.toString(), e);
+                    }
+                }
+            }
+        });
+        LOG.debug("event dispatcher is started");
+    }
+
+    void stop() {
+        // stop accepting new tasks
+        eventHandler.shutdown();
+        try {
+            // Wait a while for existing tasks to terminate
+            if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS)) {
+                eventHandler.shutdownNow();
+                // Wait a while for tasks to respond to being cancelled
+                if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS)) {
+                    LOG.error("Dispatcher's event handler did not terminate");
+                }
+            }
+        } catch (InterruptedException e) {
+            // (Re-)Cancel if current thread also interrupted
+            eventHandler.shutdownNow();
+            // Preserve interrupt status
+            Thread.currentThread().interrupt();
+        }
+        LOG.debug("event dispatcher is stopped");
+    }
+
+    private void dispatchEvent(AbstractEvent ev) {
+        LOG.trace("dispatchEvent: Processing (id={}): {}", ev.getTransactionId(), ev);
+        AbstractHandler handler = handlers[ev.getHandlerType().ordinal()];
+        if (handler == null) {
+            LOG.warn("event dispatcher found no handler for {}", ev);
+            return;
+        }
+
+        handler.processEvent(ev);
+        LOG.trace("dispatchEvent: Done processing (id={}): {}", ev.getTransactionId(), ev);
+    }
+
+    public void eventHandlerAdded(final ServiceReference ref, AbstractHandler handler){
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        Object handlerTypeObject = ref.getProperty(Constants.EVENT_HANDLER_TYPE_PROPERTY);
+        if (!(handlerTypeObject instanceof AbstractEvent.HandlerType)){
+            // The exception should give us a stacktrace
+            LOG.error("Abstract handler reg failed to provide a valid handler type: {} ref: {} handler: {}",
+                    handlerTypeObject, ref.getClass().getName(), handler.getClass().getName(),
+                    new IllegalArgumentException("Missing handler type"));
+            return;
+        }
+        AbstractEvent.HandlerType handlerType = (AbstractEvent.HandlerType) handlerTypeObject;
+        handlers[handlerType.ordinal()] = handler;
+        LOG.info("eventHandlerAdded: handler: {}, pid: {}, type: {}",
+                handler.getClass().getName(), pid, handlerType);
+    }
+
+    public void eventHandlerRemoved(final ServiceReference ref){
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        Object handlerTypeObject = ref.getProperty(Constants.EVENT_HANDLER_TYPE_PROPERTY);
+        if (!(handlerTypeObject instanceof AbstractEvent.HandlerType)){
+            LOG.error("Abstract handler unreg failed to provide a valid handler type {}", handlerTypeObject);
+            return;
+        }
+        AbstractEvent.HandlerType handlerType = (AbstractEvent.HandlerType) handlerTypeObject;
+        handlers[handlerType.ordinal()] = null;
+        LOG.debug("Event handler for type {} unregistered pid {}", handlerType, pid);
+    }
+
+    /**
+     * Enqueue the event.
+     *
+     * @param event the {@link AbstractEvent} event to be handled.
+     */
+    @Override
+    public void enqueueEvent(AbstractEvent event) {
+        if (event == null) {
+            LOG.warn("enqueueEvent: event is null");
+            return;
+        }
+
+        try {
+            events.put(event);
+        } catch (InterruptedException e) {
+            LOG.error("Thread was interrupted while trying to enqueue event ", e);
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {}
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/HostConfigService.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/HostConfigService.java
new file mode 100644 (file)
index 0000000..171abd0
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.impl;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.ClusterAwareMdsalUtils;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.Hostconfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.HostconfigBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+
+public class HostConfigService implements OvsdbInventoryListener, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(HostConfigService.class);
+
+    private static final String OS_HOST_CONFIG_HOST_ID_KEY = "odl_os_hostconfig_hostid";
+    private static final String OS_HOST_CONFIG_HOST_TYPE_KEY = "odl_os_hostconfig_hosttype";
+    private static final String OS_HOST_CONFIG_CONFIG_KEY = "odl_os_hostconfig_config";
+
+    private final DataBroker databroker;
+    private final ClusterAwareMdsalUtils mdsalUtils;
+    private volatile OvsdbInventoryService ovsdbInventoryService;
+    private volatile Southbound southbound;
+
+    public HostConfigService(DataBroker dataBroker) {
+        this.databroker = dataBroker;
+        mdsalUtils = new ClusterAwareMdsalUtils(dataBroker);
+    }
+
+    @Override
+    public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
+        boolean result;
+        Hostconfig hostConfig;
+        InstanceIdentifier<Hostconfig> hostConfigId;
+
+        if (ovsdbType != OvsdbType.NODE) {
+            return;
+        }
+        hostConfig = buildHostConfigInfo(node);
+        if (hostConfig == null) {
+              return;
+        }
+        LOG.trace("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
+        switch (action) {
+            case ADD:
+            case UPDATE:
+                    hostConfigId = createInstanceIdentifier(hostConfig);
+                    result = mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, hostConfigId, hostConfig);
+                    LOG.trace("Add Node: result: {}", result);
+                break;
+            case DELETE:
+                    hostConfigId = createInstanceIdentifier(hostConfig);
+                    result = mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, hostConfigId);
+                    LOG.trace("Delete Node: result: {}", result);
+                break;
+        }
+    }
+
+    @Override
+    public void triggerUpdates() {
+        List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
+        for (Node node : ovsdbNodes) {
+            ovsdbUpdate(node, node.getAugmentation(OvsdbNodeAugmentation.class),
+                    OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
+        }
+    }
+
+    private Hostconfig buildHostConfigInfo(Node node) {
+        HostconfigBuilder hostconfigBuilder = new HostconfigBuilder();
+        String value;
+
+        value = southbound.getExternalId(node, OvsdbTables.OPENVSWITCH, OS_HOST_CONFIG_HOST_ID_KEY);
+        if (value == null){
+            return null;
+        }
+        hostconfigBuilder.setHostId(value);
+        value = southbound.getExternalId(node, OvsdbTables.OPENVSWITCH, OS_HOST_CONFIG_HOST_TYPE_KEY);
+        if (value == null) {
+            return null;
+        }
+        hostconfigBuilder.setHostType(value);
+        value = southbound.getExternalId(node, OvsdbTables.OPENVSWITCH, OS_HOST_CONFIG_CONFIG_KEY);
+        if (value == null) {
+            return null;
+        }
+        hostconfigBuilder.setConfig(value);
+        return hostconfigBuilder.build();
+    }
+
+    private InstanceIdentifier<Hostconfig> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Hostconfigs.class)
+                .child(Hostconfig.class);
+    }
+
+    private InstanceIdentifier<Hostconfig> createInstanceIdentifier(Hostconfig hostconfig) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Hostconfigs.class)
+                .child(Hostconfig.class, hostconfig.getKey());
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        ovsdbInventoryService =
+                (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
+        ovsdbInventoryService.listenerAdded(this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3Adapter.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3Adapter.java
new file mode 100644 (file)
index 0000000..13b5354
--- /dev/null
@@ -0,0 +1,1699 @@
+/*
+ * Copyright (c) 2014 - 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.openstack.netvirt.impl;
+
+import static org.opendaylight.netvirt.openstack.netvirt.api.Action.ADD;
+import static org.opendaylight.netvirt.openstack.netvirt.api.Action.DELETE;
+import static org.opendaylight.netvirt.openstack.netvirt.api.Action.UPDATE;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.NeutronL3AdapterEvent;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolverListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.IcmpEchoProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronIAwareUtil;
+import org.opendaylight.netvirt.utils.neutron.utils.NeutronModelsDataStoreHelper;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+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.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+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.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
+ * these events, the abstract router callbacks can be generated to the multi-tenant aware router,
+ * as well as the multi-tenant router forwarding provider.
+ */
+public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResolverListener, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronL3Adapter.class);
+
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile ConfigurationService configurationService;
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronFloatingIPCRUD neutronFloatingIpCache;
+    private volatile L3ForwardingProvider l3ForwardingProvider;
+    private volatile InboundNatProvider inboundNatProvider;
+    private volatile OutboundNatProvider outboundNatProvider;
+    private volatile ArpProvider arpProvider;
+    private volatile RoutingProvider routingProvider;
+    private volatile GatewayMacResolver gatewayMacResolver;
+    private volatile SecurityServicesManager securityServicesManager;
+    private volatile IcmpEchoProvider icmpEchoProvider;
+
+    private class FloatIpData {
+        // br-int of node where floating ip is associated with tenant port
+        private final Long dpid;
+        // patch port in br-int used to reach br-ex
+        private final Long ofPort;
+        // segmentation id of the net where fixed ip is instantiated
+        private final String segId;
+        // mac address assigned to neutron port of floating ip
+        private final String macAddress;
+        private final String floatingIpAddress;
+        // ip address given to tenant vm
+        private final String fixedIpAddress;
+        private final String neutronRouterMac;
+
+        FloatIpData(final Long dpid, final Long ofPort, final String segId, final String macAddress,
+                    final String floatingIpAddress, final String fixedIpAddress, final String neutronRouterMac) {
+            this.dpid = dpid;
+            this.ofPort = ofPort;
+            this.segId = segId;
+            this.macAddress = macAddress;
+            this.floatingIpAddress = floatingIpAddress;
+            this.fixedIpAddress = fixedIpAddress;
+            this.neutronRouterMac = neutronRouterMac;
+        }
+    }
+
+    private Map<String, String> networkIdToRouterMacCache;
+    private Map<String, List<Neutron_IPs>> networkIdToRouterIpListCache;
+    private Map<String, NeutronRouter_Interface> subnetIdToRouterInterfaceCache;
+
+    private Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache;
+    private Map<String, FloatIpData> floatIpDataMapCache;
+
+    private String externalRouterMac;
+    private Boolean enabled = false;
+    private Boolean isCachePopulationDone = false;
+    private Map<String, NeutronPort> portCleanupCache;
+    private Map<String, NeutronNetwork> networkCleanupCache;
+
+    private Southbound southbound;
+    private DistributedArpService distributedArpService;
+    private NeutronModelsDataStoreHelper neutronModelsDataStoreHelper;
+
+    private static final String OWNER_ROUTER_INTERFACE = "network:router_interface";
+    private static final String OWNER_ROUTER_INTERFACE_DISTRIBUTED = "network:router_interface_distributed";
+    private static final String OWNER_ROUTER_GATEWAY = "network:router_gateway";
+    private static final String OWNER_FLOATING_IP = "network:floatingip";
+    private static final String DEFAULT_EXT_RTR_MAC = "00:00:5E:00:01:01";
+
+    public NeutronL3Adapter(NeutronModelsDataStoreHelper neutronHelper) {
+        LOG.info(">>>>>> NeutronL3Adapter constructor {}", this.getClass());
+        this.neutronModelsDataStoreHelper = neutronHelper;
+    }
+
+    private void initL3AdapterMembers() {
+        Preconditions.checkNotNull(configurationService);
+
+        if (configurationService.isL3ForwardingEnabled()) {
+            this.networkIdToRouterMacCache = new HashMap<>();
+            this.networkIdToRouterIpListCache = new HashMap<>();
+            this.subnetIdToRouterInterfaceCache = new HashMap<>();
+            this.neutronPortToDpIdCache = new HashMap<>();
+            this.floatIpDataMapCache = new HashMap<>();
+
+            this.externalRouterMac = configurationService.getDefaultGatewayMacAddress(null);
+            if (this.externalRouterMac == null) {
+                this.externalRouterMac = DEFAULT_EXT_RTR_MAC;
+            }
+            this.enabled = true;
+            LOG.info("OVSDB L3 forwarding is enabled");
+        } else {
+            LOG.debug("OVSDB L3 forwarding is disabled");
+        }
+        this.portCleanupCache = new HashMap<>();
+        this.networkCleanupCache = new HashMap<>();
+    }
+
+    //
+    // Callbacks from AbstractHandler
+    //
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NeutronL3AdapterEvent)) {
+            LOG.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        if (!this.enabled) {
+            return;
+        }
+
+        NeutronL3AdapterEvent ev = (NeutronL3AdapterEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case UPDATE:
+                if (ev.getSubType() == NeutronL3AdapterEvent.SubType.SUBTYPE_EXTERNAL_MAC_UPDATE) {
+                    updateExternalRouterMac( ev.getMacAddress().getValue() );
+                } else {
+                    LOG.warn("Received update for an unexpected event " + ev);
+                }
+                break;
+            case ADD:
+                // fall through...
+                // break;
+            case DELETE:
+                // fall through...
+                // break;
+            default:
+                LOG.warn("Unable to process event " + ev);
+                break;
+        }
+    }
+
+    //
+    // Callbacks from GatewayMacResolverListener
+    //
+
+    @Override
+    public void gatewayMacResolved(Long externalNetworkBridgeDpid, IpAddress gatewayIpAddress, MacAddress macAddress) {
+        LOG.info("got gatewayMacResolved callback for ip {} on dpid {} to mac {}",
+                gatewayIpAddress, externalNetworkBridgeDpid, macAddress);
+        if (!this.enabled) {
+            return;
+        }
+
+        if (macAddress == null || macAddress.getValue() == null) {
+            // TODO: handle cases when mac is null
+            return;
+        }
+
+        //
+        // Enqueue event so update is handled by adapter's thread
+        //
+        enqueueEvent( new NeutronL3AdapterEvent(externalNetworkBridgeDpid, gatewayIpAddress, macAddress) );
+    }
+
+    private void populateL3ForwardingCaches() {
+        if (!this.enabled) {
+            return;
+        }
+        if(this.isCachePopulationDone || this.neutronFloatingIpCache == null
+                || this.neutronPortCache == null ||this.neutronNetworkCache == null) {
+            return;
+        }
+        this.isCachePopulationDone = true;
+        LOG.debug("Populating NetVirt L3 caches from data store configuration");
+        Routers routers = this.neutronModelsDataStoreHelper.readAllNeutronRouters();
+        Ports ports = this.neutronModelsDataStoreHelper.readAllNeutronPorts();
+        if(routers != null && routers.getRouter() != null && ports != null) {
+            LOG.debug("L3 Cache Population : {} Neutron router present in data store",routers.getRouter().size());
+            for( Router router : routers.getRouter()) {
+                LOG.debug("L3 Cache Population : Populate caches for router {}",router);
+                if(!ports.getPort().isEmpty()) {
+                    for( Port port : ports.getPort()) {
+                        if (port.getDeviceId().equals(router.getUuid().getValue()) &&
+                                port.getDeviceOwner().equals(OWNER_ROUTER_INTERFACE)) {
+                            LOG.debug("L3 Cache Population : Router interface {} found.",port);
+                            networkIdToRouterMacCache.put(port.getNetworkId().getValue()
+                                    , port.getMacAddress());
+
+                            networkIdToRouterIpListCache.put(port.getNetworkId().getValue(),
+                                    NeutronIAwareUtil.convertMDSalIpToNeutronIp(port.getFixedIps()));
+                            subnetIdToRouterInterfaceCache.put(port.getFixedIps().get(0).getSubnetId().getValue(),
+                                    NeutronIAwareUtil.convertMDSalInterfaceToNeutronRouterInterface(port));
+                        }
+                    }
+                }else {
+                    LOG.warn("L3 Cache Population :Did not find any port information " +
+                            "in config Data Store for router {}",router);
+                }
+            }
+        }
+        LOG.debug("NetVirt L3 caches population is done");
+    }
+
+    private Pair<Long, Uuid> getDpIdOfNeutronPort(String neutronTenantPortUuid) {
+        if(neutronPortToDpIdCache.get(neutronTenantPortUuid) == null) {
+            List<Node> bridges = this.southbound.readOvsdbTopologyBridgeNodes();
+            LOG.debug("getDpIdOfNeutronPort : {} bridges present in ovsdb topology",bridges.size());
+            for(Node bridge : bridges) {
+                List<OvsdbTerminationPointAugmentation> interfaces
+                        = southbound.extractTerminationPointAugmentations(bridge);
+                if(interfaces != null && !interfaces.isEmpty()) {
+                    LOG.debug("getDpIdOfNeutronPort : {} termination point present on bridge {}",
+                            interfaces.size(), bridge.getNodeId());
+                    for (OvsdbTerminationPointAugmentation intf : interfaces) {
+                        NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+                        if(neutronPort != null && neutronPort.getID().equals(neutronTenantPortUuid)) {
+                            Long dpId = getDpidForIntegrationBridge(bridge);
+                            Uuid interfaceUuid = intf.getInterfaceUuid();
+                            LOG.debug("getDpIdOfNeutronPort : Found bridge {} and interface {} for the tenant neutron" +
+                                    " port {}",dpId,interfaceUuid,neutronTenantPortUuid);
+                            handleInterfaceEventAdd(neutronPort.getPortUUID(), dpId, interfaceUuid);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return neutronPortToDpIdCache.get(neutronTenantPortUuid);
+    }
+
+    private Collection<FloatIpData> getAllFloatingIPsWithMetadata() {
+        LOG.debug("getAllFloatingIPsWithMetadata : Fechting all floating Ips and it's metadata");
+        List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
+        if(neutronFloatingIps != null && !neutronFloatingIps.isEmpty()) {
+            for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
+                if(!floatIpDataMapCache.containsKey(neutronFloatingIP.getID())){
+                    LOG.debug("Metadata for floating ip {} is not present in the cache. " +
+                            "Fetching from data store.",neutronFloatingIP.getID());
+                    this.getFloatingIPWithMetadata(neutronFloatingIP.getID());
+                }
+            }
+        }
+        LOG.debug("getAllFloatingIPsWithMetadata : {} floating points found in data store",floatIpDataMapCache.size());
+        return floatIpDataMapCache.values();
+    }
+    private FloatIpData getFloatingIPWithMetadata(String neutronFloatingId) {
+        LOG.debug("getFloatingIPWithMetadata : Get Floating ip and it's meta data for neutron " +
+                "floating id {} ",neutronFloatingId);
+        if(floatIpDataMapCache.get(neutronFloatingId) == null) {
+            NeutronFloatingIP neutronFloatingIP = neutronFloatingIpCache.getFloatingIP(neutronFloatingId);
+            if (neutronFloatingIP == null) {
+                LOG.error("getFloatingIPWithMetadata : Floating ip {} is missing from data store, that should not happen",neutronFloatingId);
+                return null;
+            }
+            List<NeutronPort> neutronPorts = neutronPortCache.getAllPorts();
+            NeutronPort neutronPortForFloatIp = null;
+            for (NeutronPort neutronPort : neutronPorts) {
+                if (neutronPort.getDeviceOwner().equals(OWNER_FLOATING_IP) &&
+                        neutronPort.getDeviceID().equals(neutronFloatingIP.getID())) {
+                    neutronPortForFloatIp = neutronPort;
+                    break;
+                }
+            }
+
+            String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
+            if(neutronTenantPortUuid == null) {
+                return null;
+            }
+            Pair<Long, Uuid> nodeIfPair = this.getDpIdOfNeutronPort(neutronTenantPortUuid);
+            String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
+            String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
+            String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
+
+            NeutronPort tenantNeutronPort = neutronPortCache.getPort(neutronTenantPortUuid);
+            NeutronNetwork tenantNeutronNetwork = tenantNeutronPort != null ?
+                    neutronNetworkCache.getNetwork(tenantNeutronPort.getNetworkUUID()) : null;
+            String providerSegmentationId = tenantNeutronNetwork != null ?
+                    tenantNeutronNetwork.getProviderSegmentationID() : null;
+            String neutronRouterMac = tenantNeutronNetwork != null ?
+                    networkIdToRouterMacCache.get(tenantNeutronNetwork.getID()) : null;
+
+            if (nodeIfPair == null || neutronTenantPortUuid == null ||
+                    providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+                    floatingIpMac == null || floatingIpMac.isEmpty() ||
+                    neutronRouterMac == null || neutronRouterMac.isEmpty()) {
+                LOG.debug("getFloatingIPWithMetadata :Floating IP {}<->{}, incomplete floatPort {} tenantPortUuid {} " +
+                                "seg {} mac {} rtrMac {}",
+                        fixedIpAddress,
+                        floatingIpAddress,
+                        neutronPortForFloatIp,
+                        neutronTenantPortUuid,
+                        providerSegmentationId,
+                        floatingIpMac,
+                        neutronRouterMac);
+
+                return null;
+            }
+
+            // get ofport for patch port in br-int
+            final Long dpId = nodeIfPair.getLeft();
+            final Long ofPort = findOFPortForExtPatch(dpId);
+            if (ofPort == null) {
+                LOG.warn("getFloatingIPWithMetadata : Unable to locate OF port of patch port " +
+                                "to connect floating ip to external bridge. dpid {}",
+                        dpId);
+                return null;
+            }
+
+            final FloatIpData floatIpData = new FloatIpData(dpId, ofPort, providerSegmentationId, floatingIpMac,
+                    floatingIpAddress, fixedIpAddress, neutronRouterMac);
+            floatIpDataMapCache.put(neutronFloatingIP.getID(), floatIpData);
+
+        }
+        return floatIpDataMapCache.get(neutronFloatingId);
+    }
+    /**
+     * Invoked to configure the mac address for the external gateway in br-ex. ovsdb netvirt needs help in getting
+     * mac for given ip in br-ex (bug 3378). For example, since ovsdb has no real arp, it needs a service in can
+     * subscribe so that the mac address associated to the gateway ip address is available.
+     *
+     * @param externalRouterMacUpdate  The mac address to be associated to the gateway.
+     */
+    public void updateExternalRouterMac(final String externalRouterMacUpdate) {
+        Preconditions.checkNotNull(externalRouterMacUpdate);
+
+        flushExistingIpRewrite();
+        this.externalRouterMac = externalRouterMacUpdate;
+        rebuildExistingIpRewrite();
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param subnet An instance of NeutronSubnet object.
+     */
+    public void handleNeutronSubnetEvent(final NeutronSubnet subnet, Action action) {
+        LOG.debug("Neutron subnet {} event : {}", action, subnet.toString());
+        if (action == ADD) {
+            this.storeNetworkInCleanupCache(neutronNetworkCache.getNetwork(subnet.getNetworkUUID()));
+        }
+    }
+
+    /**
+     * Process the port event as a router interface event.
+     * For a not delete action, since a port is only create when the tennat uses the subnet, it is required to
+     * verify if all routers across all nodes have the interface for the port's subnet(s) configured.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param neutronPort An instance of NeutronPort object.
+     */
+    public void handleNeutronPortEvent(final NeutronPort neutronPort, Action action) {
+        LOG.debug("Neutron port {} event : {}", action, neutronPort.toString());
+
+        if (action == UPDATE) {
+            // FIXME: Bug 4971 Move cleanup cache to SG Impl
+            this.updatePortInCleanupCache(neutronPort, neutronPort.getOriginalPort());
+            if (neutronPort.getPortSecurityEnabled()) {
+                this.processSecurityGroupUpdate(neutronPort);
+            }
+        }
+
+        if (!this.enabled) {
+            return;
+        }
+
+        final boolean isDelete = action == DELETE;
+
+        if (action == DELETE) {
+            // Bug 5164: Cleanup Floating IP OpenFlow Rules when port is deleted.
+            this.cleanupFloatingIPRules(neutronPort);
+        }
+        else if (action == UPDATE){
+            // Bug 5353: VM restart cause floatingIp flows to be removed
+            this.updateFloatingIPRules(neutronPort);
+        }
+
+        if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_GATEWAY)){
+            if (!isDelete) {
+                LOG.info("Port {} is network router gateway interface, "
+                        + "triggering gateway resolution for the attached external network", neutronPort);
+                this.triggerGatewayMacResolver(neutronPort);
+            }else{
+                NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(neutronPort.getNetworkUUID());
+                if (null == externalNetwork) {
+                    externalNetwork = this.getNetworkFromCleanupCache(neutronPort.getNetworkUUID());
+                }
+
+                if (externalNetwork != null && externalNetwork.isRouterExternal()) {
+                    final NeutronSubnet externalSubnet = getExternalNetworkSubnet(neutronPort);
+                    // TODO support IPv6
+                    if (externalSubnet != null &&
+                            externalSubnet.getIpVersion() == 4) {
+                        gatewayMacResolver.stopPeriodicRefresh(new Ipv4Address(externalSubnet.getGatewayIP()));
+                    }
+                }
+            }
+        }
+
+        // Treat the port event as a router interface event if the port belongs to router. This is a
+        // helper for handling cases when handleNeutronRouterInterfaceEvent is not available
+        //
+        if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE) ||
+            neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE_DISTRIBUTED)) {
+
+            if (neutronPort.getFixedIPs() != null) {
+                for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
+                    NeutronRouter_Interface neutronRouterInterface =
+                        new NeutronRouter_Interface(neutronIP.getSubnetUUID(), neutronPort.getPortUUID());
+                    // id of router interface to be same as subnet
+                    neutronRouterInterface.setID(neutronIP.getSubnetUUID());
+                    neutronRouterInterface.setTenantID(neutronPort.getTenantID());
+
+                    this.handleNeutronRouterInterfaceEvent(null /*neutronRouter*/, neutronRouterInterface, action);
+                }
+            }
+        } else {
+            // We made it here, port is not used as a router interface. If this is not a delete action, make sure that
+            // all nodes that are supposed to have a router interface for the port's subnet(s), have it configured. We
+            // need to do this check here because a router interface is not added to a node until tenant becomes needed
+            // there.
+            //
+            if (!isDelete && neutronPort.getFixedIPs() != null) {
+                for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
+                    NeutronRouter_Interface neutronRouterInterface =
+                            subnetIdToRouterInterfaceCache.get(neutronIP.getSubnetUUID());
+                    if (neutronRouterInterface != null) {
+                        this.handleNeutronRouterInterfaceEvent(null /*neutronRouter*/, neutronRouterInterface, action);
+                    }
+                }
+            }
+            this.updateL3ForNeutronPort(neutronPort, isDelete);
+        }
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param neutronRouter An instance of NeutronRouter object.
+     */
+    public void handleNeutronRouterEvent(final NeutronRouter neutronRouter, Action action) {
+        LOG.debug("Neutron router {} event : {}", action, neutronRouter.toString());
+    }
+
+    /**
+     * Process the event enforcing actions and verifying dependencies between all router's interface. For example,
+     * delete the ports on the same subnet.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param neutronRouter An instance of NeutronRouter object.
+     * @param neutronRouterInterface An instance of NeutronRouter_Interface object.
+     */
+    public void handleNeutronRouterInterfaceEvent(final NeutronRouter neutronRouter,
+                                                  final NeutronRouter_Interface neutronRouterInterface,
+                                                  Action action) {
+        LOG.debug("Router interface {} got event {}. Subnet {}",
+                     neutronRouterInterface.getPortUUID(),
+                     action,
+                     neutronRouterInterface.getSubnetUUID());
+        if (!this.enabled) {
+            return;
+        }
+
+        final boolean isDelete = action == DELETE;
+
+        this.programFlowsForNeutronRouterInterface(neutronRouterInterface, isDelete);
+
+        // As neutron router interface is added/removed, we need to iterate through all the neutron ports and
+        // see if they are affected by l3
+        //
+        for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
+            boolean currPortShouldBeDeleted = false;
+            // Note: delete in this case only applies to 1)router interface delete and 2)ports on the same subnet
+            if (isDelete) {
+                if (neutronPort.getFixedIPs() != null) {
+                    for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
+                        if (neutronRouterInterface.getSubnetUUID().equalsIgnoreCase(neutronIP.getSubnetUUID())) {
+                            currPortShouldBeDeleted = true;
+                            break;
+                        }
+                    }
+                }
+            }
+            this.updateL3ForNeutronPort(neutronPort, currPortShouldBeDeleted);
+        }
+
+    }
+
+    /**
+     * Invoked when a neutron message regarding the floating ip association is sent to odl via ml2. If the action is
+     * a creation, it will first add ARP rules for the given floating ip and then configure the DNAT (rewrite the
+     * packets from the floating IP address to the internal fixed ip) rules on OpenFlow Table 30 and SNAT rules (other
+     * way around) on OpenFlow Table 100.
+     *
+     * @param actionIn the {@link Action} action to be handled.
+     * @param neutronFloatingIP An {@link NeutronFloatingIP} instance of NeutronFloatingIP object.
+     */
+    public void handleNeutronFloatingIPEvent(final NeutronFloatingIP neutronFloatingIP,
+                                             Action actionIn) {
+        Preconditions.checkNotNull(neutronFloatingIP);
+
+        LOG.debug(" Floating IP {} {}<->{}, network uuid {}", actionIn,
+                neutronFloatingIP.getFixedIPAddress(),
+                neutronFloatingIP.getFloatingIPAddress(),
+                neutronFloatingIP.getFloatingNetworkUUID());
+        if (!this.enabled) {
+            return;
+        }
+
+        Action action;
+
+        // Consider action to be delete if getFixedIPAddress is null
+        //
+        if (neutronFloatingIP.getFixedIPAddress() == null) {
+            action = DELETE;
+        } else {
+            action = actionIn;
+        }
+
+        // this.programFlowsForFloatingIP(neutronFloatingIP, action == Action.DELETE);
+
+        if (action != DELETE) {
+            // must be first, as it updates floatIpDataMapCache
+            programFlowsForFloatingIPArpAdd(neutronFloatingIP);
+
+            programFlowsForFloatingIPInbound(neutronFloatingIP, ADD);
+            programFlowsForFloatingIPOutbound(neutronFloatingIP, ADD);
+        } else {
+            programFlowsForFloatingIPOutbound(neutronFloatingIP, DELETE);
+            programFlowsForFloatingIPInbound(neutronFloatingIP, DELETE);
+
+            // must be last, as it updates floatIpDataMapCache
+            programFlowsForFloatingIPArpDelete(neutronFloatingIP.getID());
+        }
+    }
+
+    /**
+     * This method performs creation or deletion of in-bound rules into Table 30 for a existing available floating
+     * ip, otherwise for newer one.
+     */
+    private void programFlowsForFloatingIPInbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
+        Preconditions.checkNotNull(neutronFloatingIP);
+
+        final FloatIpData fid = getFloatingIPWithMetadata(neutronFloatingIP.getID());
+        if (fid == null) {
+            LOG.trace("programFlowsForFloatingIPInboundAdd {} for {} uuid {} not in local cache",
+                    action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
+            return;
+        }
+        programInboundIpRewriteStage1(fid.dpid, fid.ofPort, fid.segId, fid.floatingIpAddress, fid.fixedIpAddress,
+                                      action);
+    }
+
+    /**
+     * This method performs creation or deletion of out-bound rules into Table 100 for a existing available floating
+     * ip, otherwise for newer one.
+     */
+    private void programFlowsForFloatingIPOutbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
+        Preconditions.checkNotNull(neutronFloatingIP);
+
+        final FloatIpData fid = getFloatingIPWithMetadata(neutronFloatingIP.getID());
+        if (fid == null) {
+            LOG.trace("programFlowsForFloatingIPOutbound {} for {} uuid {} not in local cache",
+                    action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
+            return;
+        }
+        programOutboundIpRewriteStage1(fid, action);
+    }
+
+    private void flushExistingIpRewrite() {
+        for (FloatIpData fid : getAllFloatingIPsWithMetadata()) {
+            programOutboundIpRewriteStage1(fid, DELETE);
+        }
+    }
+
+    private void rebuildExistingIpRewrite() {
+        for (FloatIpData fid : getAllFloatingIPsWithMetadata()) {
+            programOutboundIpRewriteStage1(fid, ADD);
+        }
+    }
+
+    /**
+     * This method creates ARP response rules into OpenFlow Table 30 for a given floating ip. In order to connect
+     * to br-ex from br-int, a patch-port is used. Thus, the patch-port will be responsible to respond the ARP
+     * requests.
+     */
+    private void programFlowsForFloatingIPArpAdd(final NeutronFloatingIP neutronFloatingIP) {
+        Preconditions.checkNotNull(neutronFloatingIP);
+        Preconditions.checkNotNull(neutronFloatingIP.getFixedIPAddress());
+        Preconditions.checkNotNull(neutronFloatingIP.getFloatingIPAddress());
+
+        // find bridge Node where floating ip is configured by looking up cache for its port
+        final NeutronPort neutronPortForFloatIp = findNeutronPortForFloatingIp(neutronFloatingIP.getID());
+        final String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
+        final Pair<Long, Uuid> nodeIfPair = this.getDpIdOfNeutronPort(neutronTenantPortUuid);
+        final String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
+        final String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
+        final String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
+
+        final NeutronPort tenantNeutronPort = neutronPortCache.getPort(neutronTenantPortUuid);
+        final NeutronNetwork tenantNeutronNetwork = tenantNeutronPort != null ?
+                neutronNetworkCache.getNetwork(tenantNeutronPort.getNetworkUUID()) : null;
+        final String providerSegmentationId = tenantNeutronNetwork != null ?
+                tenantNeutronNetwork.getProviderSegmentationID() : null;
+        final String neutronRouterMac = tenantNeutronNetwork != null ?
+                networkIdToRouterMacCache.get(tenantNeutronNetwork.getID()) : null;
+
+        if (nodeIfPair == null || neutronTenantPortUuid == null ||
+                providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+                floatingIpMac == null || floatingIpMac.isEmpty() ||
+                neutronRouterMac == null || neutronRouterMac.isEmpty()) {
+            LOG.trace("Floating IP {}<->{}, incomplete floatPort {} tenantPortUuid {} seg {} mac {} rtrMac {}",
+                    fixedIpAddress,
+                    floatingIpAddress,
+                    neutronPortForFloatIp,
+                    neutronTenantPortUuid,
+                    providerSegmentationId,
+                    floatingIpMac,
+                    neutronRouterMac);
+            return;
+        }
+
+        // get ofport for patch port in br-int
+        final Long dpId = nodeIfPair.getLeft();
+        final Long ofPort = findOFPortForExtPatch(dpId);
+        if (ofPort == null) {
+            LOG.warn("Unable to locate OF port of patch port to connect floating ip to external bridge. dpid {}",
+                    dpId);
+            return;
+        }
+
+        // Respond to ARPs for the floating ip address by default, via the patch port that connects br-int to br-ex
+        //
+        if (distributedArpService.programStaticRuleStage1(dpId, encodeExcplicitOFPort(ofPort), floatingIpMac, floatingIpAddress,
+                ADD)) {
+            final FloatIpData floatIpData = new FloatIpData(dpId, ofPort, providerSegmentationId, floatingIpMac,
+                    floatingIpAddress, fixedIpAddress, neutronRouterMac);
+            floatIpDataMapCache.put(neutronFloatingIP.getID(), floatIpData);
+            LOG.info("Floating IP {}<->{} programmed ARP mac {} on OFport {} seg {} dpid {}",
+                    neutronFloatingIP.getFixedIPAddress(), neutronFloatingIP.getFloatingIPAddress(),
+                    floatingIpMac, ofPort, providerSegmentationId, dpId);
+        }
+    }
+
+    private void programFlowsForFloatingIPArpDelete(final String neutronFloatingIPUuid) {
+        final FloatIpData floatIpData = getFloatingIPWithMetadata(neutronFloatingIPUuid);
+        if (floatIpData == null) {
+            LOG.trace("programFlowsForFloatingIPArpDelete for uuid {} is not needed", neutronFloatingIPUuid);
+            return;
+        }
+
+        if (distributedArpService.programStaticRuleStage1(floatIpData.dpid, encodeExcplicitOFPort(floatIpData.ofPort), floatIpData.macAddress,
+                floatIpData.floatingIpAddress, DELETE)) {
+            floatIpDataMapCache.remove(neutronFloatingIPUuid);
+            LOG.info("Floating IP {} un-programmed ARP mac {} on {} dpid {}",
+                    floatIpData.floatingIpAddress, floatIpData.macAddress, floatIpData.ofPort, floatIpData.dpid);
+        }
+    }
+
+    private NeutronPort findNeutronPortForFloatingIp(final String floatingIpUuid) {
+        for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
+            if (neutronPort.getDeviceOwner().equals(OWNER_FLOATING_IP) &&
+                    neutronPort.getDeviceID().equals(floatingIpUuid)) {
+                return neutronPort;
+            }
+        }
+        return null;
+    }
+
+    private Long findOFPortForExtPatch(Long dpId) {
+        final String brInt = configurationService.getIntegrationBridgeName();
+        final String brExt = configurationService.getExternalBridgeName();
+        final String portNameInt = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brExt));
+
+        Preconditions.checkNotNull(dpId);
+        Preconditions.checkNotNull(portNameInt);
+
+        final long dpidPrimitive = dpId;
+        for (Node node : nodeCacheManager.getBridgeNodes()) {
+            if (dpidPrimitive == southbound.getDataPathId(node)) {
+                final OvsdbTerminationPointAugmentation terminationPointOfBridge =
+                        southbound.getTerminationPointOfBridge(node, portNameInt);
+                return terminationPointOfBridge == null ? null : terminationPointOfBridge.getOfport();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param action the {@link Action} action to be handled.
+     * @param neutronNetwork An {@link NeutronNetwork} instance of NeutronFloatingIP object.
+     */
+    public void handleNeutronNetworkEvent(final NeutronNetwork neutronNetwork, Action action) {
+        LOG.debug("neutronNetwork {}: network: {}", action, neutronNetwork);
+        if (action == UPDATE) {
+            this.updateNetworkInCleanupCache(neutronNetwork);
+        }
+    }
+
+    //
+    // Callbacks from OVSDB's southbound handler
+    //
+    /**
+     * Process the event.
+     *
+     * @param bridgeNode An instance of Node object.
+     * @param intf An {@link org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+     * .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
+     * @param neutronNetwork An {@link NeutronNetwork} instance of NeutronNetwork
+     * object.
+     * @param action the {@link Action} action to be handled.
+     */
+    public void handleInterfaceEvent(final Node bridgeNode, final OvsdbTerminationPointAugmentation intf,
+                                     final NeutronNetwork neutronNetwork, Action action) {
+        LOG.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
+                     action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork);
+
+        final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+        if (action != DELETE && neutronPort != null) {
+            // FIXME: Bug 4971 Move cleanup cache to SG Impl
+            storePortInCleanupCache(neutronPort);
+        }
+
+        if (!this.enabled) {
+            return;
+        }
+
+        final Long dpId = getDpidForIntegrationBridge(bridgeNode);
+        final Uuid interfaceUuid = intf.getInterfaceUuid();
+
+        LOG.trace("southbound interface {} node:{} interface:{}, neutronNetwork:{} port:{} dpid:{} intfUuid:{}",
+                action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork, neutronPort, dpId, interfaceUuid);
+
+        if (neutronPort != null) {
+            final String neutronPortUuid = neutronPort.getPortUUID();
+
+            if (action != DELETE && dpId != null && interfaceUuid != null) {
+                handleInterfaceEventAdd(neutronPortUuid, dpId, interfaceUuid);
+            }
+
+            handleNeutronPortEvent(neutronPort, action);
+        }
+
+        if (action == DELETE && interfaceUuid != null) {
+            handleInterfaceEventDelete(intf, dpId);
+        }
+    }
+
+    private void handleInterfaceEventAdd(final String neutronPortUuid, Long dpId, final Uuid interfaceUuid) {
+        neutronPortToDpIdCache.put(neutronPortUuid, new ImmutablePair<>(dpId, interfaceUuid));
+        LOG.debug("handleInterfaceEvent add cache entry NeutronPortUuid {} : dpid {}, ifUuid {}",
+                neutronPortUuid, dpId, interfaceUuid.getValue());
+    }
+
+    private void handleInterfaceEventDelete(final OvsdbTerminationPointAugmentation intf, final Long dpId) {
+        // Remove entry from neutronPortToDpIdCache based on interface uuid
+        for (Map.Entry<String, Pair<Long, Uuid>> entry : neutronPortToDpIdCache.entrySet()) {
+            final String currPortUuid = entry.getKey();
+            if (intf.getInterfaceUuid().equals(entry.getValue().getRight())) {
+                LOG.debug("handleInterfaceEventDelete remove cache entry NeutronPortUuid {} : dpid {}, ifUuid {}",
+                        currPortUuid, dpId, intf.getInterfaceUuid().getValue());
+                neutronPortToDpIdCache.remove(currPortUuid);
+                break;
+            }
+        }
+    }
+
+    //
+    // Internal helpers
+    //
+    private void updateL3ForNeutronPort(final NeutronPort neutronPort, final boolean isDelete) {
+
+        final String networkUUID = neutronPort.getNetworkUUID();
+        final String routerMacAddress = networkIdToRouterMacCache.get(networkUUID);
+
+        if(!isDelete) {
+            // If there is no router interface handling the networkUUID, we are done
+            if (routerMacAddress == null || routerMacAddress.isEmpty()) {
+                return;
+            }
+
+            // If this is the neutron port for the router interface itself, ignore it as well. Ports that represent the
+            // router interface are handled via handleNeutronRouterInterfaceEvent.
+            if (routerMacAddress.equalsIgnoreCase(neutronPort.getMacAddress())) {
+                return;
+            }
+        }
+
+        final NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
+        final String providerSegmentationId = neutronNetwork != null ?
+                                              neutronNetwork.getProviderSegmentationID() : null;
+        final String tenantMac = neutronPort.getMacAddress();
+
+        if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+            tenantMac == null || tenantMac.isEmpty()) {
+            // done: go no further w/out all the info needed...
+            return;
+        }
+
+        final Action action = isDelete ? DELETE : ADD;
+        List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (nodes.isEmpty()) {
+            LOG.trace("updateL3ForNeutronPort has no nodes to work with");
+        }
+        for (Node node : nodes) {
+            final Long dpid = getDpidForIntegrationBridge(node);
+            if (dpid == null) {
+                continue;
+            }
+            if (neutronPort.getFixedIPs() == null) {
+                continue;
+            }
+            for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
+                final String tenantIpStr = neutronIP.getIpAddress();
+                if (tenantIpStr.isEmpty()) {
+                    continue;
+                }
+
+                // Configure L3 fwd. We do that regardless of tenant network present, because these rules are
+                // still needed when routing to subnets non-local to node (bug 2076).
+                programL3ForwardingStage1(node, dpid, providerSegmentationId, tenantMac, tenantIpStr, action);
+            }
+        }
+    }
+
+    private void processSecurityGroupUpdate(NeutronPort neutronPort) {
+        LOG.trace("processSecurityGroupUpdate:" + neutronPort);
+        /**
+         * Get updated data and original data for the the changed. Identify the security groups that got
+         * added and removed and call the appropriate providers for updating the flows.
+         */
+        try {
+            NeutronPort originalPort = neutronPort.getOriginalPort();
+            List<NeutronSecurityGroup> addedGroup = getsecurityGroupChanged(neutronPort,
+                                                                            neutronPort.getOriginalPort());
+            List<NeutronSecurityGroup> deletedGroup = getsecurityGroupChanged(neutronPort.getOriginalPort(),
+                                                                              neutronPort);
+
+            if (null != addedGroup && !addedGroup.isEmpty()) {
+                securityServicesManager.syncSecurityGroup(neutronPort,addedGroup,true);
+            }
+            if (null != deletedGroup && !deletedGroup.isEmpty()) {
+                securityServicesManager.syncSecurityGroup(neutronPort,deletedGroup,false);
+            }
+
+        } catch (Exception e) {
+            LOG.error("Exception in processSecurityGroupUpdate", e);
+        }
+    }
+
+    private List<NeutronSecurityGroup> getsecurityGroupChanged(NeutronPort port1, NeutronPort port2) {
+        LOG.trace("getsecurityGroupChanged:" + "Port1:" + port1 + "Port2" + port2);
+        if (port1 == null) {
+            return null;
+        }
+        List<NeutronSecurityGroup> list1 = new ArrayList<>(port1.getSecurityGroups());
+        if (port2 == null) {
+            return list1;
+        }
+        List<NeutronSecurityGroup> list2 = new ArrayList<>(port2.getSecurityGroups());
+        for (Iterator<NeutronSecurityGroup> iterator = list1.iterator(); iterator.hasNext();) {
+            NeutronSecurityGroup securityGroup1 = iterator.next();
+            for (NeutronSecurityGroup securityGroup2 :list2) {
+                if (securityGroup1.getID().equals(securityGroup2.getID())) {
+                    iterator.remove();
+                }
+            }
+        }
+        return list1;
+    }
+
+    private void programL3ForwardingStage1(Node node, Long dpid, String providerSegmentationId,
+                                           String macAddress, String ipStr,
+                                           Action actionForNode) {
+        if (actionForNode == DELETE) {
+            LOG.trace("Deleting Flow : programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {}",
+                         node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
+        }
+        if (actionForNode == ADD) {
+            LOG.trace("Adding Flow : programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {}",
+                    node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
+        }
+
+        this.programL3ForwardingStage2(node, dpid, providerSegmentationId,
+                                                       macAddress, ipStr, actionForNode);
+    }
+
+    private Status programL3ForwardingStage2(Node node, Long dpid, String providerSegmentationId,
+                                             String macAddress,
+                                             String address,
+                                             Action actionForNode) {
+        Status status;
+        try {
+            InetAddress inetAddress = InetAddress.getByName(address);
+            status = l3ForwardingProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     l3ForwardingProvider.programForwardingTableEntry(dpid, providerSegmentationId,
+                                                                      inetAddress, macAddress, actionForNode);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            LOG.debug("ProgramL3Forwarding {} for mac:{} addr:{} node:{} action:{}",
+                         l3ForwardingProvider == null ? "skipped" : "programmed",
+                         macAddress, address, node.getNodeId().getValue(), actionForNode);
+        } else {
+            LOG.error("ProgramL3Forwarding failed for mac:{} addr:{} node:{} action:{} status:{}",
+                         macAddress, address, node.getNodeId().getValue(), actionForNode, status);
+        }
+        return status;
+    }
+
+    // --
+
+    private void programFlowsForNeutronRouterInterface(final NeutronRouter_Interface destNeutronRouterInterface,
+                                                       Boolean isDelete) {
+        Preconditions.checkNotNull(destNeutronRouterInterface);
+
+        final NeutronPort neutronPort = neutronPortCache.getPort(destNeutronRouterInterface.getPortUUID());
+        String macAddress = neutronPort != null ? neutronPort.getMacAddress() : null;
+        List<Neutron_IPs> ipList = neutronPort != null ? neutronPort.getFixedIPs() : null;
+        final NeutronSubnet subnet = neutronSubnetCache.getSubnet(destNeutronRouterInterface.getSubnetUUID());
+        final NeutronNetwork neutronNetwork = subnet != null ?
+                                              neutronNetworkCache.getNetwork(subnet.getNetworkUUID()) : null;
+        final String destinationSegmentationId = neutronNetwork != null ?
+                                                 neutronNetwork.getProviderSegmentationID() : null;
+        final Boolean isExternal = neutronNetwork != null ? neutronNetwork.getRouterExternal() : Boolean.TRUE;
+        final String cidr = subnet != null ? subnet.getCidr() : null;
+        final int mask = getMaskLenFromCidr(cidr);
+
+        LOG.trace("programFlowsForNeutronRouterInterface called for interface {} isDelete {}",
+                     destNeutronRouterInterface, isDelete);
+
+        // in delete path, mac address as well as ip address are not provided. Being so, let's find them from
+        // the local cache
+        if (neutronNetwork != null) {
+            if (macAddress == null || macAddress.isEmpty()) {
+                macAddress = networkIdToRouterMacCache.get(neutronNetwork.getNetworkUUID());
+            }
+            if (ipList == null || ipList.isEmpty()) {
+                ipList = networkIdToRouterIpListCache.get(neutronNetwork.getNetworkUUID());
+            }
+        }
+
+        if (destinationSegmentationId == null || destinationSegmentationId.isEmpty() ||
+            cidr == null || cidr.isEmpty() ||
+            macAddress == null || macAddress.isEmpty() ||
+            ipList == null || ipList.isEmpty()) {
+            LOG.debug("programFlowsForNeutronRouterInterface is bailing seg:{} cidr:{} mac:{}  ip:{}",
+                         destinationSegmentationId, cidr, macAddress, ipList);
+            // done: go no further w/out all the info needed...
+            return;
+        }
+
+        final Action actionForNode = isDelete ? DELETE : ADD;
+
+        // Keep cache for finding router's mac from network uuid -- add
+        //
+        if (! isDelete) {
+            networkIdToRouterMacCache.put(neutronNetwork.getNetworkUUID(), macAddress);
+            networkIdToRouterIpListCache.put(neutronNetwork.getNetworkUUID(), new ArrayList<>(ipList));
+            subnetIdToRouterInterfaceCache.put(subnet.getSubnetUUID(), destNeutronRouterInterface);
+        }
+
+        List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (nodes.isEmpty()) {
+            LOG.trace("programFlowsForNeutronRouterInterface has no nodes to work with");
+        }
+        for (Node node : nodes) {
+            final Long dpid = getDpidForIntegrationBridge(node);
+            if (dpid == null) {
+                continue;
+            }
+
+            for (Neutron_IPs neutronIP : ipList) {
+                final String ipStr = neutronIP.getIpAddress();
+                if (ipStr.isEmpty()) {
+                    LOG.debug("programFlowsForNeutronRouterInterface is skipping node {} ip {}",
+                            node.getNodeId().getValue(), ipStr);
+                    continue;
+                }
+
+                // Iterate through all other interfaces and add/remove reflexive flows to this interface
+                //
+                for (NeutronRouter_Interface srcNeutronRouterInterface : subnetIdToRouterInterfaceCache.values()) {
+                    programFlowsForNeutronRouterInterfacePair(node, dpid,
+                                                              srcNeutronRouterInterface, destNeutronRouterInterface,
+                                                              neutronNetwork, destinationSegmentationId,
+                                                              macAddress, ipStr, mask, actionForNode,
+                                                              true /*isReflexsive*/);
+                }
+
+                if (! isExternal) {
+                    programFlowForNetworkFromExternal(node, dpid, destinationSegmentationId, macAddress, ipStr, mask,
+                            actionForNode);
+                }
+                // Enable ARP responder by default, because router interface needs to be responded always.
+                distributedArpService.programStaticRuleStage1(dpid, destinationSegmentationId, macAddress, ipStr, actionForNode);
+                programIcmpEcho(dpid, destinationSegmentationId, macAddress, ipStr, actionForNode);
+            }
+
+            // Compute action to be programmed. In the case of rewrite exclusions, we must never program rules
+            // for the external neutron networks.
+            //
+            {
+                final Action actionForRewriteExclusion = isExternal ? DELETE : actionForNode;
+                programIpRewriteExclusionStage1(node, dpid, destinationSegmentationId, cidr, actionForRewriteExclusion);
+            }
+        }
+
+        if (isDelete) {
+            networkIdToRouterMacCache.remove(neutronNetwork.getNetworkUUID());
+            networkIdToRouterIpListCache.remove(neutronNetwork.getNetworkUUID());
+            subnetIdToRouterInterfaceCache.remove(subnet.getSubnetUUID());
+        }
+    }
+
+    private void programFlowForNetworkFromExternal(final Node node,
+                                                   final Long dpid,
+                                                   final String destinationSegmentationId,
+                                                   final String dstMacAddress,
+                                                   final String destIpStr,
+                                                   final int destMask,
+                                                   final Action actionForNode) {
+        programRouterInterfaceStage1(node, dpid, Constants.EXTERNAL_NETWORK, destinationSegmentationId,
+                dstMacAddress, destIpStr, destMask, actionForNode);
+    }
+
+    private void programFlowsForNeutronRouterInterfacePair(final Node node,
+                                                           final Long dpid,
+                                                           final NeutronRouter_Interface srcNeutronRouterInterface,
+                                                           final NeutronRouter_Interface dstNeutronRouterInterface,
+                                                           final NeutronNetwork dstNeutronNetwork,
+                                                           final String destinationSegmentationId,
+                                                           final String dstMacAddress,
+                                                           final String destIpStr,
+                                                           final int destMask,
+                                                           final Action actionForNode,
+                                                           Boolean isReflexsive) {
+        Preconditions.checkNotNull(srcNeutronRouterInterface);
+        Preconditions.checkNotNull(dstNeutronRouterInterface);
+
+        final String sourceSubnetId = srcNeutronRouterInterface.getSubnetUUID();
+        if (sourceSubnetId == null) {
+            LOG.error("Could not get provider Subnet ID from router interface {}",
+                         srcNeutronRouterInterface.getID());
+            return;
+        }
+
+        final NeutronSubnet sourceSubnet = neutronSubnetCache.getSubnet(sourceSubnetId);
+        final String sourceNetworkId = sourceSubnet == null ? null : sourceSubnet.getNetworkUUID();
+        if (sourceNetworkId == null) {
+            LOG.error("Could not get provider Network ID from subnet {}", sourceSubnetId);
+            return;
+        }
+
+        final NeutronNetwork sourceNetwork = neutronNetworkCache.getNetwork(sourceNetworkId);
+        if (sourceNetwork == null) {
+            LOG.error("Could not get provider Network for Network ID {}", sourceNetworkId);
+            return;
+        }
+
+        if (! sourceNetwork.getTenantID().equals(dstNeutronNetwork.getTenantID())) {
+            // Isolate subnets from different tenants within the same router
+            return;
+        }
+        final String sourceSegmentationId = sourceNetwork.getProviderSegmentationID();
+        if (sourceSegmentationId == null) {
+            LOG.error("Could not get provider Segmentation ID for Subnet {}", sourceSubnetId);
+            return;
+        }
+        if (sourceSegmentationId.equals(destinationSegmentationId)) {
+            // Skip 'self'
+            return;
+        }
+
+        programRouterInterfaceStage1(node, dpid, sourceSegmentationId, destinationSegmentationId,
+                                     dstMacAddress, destIpStr, destMask, actionForNode);
+
+        // Flip roles src->dst; dst->src
+        if (isReflexsive) {
+            final NeutronPort sourceNeutronPort = neutronPortCache.getPort(srcNeutronRouterInterface.getPortUUID());
+            final String macAddress2 = sourceNeutronPort != null ? sourceNeutronPort.getMacAddress() : null;
+            final List<Neutron_IPs> ipList2 = sourceNeutronPort != null ? sourceNeutronPort.getFixedIPs() : null;
+            final String cidr2 = sourceSubnet.getCidr();
+            final int mask2 = getMaskLenFromCidr(cidr2);
+
+            if (cidr2 == null || cidr2.isEmpty() ||
+                macAddress2 == null || macAddress2.isEmpty() ||
+                ipList2 == null || ipList2.isEmpty()) {
+                LOG.trace("programFlowsForNeutronRouterInterfacePair reflexive is bailing seg:{} cidr:{} mac:{} ip:{}",
+                             sourceSegmentationId, cidr2, macAddress2, ipList2);
+                // done: go no further w/out all the info needed...
+                return;
+            }
+
+            for (Neutron_IPs neutronIP2 : ipList2) {
+                final String ipStr2 = neutronIP2.getIpAddress();
+                if (ipStr2.isEmpty()) {
+                    continue;
+                }
+                programFlowsForNeutronRouterInterfacePair(node, dpid, dstNeutronRouterInterface,
+                                                          srcNeutronRouterInterface,
+                                                          sourceNetwork, sourceSegmentationId,
+                                                          macAddress2, ipStr2, mask2, actionForNode,
+                                                          false /*isReflexsive*/);
+            }
+        }
+    }
+
+    private void programRouterInterfaceStage1(Node node, Long dpid, String sourceSegmentationId,
+                                              String destinationSegmentationId,
+                                              String macAddress, String ipStr, int mask,
+                                              Action actionForNode) {
+        if (actionForNode == DELETE) {
+            LOG.trace("Deleting Flow : programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
+                         " action {}",
+                         node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
+                         macAddress, ipStr, mask, actionForNode);
+        }
+        if (actionForNode == ADD) {
+            LOG.trace("Adding Flow : programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
+                         " action {}",
+                         node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
+                         macAddress, ipStr, mask, actionForNode);
+        }
+
+        this.programRouterInterfaceStage2(node, dpid, sourceSegmentationId, destinationSegmentationId,
+                                                          macAddress, ipStr, mask, actionForNode);
+    }
+
+    private Status programRouterInterfaceStage2(Node node, Long dpid, String sourceSegmentationId,
+                                                String destinationSegmentationId,
+                                                String macAddress,
+                                                String address, int mask,
+                                                Action actionForNode) {
+        Status status;
+        try {
+            InetAddress inetAddress = InetAddress.getByName(address);
+            status = routingProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     routingProvider.programRouterInterface(dpid, sourceSegmentationId, destinationSegmentationId,
+                                                            macAddress, inetAddress, mask, actionForNode);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            LOG.debug("programRouterInterfaceStage2 {} for mac:{} addr:{}/{} node:{} srcTunId:{} destTunId:{} action:{}",
+                         routingProvider == null ? "skipped" : "programmed",
+                         macAddress, address, mask, node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
+                         actionForNode);
+        } else {
+            LOG.error("programRouterInterfaceStage2 failed for mac:{} addr:{}/{} node:{} srcTunId:{} destTunId:{} action:{} status:{}",
+                         macAddress, address, mask, node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
+                         actionForNode, status);
+        }
+        return status;
+    }
+
+    private boolean programIcmpEcho(Long dpid, String segOrOfPort,
+                                           String macAddress, String ipStr,
+                                           Action action) {
+        if (action == DELETE ) {
+            LOG.trace("Deleting Flow : programIcmpEcho dpid {} segOrOfPort {} mac {} ip {} action {}",
+                    dpid, segOrOfPort, macAddress, ipStr, action);
+        }
+        if (action == ADD) {
+            LOG.trace("Adding Flow : programIcmpEcho dpid {} segOrOfPort {} mac {} ip {} action {}",
+                    dpid, segOrOfPort, macAddress, ipStr, action);
+        }
+
+        Status status = new Status(StatusCode.UNSUPPORTED);
+        if (icmpEchoProvider != null){
+            try {
+                InetAddress inetAddress = InetAddress.getByName(ipStr);
+                status = icmpEchoProvider.programIcmpEchoEntry(dpid, segOrOfPort,
+                                                macAddress, inetAddress, action);
+            } catch (UnknownHostException e) {
+                status = new Status(StatusCode.BADREQUEST);
+            }
+        }
+
+        if (status.isSuccess()) {
+            LOG.debug("programIcmpEcho {} for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{}",
+                    icmpEchoProvider == null ? "skipped" : "programmed",
+                    macAddress, ipStr, dpid, segOrOfPort, action);
+        } else {
+            LOG.error("programIcmpEcho failed for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{} status:{}",
+                    macAddress, ipStr, dpid, segOrOfPort, action, status);
+        }
+
+        return status.isSuccess();
+    }
+
+    private boolean programInboundIpRewriteStage1(Long dpid, Long inboundOFPort, String providerSegmentationId,
+                                                  String matchAddress, String rewriteAddress,
+                                                  Action action) {
+        if (action == DELETE ) {
+            LOG.trace("Deleting Flow : programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
+                    " action {}",
+                    dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
+        }
+        if (action == ADD ) {
+            LOG.trace("Adding Flow : programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
+                    " action {}",
+                    dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
+        }
+
+        Status status = programInboundIpRewriteStage2(dpid, inboundOFPort, providerSegmentationId, matchAddress,
+                rewriteAddress, action);
+        return status.isSuccess();
+    }
+
+    private Status programInboundIpRewriteStage2(Long dpid, Long inboundOFPort, String providerSegmentationId,
+                                                 String matchAddress, String rewriteAddress,
+                                                 Action action) {
+        Status status;
+        try {
+            InetAddress inetMatchAddress = InetAddress.getByName(matchAddress);
+            InetAddress inetRewriteAddress = InetAddress.getByName(rewriteAddress);
+            status = inboundNatProvider == null ?
+                    new Status(StatusCode.SUCCESS) :
+                    inboundNatProvider.programIpRewriteRule(dpid, inboundOFPort, providerSegmentationId,
+                            inetMatchAddress, inetRewriteAddress,
+                            action);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            final boolean isSkipped = inboundNatProvider == null;
+            LOG.debug("programInboundIpRewriteStage2 {} for dpid:{} ofPort:{} seg:{} match:{} rewrite:{} action:{}",
+                    isSkipped ? "skipped" : "programmed",
+                    dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
+        } else {
+            LOG.error("programInboundIpRewriteStage2 failed for dpid:{} ofPort:{} seg:{} match:{} rewrite:{} action:{}" +
+                         " status:{}",
+                    dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action,
+                    status);
+        }
+        return status;
+    }
+
+    private void programIpRewriteExclusionStage1(Node node, Long dpid, String providerSegmentationId, String cidr,
+                                                 Action actionForRewriteExclusion) {
+        if (actionForRewriteExclusion == DELETE ) {
+            LOG.trace("Deleting Flow : programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {}",
+                         node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
+        }
+        if (actionForRewriteExclusion == ADD) {
+            LOG.trace("Adding Flow : programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {}",
+                         node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
+        }
+
+        this.programIpRewriteExclusionStage2(node, dpid, providerSegmentationId, cidr,actionForRewriteExclusion);
+    }
+
+    private Status programIpRewriteExclusionStage2(Node node, Long dpid, String providerSegmentationId, String cidr,
+                                                   Action actionForNode) {
+        final Status status = outboundNatProvider == null ? new Status(StatusCode.SUCCESS) :
+                outboundNatProvider.programIpRewriteExclusion(dpid, providerSegmentationId, cidr, actionForNode);
+
+        if (status.isSuccess()) {
+            final boolean isSkipped = outboundNatProvider == null;
+            LOG.debug("IpRewriteExclusion {} for cidr:{} node:{} action:{}",
+                         isSkipped ? "skipped" : "programmed",
+                         cidr, node.getNodeId().getValue(), actionForNode);
+        } else {
+            LOG.error("IpRewriteExclusion failed for cidr:{} node:{} action:{} status:{}",
+                         cidr, node.getNodeId().getValue(), actionForNode, status);
+        }
+        return status;
+    }
+
+    private void programOutboundIpRewriteStage1(FloatIpData fid, Action action) {
+
+        if (action == DELETE) {
+            LOG.trace("Deleting Flow : programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} ",
+                    fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
+        }
+        if (action == ADD) {
+            LOG.trace("Adding Flow : programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} " ,
+                    fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
+        }
+
+        this.programOutboundIpRewriteStage2(fid, action);
+    }
+
+    private Status programOutboundIpRewriteStage2(FloatIpData fid, Action action) {
+        Status status;
+        try {
+            InetAddress matchSrcAddress = InetAddress.getByName(fid.fixedIpAddress);
+            InetAddress rewriteSrcAddress = InetAddress.getByName(fid.floatingIpAddress);
+            status = outboundNatProvider == null ?
+                    new Status(StatusCode.SUCCESS) :
+                    outboundNatProvider.programIpRewriteRule(
+                            fid.dpid, fid.segId, fid.neutronRouterMac, matchSrcAddress, fid.macAddress,
+                            this.externalRouterMac, rewriteSrcAddress, fid.ofPort, action);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            final boolean isSkipped = outboundNatProvider == null;
+            LOG.debug("programOutboundIpRewriteStage2 {} for dpid {} seg {} fixedIpAddress {} floatIp {}" +
+                            " action {}",
+                         isSkipped ? "skipped" : "programmed",
+                         fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
+        } else {
+            LOG.error("programOutboundIpRewriteStage2 failed for dpid {} seg {} fixedIpAddress {} floatIp {}" +
+                         " action {} status:{}",
+                         fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action, status);
+        }
+        return status;
+    }
+
+    private int getMaskLenFromCidr(String cidr) {
+        if (cidr == null) {
+            return 0;
+        }
+        String[] splits = cidr.split("/");
+        if (splits.length != 2) {
+            return 0;
+        }
+
+        int result;
+        try {
+            result = Integer.parseInt(splits[1].trim());
+        } catch (NumberFormatException nfe) {
+            result = 0;
+        }
+        return result;
+    }
+
+    private Long getDpidForIntegrationBridge(Node node) {
+        // Check if node is integration bridge; and only then return its dpid
+        if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
+            return southbound.getDataPathId(node);
+        }
+        return null;
+    }
+
+    private Long getDpidForExternalBridge(Node node) {
+        // Check if node is external bridge; and only then return its dpid
+        if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
+            return southbound.getDataPathId(node);
+        }
+        return null;
+    }
+
+    private Node getExternalBridgeNode(){
+        //Pickup the first node that has external bridge (br-ex).
+        //NOTE: We are assuming that all the br-ex are serving one external network and gateway ip of
+        //the external network is reachable from every br-ex
+        // TODO: Consider other deployment scenario, and thing of better solution.
+        List<Node> allBridges = nodeCacheManager.getBridgeNodes();
+        for(Node node : allBridges){
+            if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private NeutronSubnet getExternalNetworkSubnet(NeutronPort gatewayPort){
+        if (gatewayPort.getFixedIPs() == null) {
+            return null;
+        }
+        for (Neutron_IPs neutronIPs : gatewayPort.getFixedIPs()) {
+            String subnetUUID = neutronIPs.getSubnetUUID();
+            NeutronSubnet extSubnet = neutronSubnetCache.getSubnet(subnetUUID);
+            if (extSubnet != null && extSubnet.getGatewayIP() != null) {
+                return extSubnet;
+            }
+            if (extSubnet == null) {
+                // TODO: when subnet is created, try again.
+                LOG.debug("subnet {} in not found", subnetUUID);
+             }
+        }
+        return null;
+    }
+
+    private void cleanupFloatingIPRules(final NeutronPort neutronPort) {
+
+        List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
+        if (neutronFloatingIps != null && !neutronFloatingIps.isEmpty()) {
+            for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
+                if (neutronFloatingIP.getPortUUID().equals(neutronPort.getPortUUID())) {
+                    handleNeutronFloatingIPEvent(neutronFloatingIP, DELETE);
+                }
+            }
+        }
+    }
+
+    private void updateFloatingIPRules(final NeutronPort neutronPort) {
+        List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
+        if (neutronFloatingIps != null) {
+            for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
+                if (neutronFloatingIP.getPortUUID().equals(neutronPort.getPortUUID())) {
+                    handleNeutronFloatingIPEvent(neutronFloatingIP, UPDATE);
+                }
+            }
+        }
+    }
+
+
+    private void triggerGatewayMacResolver(final NeutronPort gatewayPort){
+
+        Preconditions.checkNotNull(gatewayPort);
+        NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(gatewayPort.getNetworkUUID());
+
+        if(externalNetwork != null){
+            if(externalNetwork.isRouterExternal()){
+                final NeutronSubnet externalSubnet = getExternalNetworkSubnet(gatewayPort);
+
+                // TODO: address IPv6 case.
+                if (externalSubnet != null &&
+                        externalSubnet.getIpVersion() == 4 &&
+                        gatewayPort.getFixedIPs() != null) {
+                    LOG.info("Trigger MAC resolution for gateway ip {}", externalSubnet.getGatewayIP());
+                    Neutron_IPs neutronIP = null;
+                    for (Neutron_IPs nIP : gatewayPort.getFixedIPs()) {
+                        InetAddress ipAddress;
+                        try {
+                            ipAddress = InetAddress.getByName(nIP.getIpAddress());
+                        } catch (UnknownHostException e) {
+                            LOG.warn("unknown host exception {}", e);
+                            continue;
+                        }
+                        if (ipAddress instanceof Inet4Address) {
+                            neutronIP = nIP;
+                            break;
+                        }
+                    }
+                    if (neutronIP == null) {
+                        // TODO IPv6 neighbor discovery
+                        LOG.debug("Ignoring gateway ports with IPv6 only fixed ip {}",
+                                  gatewayPort.getFixedIPs());
+                    } else {
+                        gatewayMacResolver.resolveMacAddress(
+                            this, /* gatewayMacResolverListener */
+                            null, /* externalNetworkBridgeDpid */
+                            true, /* refreshExternalNetworkBridgeDpidIfNeeded */
+                            new Ipv4Address(externalSubnet.getGatewayIP()),
+                            new Ipv4Address(neutronIP.getIpAddress()),
+                            new MacAddress(gatewayPort.getMacAddress()),
+                            true /* periodicRefresh */);
+                    }
+                } else {
+                    LOG.warn("No gateway IP address found for external network {}", externalNetwork);
+                }
+            }
+        }else{
+            LOG.warn("Neutron network not found for router interface {}", gatewayPort);
+        }
+    }
+
+
+    private void storePortInCleanupCache(NeutronPort port) {
+        this.portCleanupCache.put(port.getPortUUID(),port);
+    }
+
+
+    private void updatePortInCleanupCache(NeutronPort updatedPort,NeutronPort originalPort) {
+        removePortFromCleanupCache(originalPort);
+        storePortInCleanupCache(updatedPort);
+    }
+
+    public void removePortFromCleanupCache(NeutronPort port) {
+        if(port != null) {
+            this.portCleanupCache.remove(port.getPortUUID());
+        }
+    }
+
+    public Map<String, NeutronPort> getPortCleanupCache() {
+        return this.portCleanupCache;
+    }
+
+    public NeutronPort getPortFromCleanupCache(String portid) {
+        for (String neutronPortUuid : this.portCleanupCache.keySet()) {
+            if (neutronPortUuid.equals(portid)) {
+                LOG.info("getPortFromCleanupCache: Matching NeutronPort found {}", portid);
+                return this.portCleanupCache.get(neutronPortUuid);
+            }
+        }
+        return null;
+    }
+
+    private void storeNetworkInCleanupCache(NeutronNetwork network) {
+        this.networkCleanupCache.put(network.getNetworkUUID(), network);
+    }
+
+
+    private void updateNetworkInCleanupCache(NeutronNetwork network) {
+        for (String neutronNetworkUuid:this.networkCleanupCache.keySet()) {
+            if (neutronNetworkUuid.equals(network.getNetworkUUID())) {
+                this.networkCleanupCache.remove(neutronNetworkUuid);
+            }
+        }
+        this.networkCleanupCache.put(network.getNetworkUUID(), network);
+    }
+
+    public void removeNetworkFromCleanupCache(String networkid) {
+        NeutronNetwork network = null;
+        for (String neutronNetworkUuid:this.networkCleanupCache.keySet()) {
+            if (neutronNetworkUuid.equals(networkid)) {
+                network = networkCleanupCache.get(neutronNetworkUuid);
+                break;
+            }
+        }
+        if (network != null) {
+            for (String neutronPortUuid:this.portCleanupCache.keySet()) {
+                if (this.portCleanupCache.get(neutronPortUuid).getNetworkUUID().equals(network.getNetworkUUID())) {
+                    LOG.info("This network is used by another port", network);
+                    return;
+                }
+            }
+            this.networkCleanupCache.remove(network.getNetworkUUID());
+        }
+    }
+
+    public Map<String, NeutronNetwork> getNetworkCleanupCache() {
+        return this.networkCleanupCache;
+    }
+
+    public NeutronNetwork getNetworkFromCleanupCache(String networkid) {
+        for (String neutronNetworkUuid:this.networkCleanupCache.keySet()) {
+            if (neutronNetworkUuid.equals(networkid)) {
+                LOG.info("getPortFromCleanupCache: Matching NeutronPort found {}", networkid);
+                return networkCleanupCache.get(neutronNetworkUuid);
+            }
+        }
+        return null;
+    }
+    /**
+     * Return String that represents OF port with marker explicitly provided (reverse of MatchUtils:parseExplicitOFPort)
+     *
+     * @param ofPort the OF port number
+     * @return the string with encoded OF port (example format "OFPort|999")
+     */
+    public static String encodeExcplicitOFPort(Long ofPort) {
+        return "OFPort|" + ofPort.toString();
+    }
+    private void initNetworkCleanUpCache() {
+        if (this.neutronNetworkCache != null) {
+            for (NeutronNetwork neutronNetwork : neutronNetworkCache.getAllNetworks()) {
+                networkCleanupCache.put(neutronNetwork.getNetworkUUID(), neutronNetwork);
+            }
+        }
+    }
+    private void initPortCleanUpCache() {
+        if (this.neutronPortCache != null) {
+            for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
+                portCleanupCache.put(neutronPort.getPortUUID(), neutronPort);
+            }
+        }
+    }
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        arpProvider =
+                (ArpProvider) ServiceHelper.getGlobalInstance(ArpProvider.class, this);
+        inboundNatProvider =
+                (InboundNatProvider) ServiceHelper.getGlobalInstance(InboundNatProvider.class, this);
+        outboundNatProvider =
+                (OutboundNatProvider) ServiceHelper.getGlobalInstance(OutboundNatProvider.class, this);
+        routingProvider =
+                (RoutingProvider) ServiceHelper.getGlobalInstance(RoutingProvider.class, this);
+        l3ForwardingProvider =
+                (L3ForwardingProvider) ServiceHelper.getGlobalInstance(L3ForwardingProvider.class, this);
+        distributedArpService =
+                 (DistributedArpService) ServiceHelper.getGlobalInstance(DistributedArpService.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        gatewayMacResolver =
+                (GatewayMacResolver) ServiceHelper.getGlobalInstance(GatewayMacResolver.class, this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
+
+        initL3AdapterMembers();
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+            initNetworkCleanUpCache();
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+            initPortCleanUpCache();
+        } else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD)impl;
+        } else if (impl instanceof INeutronFloatingIPCRUD) {
+            neutronFloatingIpCache = (INeutronFloatingIPCRUD)impl;
+        } else if (impl instanceof ArpProvider) {
+            arpProvider = (ArpProvider)impl;
+        } else if (impl instanceof InboundNatProvider) {
+            inboundNatProvider = (InboundNatProvider)impl;
+        } else if (impl instanceof OutboundNatProvider) {
+            outboundNatProvider = (OutboundNatProvider)impl;
+        } else if (impl instanceof RoutingProvider) {
+            routingProvider = (RoutingProvider)impl;
+        } else if (impl instanceof L3ForwardingProvider) {
+            l3ForwardingProvider = (L3ForwardingProvider)impl;
+        }else if (impl instanceof GatewayMacResolver) {
+            gatewayMacResolver = (GatewayMacResolver)impl;
+        }else if (impl instanceof IcmpEchoProvider) {
+            icmpEchoProvider = (IcmpEchoProvider)impl;
+        }
+
+        populateL3ForwardingCaches();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NodeCacheManagerImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NodeCacheManagerImpl.java
new file mode 100644 (file)
index 0000000..0ef05ba
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.netvirt.openstack.netvirt.NodeCacheManagerEvent;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Flavio Fernandes (ffernand@redhat.com)
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class NodeCacheManagerImpl extends AbstractHandler implements NodeCacheManager, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(NodeCacheManagerImpl.class);
+    private Map<NodeId, Node> nodeCache = new ConcurrentHashMap<>();
+    private Map<Long, NodeCacheListener> handlers = Maps.newHashMap();
+    private volatile Southbound southbound;
+
+    @Override
+    public void nodeAdded(Node node) {
+        LOG.debug("nodeAdded: {}", node);
+        enqueueEvent(new NodeCacheManagerEvent(node, Action.UPDATE));
+    }
+
+    @Override
+    public void nodeRemoved(Node node) {
+        LOG.debug("nodeRemoved: {}", node);
+        enqueueEvent(new NodeCacheManagerEvent(node, Action.DELETE));
+    }
+
+    // TODO SB_MIGRATION
+    // might need to break this into two different events
+    // notifyOvsdbNode, notifyBridgeNode or just make sure the
+    // classes implementing the interface check for ovsdbNode or bridgeNode
+    private void processNodeUpdate(Node node) {
+        Action action = Action.UPDATE;
+
+        NodeId nodeId = node.getNodeId();
+        if (nodeCache.get(nodeId) == null) {
+            action = Action.ADD;
+        }
+        nodeCache.put(nodeId, node);
+
+        LOG.debug("processNodeUpdate: size= {}, Node type= {}, action= {}, node= {}",
+                nodeCache.size(),
+                southbound.getBridge(node) != null ? "BridgeNode" : "OvsdbNode",
+                action == Action.ADD ? "ADD" : "UPDATE",
+                node);
+
+        for (NodeCacheListener handler : handlers.values()) {
+            try {
+                handler.notifyNode(node, action);
+            } catch (Exception e) {
+                LOG.error("Failed notifying node add event", e);
+            }
+        }
+        LOG.debug("processNodeUpdate returns");
+    }
+
+    private void processNodeRemoved(Node node) {
+        nodeCache.remove(node.getNodeId());
+        for (NodeCacheListener handler : handlers.values()) {
+            try {
+                handler.notifyNode(node, Action.DELETE);
+            } catch (Exception e) {
+                LOG.error("Failed notifying node remove event", e);
+            }
+        }
+        LOG.warn("processNodeRemoved returns");
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NodeCacheManagerEvent)) {
+            LOG.error("Unable to process abstract event {}", abstractEvent);
+            return;
+        }
+        NodeCacheManagerEvent ev = (NodeCacheManagerEvent) abstractEvent;
+        LOG.debug("NodeCacheManagerImpl: dequeue: {}", ev);
+        switch (ev.getAction()) {
+            case DELETE:
+                processNodeRemoved(ev.getNode());
+                break;
+            case UPDATE:
+                processNodeUpdate(ev.getNode());
+                break;
+            default:
+                LOG.warn("Unable to process event action {}", ev.getAction());
+                break;
+        }
+    }
+
+    public void cacheListenerAdded(final ServiceReference ref, NodeCacheListener handler){
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        handlers.put(pid, handler);
+        LOG.info("Node cache listener registered, pid {} {}", pid, handler.getClass().getName());
+    }
+
+    public void cacheListenerRemoved(final ServiceReference ref){
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        handlers.remove(pid);
+        LOG.debug("Node cache listener unregistered, pid {}", pid);
+    }
+
+    @Override
+    public Map<NodeId,Node> getOvsdbNodes() {
+        Map<NodeId,Node> ovsdbNodesMap = new ConcurrentHashMap<>();
+        for (Map.Entry<NodeId, Node> ovsdbNodeEntry : nodeCache.entrySet()) {
+            if (southbound.extractOvsdbNode(ovsdbNodeEntry.getValue()) != null) {
+                ovsdbNodesMap.put(ovsdbNodeEntry.getKey(), ovsdbNodeEntry.getValue());
+            }
+        }
+        return ovsdbNodesMap;
+    }
+
+    @Override
+    public List<Node> getBridgeNodes() {
+        List<Node> nodes = Lists.newArrayList();
+        for (Node node : nodeCache.values()) {
+            if (southbound.getBridge(node) != null) {
+                nodes.add(node);
+            }
+        }
+        return nodes;
+    }
+
+    @Override
+    public List <Long> getBridgeDpids(final String bridgeName) {
+        List<Long> dpids = Lists.newArrayList();
+        for (Node node : nodeCache.values()) {
+            if (bridgeName == null || southbound.getBridge(node, bridgeName) != null) {
+                long dpid = southbound.getDataPathId(node);
+                if (dpid != 0L) {
+                    dpids.add(Long.valueOf(dpid));
+                }
+            }
+        }
+        return dpids;
+    }
+
+    @Override
+    public List<Node> getNodes() {
+        List<Node> nodes = Lists.newArrayList();
+        for (Node node : nodeCache.values()) {
+            nodes.add(node);
+        }
+        return nodes;
+    }
+
+    private void populateNodeCache() {
+        LOG.debug("populateNodeCache : Populating the node cache");
+        List<Node> nodes = southbound.readOvsdbTopologyNodes();
+        for(Node ovsdbNode : nodes) {
+            this.nodeCache.put(ovsdbNode.getNodeId(), ovsdbNode);
+        }
+        nodes = southbound.readOvsdbTopologyBridgeNodes();
+        for(Node bridgeNode : nodes) {
+            this.nodeCache.put(bridgeNode.getNodeId(), bridgeNode);
+        }
+        LOG.debug("populateNodeCache : Node cache population is done. Total nodes : {}",this.nodeCache.size());
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+        populateNodeCache();
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OpenstackRouter.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OpenstackRouter.java
new file mode 100644 (file)
index 0000000..4325c0d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.impl;
+
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.MultiTenantAwareRouter;
+
+import java.net.InetAddress;
+import java.util.UUID;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * OpenStack router implements the MultiTenantAwareRouter interfaces It provides routing functionality for multiple
+ * tenants in an OpenStack cloud
+ */
+public class OpenstackRouter implements MultiTenantAwareRouter, ConfigInterface {
+
+    @Override
+    public void addInterface(UUID tenantId, String interfaceName, InetAddress address, int mask) {
+
+    }
+
+    @Override
+    public void addInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask) {
+
+    }
+
+    @Override
+    public void updateInterface(UUID tenantId, String interfaceName, InetAddress address, int mask) {
+
+    }
+
+    @Override
+    public void updateInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask) {
+
+    }
+
+    @Override
+    public void removeInterface(UUID tenantId, String interfaceName) {
+
+    }
+
+    @Override
+    public void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop) {
+
+    }
+
+    @Override
+    public void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority) {
+
+    }
+
+    @Override
+    public void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop) {
+
+    }
+
+    @Override
+    public void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority) {
+
+    }
+
+    @Override
+    public void addDefaultRoute(UUID tenantId, InetAddress nextHop) {
+
+    }
+
+    @Override
+    public void addDefaultRoute(UUID tenantId, InetAddress nextHop, Integer priority) {
+
+    }
+
+    @Override
+    public void addNatRule(UUID tenantId, InetAddress matchAddress, InetAddress rewriteAddress) {
+
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbDataChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbDataChangeListener.java
new file mode 100644 (file)
index 0000000..f5b9770
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.impl;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.MdsalHelper;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+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;
+
+/**
+ * MDSAL dataChangeListener for the OVSDB Southbound
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class OvsdbDataChangeListener implements ClusteredDataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbDataChangeListener.class);
+    private DataBroker dataBroker = null;
+    private ListenerRegistration<DataChangeListener> registration;
+    private final ExecutorService executorService = Executors.newFixedThreadPool(1);
+
+    public OvsdbDataChangeListener (DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    public void start() {
+        InstanceIdentifier<Node> path = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(MdsalHelper.OVSDB_TOPOLOGY_ID))
+                .child(Node.class);
+        registration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, this,
+                DataChangeScope.SUBTREE);
+        LOG.info("netvirt OvsdbDataChangeListener: dataBroker= {}, registration= {}",
+                dataBroker, registration);
+        triggerUpdates();
+    }
+
+    @Override
+    public void close () throws Exception {
+        registration.close();
+        executorService.shutdown();
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        executorService.submit(new Runnable(){
+
+            @Override
+            public void run() {
+                LOG.trace(">>>>> onDataChanged: {}", changes);
+                processOvsdbConnections(changes);
+                processOvsdbConnectionAttributeUpdates(changes);
+                processBridgeCreation(changes);
+                processBridgeUpdate(changes);
+                processPortCreation(changes);
+                processPortUpdate(changes);
+                processPortDeletion(changes);
+                processBridgeDeletion(changes);
+                processOvsdbDisconnect(changes);
+            }
+        });
+    }
+
+    private void processOvsdbConnections(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> created : changes.getCreatedData().entrySet()) {
+            if (created.getValue() instanceof OvsdbNodeAugmentation) {
+                Node ovsdbNode = getNode(changes.getCreatedData(), created);
+                LOG.trace("processOvsdbConnections: <{}>, ovsdbNode: <{}>", created, ovsdbNode);
+                ovsdbUpdate(ovsdbNode, created.getValue(), OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
+            }
+        }
+    }
+
+    private void processOvsdbDisconnect(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for(InstanceIdentifier<?> removedOvsdbNode : changes.getRemovedPaths()) {
+            if(removedOvsdbNode.getTargetType().equals(OvsdbNodeAugmentation.class)){
+                //Get top node to get details of all the bridge/termination point augmentation
+                // in case we want to do any cleanup task while processing node disconnection
+                Node parentNode = getNode(changes.getOriginalData(), removedOvsdbNode);
+                if(parentNode == null){
+                    //Throwing this warning in case behavior of southbound plugin changes.
+                    LOG.warn("OvsdbNode's {} parent node details are not present in original data,"
+                            + " it should not happen", parentNode);
+                    continue;
+                }
+                //Fetch data of removed connection info from original data
+                @SuppressWarnings("unchecked")
+                OvsdbNodeAugmentation removedOvsdbNodeAugmentationData = getDataChanges(changes.getOriginalData(),
+                        (InstanceIdentifier<OvsdbNodeAugmentation>) removedOvsdbNode);
+
+                LOG.trace("processOvsdbDisconnect: {} ", removedOvsdbNode);
+                ////Assuming Openvswitch type represent the ovsdb node connection and not OvsdbType.NODE
+
+                ovsdbUpdate(parentNode, removedOvsdbNodeAugmentationData,
+                        OvsdbInventoryListener.OvsdbType.NODE, Action.DELETE);
+            }
+        }
+    }
+
+    private void processOvsdbConnectionAttributeUpdates(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for(Map.Entry<InstanceIdentifier<?>, DataObject> updatedOvsdbNode : changes.getUpdatedData().entrySet()){
+            if(updatedOvsdbNode.getKey().getTargetType().equals(OvsdbNodeAugmentation.class)){
+                LOG.trace("processOvsdbConnectionAttributeUpdates: {}", updatedOvsdbNode);
+                /* XXX (NOTE): Till now we don't really need the old ovsdb connection attributes data before update.
+                 * I am passing the updated data of both Node and resource augmentation data (connection attributes).
+                 * If in future we need old OvsdbNodeAugmentation attributes data, we will extract it from
+                 * original data and pass it as a resourceAugmentationData.
+                 */
+                Node parentNode  = getNode(changes.getUpdatedData(), updatedOvsdbNode);
+                if (parentNode == null) {
+                    // Logging this warning, to catch any change in southbound plugin's behavior.
+                    LOG.warn("Parent Node for OvsdbNodeAugmentation is not found. On OvsdbNodeAugmentation update "
+                            + "data store must provide the parent node update. This condition should not occur "
+                            + "with the existing models defined in southbound plugin." );
+                    continue;
+                }
+                LOG.trace("processOvsdbConnectionAttributeUpdates <{}> related update on Node: <{}>",
+                        updatedOvsdbNode.getValue(), parentNode);
+
+                ovsdbUpdate(parentNode, updatedOvsdbNode.getValue(),
+                        OvsdbInventoryListener.OvsdbType.NODE, Action.UPDATE);
+            }
+        }
+    }
+
+    private void processPortCreation(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        for(Map.Entry<InstanceIdentifier<?>, DataObject> newPort : changes.getCreatedData().entrySet()){
+            if(newPort.getKey().getTargetType().equals(OvsdbTerminationPointAugmentation.class)){
+                //LOG.trace("processPortCreation: {}", newPort);
+                //If user created termination point only, Node will get updated
+                Node tpParentNode  = getNode(changes.getUpdatedData(), newPort);
+                if(tpParentNode == null){
+                    //If user created port with the bridge itself, Node will be in created data
+                    tpParentNode = getNode(changes.getCreatedData(),newPort);
+                }
+                if(tpParentNode == null){
+                    // Logging this warning, to make sure we didn't change anything
+                    // in southbound plugin that changes this behavior.
+                    LOG.warn("Parent Node for port is not found. Port creation must create or "
+                            + "update the Node. This condition should not occur." );
+                    continue;
+                }
+
+                LOG.trace("processPortCreation <{}> creation on Node <{}>", newPort.getValue(), tpParentNode);
+                ovsdbUpdate(tpParentNode, newPort.getValue(),OvsdbInventoryListener.OvsdbType.PORT, Action.ADD);
+            }
+        }
+    }
+
+    private void processPortDeletion(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for(InstanceIdentifier<?> removedPort : changes.getRemovedPaths()) {
+            if(removedPort.getTargetType().equals(OvsdbTerminationPointAugmentation.class)){
+                Node tpParentNode = getNode(changes.getOriginalData(), removedPort);
+                if(tpParentNode == null){
+                    //Throwing this warning in case behavior of southbound plugin changes.
+                    LOG.warn("Port's {} parent node details are not present in original data, "
+                            + "it should not happen", removedPort);
+                    continue;
+                }
+                //Fetch data of removed port from original data
+                @SuppressWarnings("unchecked")
+                OvsdbTerminationPointAugmentation removedTPAugmentationData = getDataChanges(changes.getOriginalData(),
+                        (InstanceIdentifier<OvsdbTerminationPointAugmentation>)removedPort);
+
+                LOG.trace("processPortDeletion <{}> deletion on Node <{}>", removedPort, tpParentNode);
+                ovsdbUpdate(tpParentNode, removedTPAugmentationData,
+                        OvsdbInventoryListener.OvsdbType.PORT, Action.DELETE);
+            }
+        }
+    }
+
+    private void processPortUpdate(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> updatedPort : changes.getUpdatedData().entrySet()){
+            if (updatedPort.getKey().getTargetType().equals(OvsdbTerminationPointAugmentation.class)){
+                //LOG.trace("processPortUpdate: <{}>", updatedPort);
+                /* XXX (NOTE): Till now we don't really need the old termination point data before update.
+                 * I am passing the updated data of both Node and resource augmentation data (termination-point).
+                 * If in future we need old TerminationPointAugmentation data, we will extract it from
+                 * original data and pass it as a resourceAugmentationData.
+                 */
+                Node tpParentNode  = getNode(changes.getUpdatedData(),updatedPort);
+                if (tpParentNode == null){
+                    // Logging this warning, to catch any change in southbound plugin's behavior.
+                    LOG.warn("Parent Node for port is not found. On Port/Interface update data store"
+                            + " must provide the parent node update. This condition should not occure "
+                            + "with the existing models define in southbound plugin." );
+                    continue;
+                }
+
+                LOG.trace("processPortUpdate <{}> update on Node <{}>", updatedPort.getValue(), tpParentNode);
+                ovsdbUpdate(tpParentNode, updatedPort.getValue(),
+                        OvsdbInventoryListener.OvsdbType.PORT, Action.UPDATE);
+            }
+        }
+    }
+
+    private void processBridgeCreation(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for(Map.Entry<InstanceIdentifier<?>, DataObject> newBridge : changes.getCreatedData().entrySet()){
+            if(newBridge.getKey().getTargetType().equals(OvsdbBridgeAugmentation.class)){
+                //LOG.trace("processBridgeCreation <{}>", newBridge);
+                //Bridge augmentation happens directly on the Node so Node details should also exist in created data.
+                Node bridgeParentNode  = getNode(changes.getCreatedData(),newBridge);
+                if(bridgeParentNode == null){
+                    // Logging this warning, to catch any change in southbound plugin behavior
+                    LOG.warn("Parent Node for bridge is not found. Bridge creation must provide the Node "
+                            + "details in create Data Changes. This condition should not occur." );
+                    continue;
+                }
+                LOG.trace("processBridgeCreation <{}> creation on Node <{}>", newBridge.getValue(), bridgeParentNode);
+                ovsdbUpdate(bridgeParentNode, newBridge.getValue(),
+                        OvsdbInventoryListener.OvsdbType.BRIDGE, Action.ADD);
+            }
+        }
+    }
+
+    private void processBridgeUpdate(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> updatedBridge : changes.getUpdatedData().entrySet()) {
+            if(updatedBridge.getKey().getTargetType().equals(OvsdbBridgeAugmentation.class)){
+                //LOG.trace("processBridgeUpdate <{}>", updatedBridge);
+                /* XXX (NOTE): Till now we don't really need the old bridge data before update.
+                 * I am passing the updated data of both Node and resource augmentation data.
+                 * If in future we need old bridgeAugmentationData, we will extract it from
+                 * original data and pass it as a resourceAugmentationData.
+                 */
+
+                Node bridgeParentNode = getNode(changes.getUpdatedData(), updatedBridge);
+                if(bridgeParentNode == null){
+                    // Logging this warning, to catch any change in southbound plugin behavior
+                    LOG.warn("Parent Node for bridge is not found. Bridge update must provide the Node "
+                            + "details in updated Data Changes. This condition should not occure" );
+                    continue;
+                }
+                LOG.trace("processBridgeUpdate <{}> update on Node <{}>", updatedBridge.getValue(), bridgeParentNode);
+                ovsdbUpdate(bridgeParentNode, updatedBridge.getValue(),
+                        OvsdbInventoryListener.OvsdbType.BRIDGE, Action.UPDATE);
+            }
+        }
+    }
+
+    private void processBridgeDeletion(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+
+        for(InstanceIdentifier<?> removedBridge : changes.getRemovedPaths()) {
+            if(removedBridge.getTargetType().equals(OvsdbBridgeAugmentation.class)){
+                Node bridgeParentNode = getNode(changes.getOriginalData(), removedBridge);
+                if(bridgeParentNode == null){
+                    //Throwing this warning to catch the behavior change of southbound plugin.
+                    LOG.warn("Bridge's {} parent node details are not present in original data"
+                            + ", it should not happen", removedBridge);
+                    continue;
+                }
+                //Fetch data of removed bridge from original data
+                @SuppressWarnings("unchecked")
+                OvsdbBridgeAugmentation removedBridgeAugmentationData = getDataChanges(changes.getOriginalData(),
+                        (InstanceIdentifier<OvsdbBridgeAugmentation>) removedBridge);
+
+                LOG.debug("processBridgeDeletion <{}> deletion on Node <{}>", removedBridge,bridgeParentNode);
+                ovsdbUpdate(bridgeParentNode, removedBridgeAugmentationData,
+                        OvsdbInventoryListener.OvsdbType.BRIDGE, Action.DELETE);
+            }
+        }
+    }
+
+    private Node getNode(Map<InstanceIdentifier<?>, DataObject> changes,
+                         Map.Entry<InstanceIdentifier<?>, DataObject> change) {
+        InstanceIdentifier<Node> nodeInstanceIdentifier = change.getKey().firstIdentifierOf(Node.class);
+        return (Node)changes.get(nodeInstanceIdentifier);
+    }
+
+    private Node getNode(Map<InstanceIdentifier<?>, DataObject> changes,InstanceIdentifier<?> path) {
+        InstanceIdentifier<Node> nodeInstanceIdentifier = path.firstIdentifierOf(Node.class);
+        return (Node)changes.get(nodeInstanceIdentifier);
+    }
+
+    private <T extends DataObject> T getDataChanges(
+            Map<InstanceIdentifier<?>, DataObject> changes,InstanceIdentifier<T> path){
+
+        for(Map.Entry<InstanceIdentifier<?>,DataObject> change : changes.entrySet()){
+            if(change.getKey().getTargetType().equals(path.getTargetType())){
+                @SuppressWarnings("unchecked")
+                T dataObject = (T) change.getValue();
+                return dataObject;
+            }
+        }
+        return null;
+    }
+
+    private void ovsdbUpdate(Node node, DataObject resourceAugmentationDataChanges,
+            OvsdbInventoryListener.OvsdbType ovsdbType, Action action) {
+
+        Set<OvsdbInventoryListener> ovsdbInventoryListeners = OvsdbInventoryServiceImpl.getOvsdbInventoryListeners();
+        for (OvsdbInventoryListener ovsdbInventoryListener : ovsdbInventoryListeners) {
+            ovsdbInventoryListener.ovsdbUpdate(node, resourceAugmentationDataChanges, ovsdbType, action);
+        }
+    }
+
+    private void triggerUpdates() {
+        Set<OvsdbInventoryListener> ovsdbInventoryListeners = OvsdbInventoryServiceImpl.getOvsdbInventoryListeners();
+        for (OvsdbInventoryListener ovsdbInventoryListener : ovsdbInventoryListeners) {
+            ovsdbInventoryListener.triggerUpdates();
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbInventoryServiceImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbInventoryServiceImpl.java
new file mode 100644 (file)
index 0000000..aa82c13
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.impl;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+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.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronRouterChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronSecurityRuleDataChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.ClusterAwareMdsalUtils;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.NetvirtProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronFloatingIPChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronNetworkChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronPortChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronSubnetChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolChangeListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolMemberChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * OvsdbInventoryServiceImpl is the implementation for {@link OvsdbInventoryService}
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class OvsdbInventoryServiceImpl implements ConfigInterface, OvsdbInventoryService {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbInventoryServiceImpl.class);
+    private static DataBroker dataBroker = null;
+    private static Set<OvsdbInventoryListener> ovsdbInventoryListeners = Sets.newCopyOnWriteArraySet();
+    private OvsdbDataChangeListener ovsdbDataChangeListener = null;
+    private static ClusterAwareMdsalUtils mdsalUtils = null;
+
+    public OvsdbInventoryServiceImpl(ProviderContext providerContext) {
+        dataBroker = providerContext.getSALService(DataBroker.class);
+        LOG.info("OvsdbInventoryServiceImpl initialized");
+        ovsdbDataChangeListener = new OvsdbDataChangeListener(dataBroker);
+        mdsalUtils = new ClusterAwareMdsalUtils(dataBroker);
+    }
+
+    @Override
+    public void listenerAdded(OvsdbInventoryListener listener) {
+        ovsdbInventoryListeners.add(listener);
+        LOG.info("listenerAdded: {}", listener);
+    }
+
+    @Override
+    public void listenerRemoved(OvsdbInventoryListener listener) {
+        ovsdbInventoryListeners.remove(listener);
+        LOG.info("listenerRemoved: {}", listener);
+    }
+
+    @Override
+    public void providersReady() {
+        ovsdbDataChangeListener.start();
+        initializeNeutronModelsDataChangeListeners(dataBroker);
+        initializeNetvirtTopology();
+    }
+
+    public static Set<OvsdbInventoryListener> getOvsdbInventoryListeners() {
+        return ovsdbInventoryListeners;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {}
+
+    @Override
+    public void setDependencies(Object impl) {}
+
+    private void initializeNetvirtTopology() {
+        while(!NetvirtProvider.isMasterElected()){
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                LOG.warn("Netvirt thread waiting on Netvirt Ownership Election is interrupted");
+            }
+        }
+        final TopologyId topologyId = new TopologyId(new Uri(Constants.NETVIRT_TOPOLOGY_ID));
+        InstanceIdentifier<Topology> path =
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+        TopologyBuilder tpb = new TopologyBuilder();
+        tpb.setTopologyId(topologyId);
+        if (! mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, path, tpb.build())) {
+            LOG.error("Error initializing netvirt topology");
+        }
+    }
+
+    private void initializeNeutronModelsDataChangeListeners(
+            DataBroker db) {
+        new NeutronNetworkChangeListener(db);
+        new NeutronSubnetChangeListener(db);
+        new NeutronPortChangeListener(db);
+        new NeutronRouterChangeListener(db);
+        new NeutronFloatingIPChangeListener(db);
+        new NeutronLoadBalancerPoolChangeListener(db);
+        new NeutronLoadBalancerPoolMemberChangeListener(db);
+        new NeutronSecurityRuleDataChangeListener(db);
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/ProviderNetworkManagerImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/ProviderNetworkManagerImpl.java
new file mode 100644 (file)
index 0000000..7c74589
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt.impl;
+
+import java.util.Map;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+
+public class ProviderNetworkManagerImpl implements ConfigInterface, NetworkingProviderManager {
+    private static final Logger LOG = LoggerFactory.getLogger(ProviderNetworkManagerImpl.class);
+    private Map<Long, ProviderEntry> providers = Maps.newHashMap();
+    private Map<Node, NetworkingProvider> nodeToProviderMapping = Maps.newHashMap();
+    private volatile OvsdbInventoryService ovsdbInventoryService;
+
+    @Override
+    public NetworkingProvider getProvider(Node node) {
+        if (nodeToProviderMapping.get(node) != null) {
+            return nodeToProviderMapping.get(node);
+        }
+
+        final String targetVersion = Constants.OPENFLOW13;
+        Predicate<ProviderEntry> providerEntryPredicate = new Predicate<ProviderEntry>() {
+            @Override
+            public boolean apply(ProviderEntry providerEntry) {
+                //ToDo: This should match on southboundProtocol and providerType too
+                return providerEntry.getProperties().get(Constants.OPENFLOW_VERSION_PROPERTY).equals(targetVersion);
+            }
+        };
+
+        Iterable<ProviderEntry> matchingProviders = Iterables.filter(providers.values(), providerEntryPredicate);
+        if (!matchingProviders.iterator().hasNext()) {
+            LOG.error("No providers matching {} found", targetVersion);
+        }
+
+        // Return the first match as only have one matching provider today
+        // ToDo: Tie-breaking logic
+        NetworkingProvider provider = matchingProviders.iterator().next().getProvider();
+        nodeToProviderMapping.put(node, provider);
+        return provider;
+    }
+
+    public void providerAdded(final ServiceReference ref, final NetworkingProvider provider){
+        Map <String, String> properties = Maps.newHashMap();
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        properties.put(Constants.SOUTHBOUND_PROTOCOL_PROPERTY,
+                (String) ref.getProperty(Constants.SOUTHBOUND_PROTOCOL_PROPERTY));
+        properties.put(Constants.OPENFLOW_VERSION_PROPERTY,
+                (String) ref.getProperty(Constants.OPENFLOW_VERSION_PROPERTY));
+        properties.put(Constants.PROVIDER_TYPE_PROPERTY, (String) ref.getProperty(Constants.PROVIDER_TYPE_PROPERTY));
+        providers.put(pid, new ProviderEntry(provider, properties));
+        LOG.info("Neutron Networking Provider Registered: {}, with {} and pid={}",
+                provider.getClass().getName(), properties.toString(), pid);
+
+        ovsdbInventoryService.providersReady();
+    }
+
+    public void providerRemoved(final ServiceReference ref){
+        Long pid = (Long)ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        providers.remove(pid);
+        LOG.info("Neutron Networking Provider Removed: {}", pid);
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        ovsdbInventoryService =
+                (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+
+    private class ProviderEntry {
+        NetworkingProvider provider;
+        Map<String, String> properties;
+
+        ProviderEntry(NetworkingProvider provider, Map<String, String> properties) {
+            this.provider = provider;
+            this.properties = properties;
+        }
+
+        public NetworkingProvider getProvider() {
+            return provider;
+        }
+
+        public Map<String, String> getProperties() {
+            return properties;
+        }
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImpl.java
new file mode 100644 (file)
index 0000000..11bb2a5
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2014, 2015 HP, 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.openstack.netvirt.impl;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * @author Aswin Suryanarayanan.
+ */
+
+public class SecurityGroupCacheManagerImpl implements ConfigInterface, SecurityGroupCacheManger {
+
+    private final Map<String, Set<String>> securityGroupCache = new ConcurrentHashMap<>();
+    private static final Logger LOG = LoggerFactory.getLogger(SecurityGroupCacheManagerImpl.class);
+    private volatile SecurityServicesManager securityServicesManager;
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+
+    @Override
+    public void portAdded(String securityGroupUuid, String portUuid) {
+        LOG.debug("In portAdded securityGroupUuid:" + securityGroupUuid + " portUuid:" + portUuid);
+        NeutronPort port = neutronPortCache.getPort(portUuid);
+        if (port == null) {
+            port = neutronL3Adapter.getPortFromCleanupCache(portUuid);
+            if (port == null) {
+                LOG.error("In portAdded no neutron port found:" + " portUuid:" + portUuid);
+                return;
+            }
+        }
+        processPortAdded(securityGroupUuid,port);
+    }
+
+    @Override
+    public void portRemoved(String securityGroupUuid, String portUuid) {
+        LOG.debug("In portRemoved securityGroupUuid:" + securityGroupUuid + " portUuid:" + portUuid);
+        NeutronPort port = neutronPortCache.getPort(portUuid);
+
+        if (port == null) {
+            port = neutronL3Adapter.getPortFromCleanupCache(portUuid);
+            if (port == null) {
+                LOG.error("In portRemoved no neutron port found:" + " portUuid:" + portUuid);
+                return;
+            }
+        }
+        processPortRemoved(securityGroupUuid,port);
+    }
+
+    @Override
+    public void addToCache(String remoteSgUuid, String portUuid) {
+        LOG.debug("In addToCache remoteSgUuid:" + remoteSgUuid + "portUuid:" + portUuid);
+        Set<String> portList = securityGroupCache.get(remoteSgUuid);
+        if (null == portList) {
+            portList = new HashSet<>();
+            securityGroupCache.put(remoteSgUuid, portList);
+        }
+        portList.add(portUuid);
+    }
+
+    @Override
+    public void removeFromCache(String remoteSgUuid, String portUuid) {
+        LOG.debug("In removeFromCache remoteSgUuid:" + remoteSgUuid + " portUuid:" + portUuid);
+        Set<String> portList = securityGroupCache.get(remoteSgUuid);
+        if (null == portList) {
+            LOG.debug("The port list is empty for security group:" + remoteSgUuid);
+            return;
+        }
+        for (Iterator<String> iterator = portList.iterator(); iterator.hasNext();) {
+            String cachedPort = iterator.next();
+            if (cachedPort.equals(portUuid)) {
+                iterator.remove();
+                break;
+            }
+        }
+        if (portList.isEmpty()) {
+            securityGroupCache.remove(remoteSgUuid);
+        }
+    }
+
+    private void processPortAdded(String securityGroupUuid, NeutronPort port) {
+        /*
+         * Itreate through the cache maintained for the security group added. For each port in the cache
+         * add the rule to allow traffic to/from the new port added.
+         */
+        LOG.debug("In processPortAdded securityGroupUuid:" + securityGroupUuid + " NeutronPort:" + port);
+        Set<String> portList = this.securityGroupCache.get(securityGroupUuid);
+        if (null == portList) {
+            LOG.debug("The port list is empty for security group:" + securityGroupUuid);
+            return;
+        }
+        for (String cachedportUuid : portList) {
+            if (cachedportUuid.equals(port.getID())) {
+                continue;
+            }
+            NeutronPort cachedport = neutronPortCache.getPort(cachedportUuid);
+            if (null == cachedport) {
+                LOG.error("In processPortAdded cachedport port not found in neuton cache:"
+                            + " cachedportUuid:" + cachedportUuid);
+                continue;
+            }
+            List<NeutronSecurityRule> remoteSecurityRules = retrieveSecurityRules(securityGroupUuid, cachedportUuid);
+            for (NeutronSecurityRule securityRule : remoteSecurityRules) {
+                if (port.getFixedIPs() == null) {
+                    continue;
+                }
+                for (Neutron_IPs vmIp : port.getFixedIPs()) {
+                    securityServicesManager.syncSecurityRule(cachedport, securityRule, vmIp, true);
+                }
+            }
+        }
+    }
+
+    private void processPortRemoved(String securityGroupUuid, NeutronPort port) {
+        /*
+         * Itreate through the cache maintained for the security group added. For each port in the cache remove
+         * the rule to allow traffic to/from the  port that got deleted.
+         */
+        LOG.debug("In processPortRemoved securityGroupUuid:" + securityGroupUuid + " port:" + port);
+        Set<String> portList = this.securityGroupCache.get(securityGroupUuid);
+        if (null == portList) {
+            LOG.debug("The port list is empty for security group:" + securityGroupUuid);
+            return;
+        }
+        for (String cachedportUuid : portList) {
+            if (cachedportUuid.equals(port.getID())) {
+                continue;
+            }
+            NeutronPort cachedport = neutronPortCache.getPort(cachedportUuid);
+            if (cachedport == null) {
+                cachedport = neutronL3Adapter.getPortFromCleanupCache(cachedportUuid);
+                if (null == cachedport) {
+                    LOG.error("In processPortRemoved cachedport port not found in neuton cache:"
+                                + " cachedportUuid:" + cachedportUuid);
+                    continue;
+                }
+            }
+            List<NeutronSecurityRule> remoteSecurityRules = retrieveSecurityRules(securityGroupUuid, cachedportUuid);
+            for (NeutronSecurityRule securityRule : remoteSecurityRules) {
+                if (port.getFixedIPs() == null) {
+                    continue;
+                }
+                for (Neutron_IPs vmIp : port.getFixedIPs()) {
+                    securityServicesManager.syncSecurityRule(cachedport, securityRule, vmIp, false);
+                }
+            }
+        }
+    }
+
+    private List<NeutronSecurityRule> retrieveSecurityRules(String securityGroupUuid, String portUuid) {
+        /*
+         * Get the list of security rules in the port with portUuid that has securityGroupUuid as a remote
+         * security group.
+         */
+        LOG.debug("In retrieveSecurityRules securityGroupUuid:" + securityGroupUuid + " portUuid:" + portUuid);
+        NeutronPort port = neutronPortCache.getPort(portUuid);
+        if (port == null) {
+            port = neutronL3Adapter.getPortFromCleanupCache(portUuid);
+            if (null == port) {
+                LOG.error("In retrieveSecurityRules no neutron port found:" + " portUuid:" + portUuid);
+                return null;
+            }
+        }
+        List<NeutronSecurityRule> remoteSecurityRules = new ArrayList<>();
+        List<NeutronSecurityGroup> securityGroups = port.getSecurityGroups();
+        for (NeutronSecurityGroup securityGroup : securityGroups) {
+            List<NeutronSecurityRule> securityRules = securityGroup.getSecurityRules();
+            for (NeutronSecurityRule securityRule : securityRules) {
+                if (securityGroupUuid.equals(securityRule.getSecurityRemoteGroupID())) {
+                    remoteSecurityRules.add(securityRule);
+                }
+            }
+        }
+        return remoteSecurityRules;
+    }
+
+    private void init() {
+        /*
+         * Rebuild the cache in case of a restart.
+         */
+        List<NeutronPort> portList = neutronPortCache.getAllPorts();
+        for (NeutronPort port:portList) {
+            List<NeutronSecurityGroup> securityGroupList = port.getSecurityGroups();
+            if ( null != securityGroupList) {
+                for (NeutronSecurityGroup securityGroup : securityGroupList) {
+                    List<NeutronSecurityRule> securityRuleList = securityGroup.getSecurityRules();
+                    if ( null != securityRuleList) {
+                        for (NeutronSecurityRule securityRule : securityRuleList) {
+                            if (null != securityRule.getSecurityRemoteGroupID()) {
+                                this.addToCache(securityRule.getSecurityRemoteGroupID(), port.getID());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
+        neutronPortCache = (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+        init();
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java
new file mode 100644 (file)
index 0000000..fc2486a
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.impl;
+
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
+    private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
+    private volatile Southbound southbound;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile ConfigurationService configurationService;
+    private volatile IngressAclProvider ingressAclProvider;
+    private volatile EgressAclProvider egressAclProvider;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+    private boolean isConntrackEnabled = false;
+
+    public SecurityServicesImpl() {
+        super();
+    }
+
+    public SecurityServicesImpl(boolean isConntrack) {
+        super();
+        this.isConntrackEnabled = isConntrack;
+    }
+
+    @Override
+    public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.error("neutron port is null");
+            return false;
+        }
+        LOG.trace("isPortSecurityReady for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return false;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        if (neutronPort == null) {
+            neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+            if (neutronPort == null) {
+                LOG.error("isPortSecurityReady for {}", terminationPointAugmentation.getName()
+                          + "not found");
+                return false;
+            }
+        }
+        String deviceOwner = neutronPort.getDeviceOwner();
+        if (!deviceOwner.contains("compute")) {
+            LOG.debug("Port {} is not a compute host, it is a: {}", neutronPortId, deviceOwner);
+        }
+        LOG.debug("isPortSecurityReady() is a {} ", deviceOwner);
+        List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
+        if (securityGroups.isEmpty()) {
+            LOG.debug("Check for device: {} does not contain a Security Group for port: {}", deviceOwner,
+                      neutronPortId);
+            return false;
+        }
+        LOG.debug("Security Group Check {} does contain a Neutron Security Group", neutronPortId);
+        return true;
+    }
+
+    @Override
+    public List<NeutronSecurityGroup> getSecurityGroupInPortList(OvsdbTerminationPointAugmentation
+                                                             terminationPointAugmentation) {
+        List<NeutronSecurityGroup> neutronSecurityGroups = new ArrayList<>();
+        if (neutronPortCache == null) {
+            LOG.error("neutron port is null");
+            return neutronSecurityGroups;
+        }
+        LOG.trace("getSecurityGroupInPortList for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return neutronSecurityGroups;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        if (neutronPort == null) {
+            neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+            if (neutronPort == null) {
+                LOG.error("getSecurityGroupInPortList for {}", terminationPointAugmentation.getName()
+                          + "not found.");
+                return neutronSecurityGroups;
+            }
+        }
+        neutronSecurityGroups = neutronPort.getSecurityGroups();
+        return neutronSecurityGroups;
+
+    }
+
+    @Override
+    public NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.warn("getDHCPServerPort: neutron port cache is null");
+        }
+        LOG.trace("getDHCPServerPort for {}",
+                  terminationPointAugmentation.getName());
+        NeutronPort neutronPort = null;
+        try {
+            String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                           Constants.EXTERNAL_ID_INTERFACE_ID);
+            if (neutronPortId == null) {
+                return null;
+            }
+            if (null != neutronPortCache) {
+                neutronPort = neutronPortCache.getPort(neutronPortId);
+
+            }
+            if (neutronPort == null) {
+                neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+                if (neutronPort == null) {
+                    LOG.error("getDHCPServerPort: neutron port of {} is not found", neutronPortId);
+                    return null;
+                }
+                LOG.info("getDHCPServerPort: neutron port of {} got from cleanupcache", neutronPortId);
+
+            }
+            /* if the current port is a DHCP port, return the same*/
+            if (neutronPort.getDeviceOwner().contains("dhcp")) {
+                return neutronPort;
+            }
+            /*Since all the fixed ip assigned to a port should be
+             *from the same network, first port is sufficient.*/
+            List<Neutron_IPs> fixedIps = neutronPort.getFixedIPs();
+            if (null == fixedIps || 0 == fixedIps.size() ) {
+                LOG.error("getDHCPServerPort: No fixed ip is assigned");
+                return null;
+            }
+            /* Get all the ports in the subnet and identify the dhcp port*/
+            String subnetUuid = fixedIps.iterator().next().getSubnetUUID();
+            NeutronSubnet neutronSubnet = neutronSubnetCache.getSubnet(subnetUuid);
+            if (neutronSubnet == null) {
+                LOG.error("getDHCPServerPort: No subnet is found for " + subnetUuid);
+                return null;
+            }
+            List<NeutronPort> ports = neutronSubnet.getPortsInSubnet();
+            for (NeutronPort port : ports) {
+                if (port.getDeviceOwner().contains("dhcp")) {
+                    return port;
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("getDHCPServerPort:getDHCPServerPort failed due to ", e);
+            return null;
+        }
+        return null;
+    }
+
+    @Override
+    public NeutronPort getNeutronPortFromDhcpIntf(
+            OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.error("getNeutronPortFromDhcpIntf: neutron port is null");
+            return null;
+        }
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(
+                terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return null;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        if (neutronPort == null) {
+            neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+            if (neutronPort == null) {
+                LOG.error("getNeutronPortFromDhcpIntf: neutron port of {} is not found", neutronPortId);
+                return null;
+            }
+        }
+        /* if the current port is a DHCP port, return true*/
+        if (neutronPort.getDeviceOwner().contains("dhcp")) {
+            LOG.trace("getNeutronPortFromDhcpIntf: neutronPort is a dhcp port", neutronPort );
+            return neutronPort;
+        }
+        return null;
+    }
+
+
+    @Override
+    public NeutronPort getNeutronPortFromCache(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        NeutronPort neutronPort = null;
+        LOG.trace("getNeutronPortFromCache for {}",
+                terminationPointAugmentation.getName());
+        try {
+            String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                    Constants.EXTERNAL_ID_INTERFACE_ID);
+            if (neutronPortId == null) {
+                return null;
+            }
+            if (null != neutronPortCache) {
+                neutronPort = neutronPortCache.getPort(neutronPortId);
+
+            }
+            if (neutronPort == null) {
+                LOG.trace("getNeutronPortFromCache: neutron port of {} search in cleanupcache", neutronPortId);
+
+                neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+                if (neutronPort == null) {
+                    LOG.error("getNeutronPortFromCache: neutron port of {} is not found", neutronPortId);
+                    return null;
+                }
+                LOG.trace("getNeutronPortFromCache: neutron port of {} got from cleanupcache", neutronPortId);
+
+            }
+        } catch (Exception e) {
+            LOG.warn("getNeutronPortFromCache:getNeutronPortFromCache failed due to ", e);
+            return null;
+        }
+        return neutronPort;
+    }
+
+
+
+    @Override
+    public boolean isComputePort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.warn("isComputePort : neutronPortCache is null");
+        }
+        NeutronPort neutronPort = null;
+        LOG.trace("isComputePort for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return false;
+        }
+        if (neutronPortCache != null) {
+            neutronPort = neutronPortCache.getPort(neutronPortId);
+        }
+        if (neutronPort == null) {
+            neutronPort = getNeutronPortFromCache(terminationPointAugmentation);
+            if (neutronPort == null) {
+                return false;
+            }
+        }
+        /*Check the device owner and if it contains compute to identify
+         * whether it is a compute port.*/
+        String deviceOwner = neutronPort.getDeviceOwner();
+        if (!deviceOwner.contains("compute")) {
+            LOG.debug("isComputePort : Port {} is not a DHCP server port for device owner {}",
+                      neutronPortId,deviceOwner);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.error("isLastPortinSubnet: neutronPortCache is null");
+        }
+        NeutronPort neutronPort = null;
+        try {
+            LOG.trace("isLastPortinSubnet: for {}", terminationPointAugmentation.getName());
+            String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                           Constants.EXTERNAL_ID_INTERFACE_ID);
+            if (neutronPortId == null) {
+                return false;
+            }
+            if (neutronPortCache != null) {
+                neutronPort = neutronPortCache.getPort(neutronPortId);
+            }
+            if (neutronPort == null) {
+                neutronPort = getNeutronPortFromCache(terminationPointAugmentation);
+                if (neutronPort == null) {
+                    LOG.error("isLastPortinSubnet: neutron port of {} is not found", neutronPortId);
+                    return false;
+                }
+            }
+            List<Neutron_IPs> neutronPortFixedIp = neutronPort.getFixedIPs();
+            if (null == neutronPortFixedIp || neutronPortFixedIp.isEmpty()) {
+                return false;
+            }
+            /*Get all the ports in the current node and check whether there
+             * is any port belonging to the same subnet of the input
+             */
+            List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+            if (terminationPoints != null && !terminationPoints.isEmpty()) {
+                for (TerminationPoint tp : terminationPoints) {
+                    OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                            tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                    if (ovsdbTerminationPointAugmentation != null && !ovsdbTerminationPointAugmentation
+                            .getName().equals(Constants.INTEGRATION_BRIDGE)) {
+                        String portId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
+                                                                                Constants.EXTERNAL_ID_INTERFACE_ID);
+                        if (null != portId) {
+                            NeutronPort port = neutronPortCache.getPort(portId);
+                            if (null != port && !(port.getID().equals(neutronPort.getID()))
+                                    && port.getDeviceOwner().contains("compute")) {
+                                List<Neutron_IPs> portFixedIp = port.getFixedIPs();
+                                if (null == portFixedIp || portFixedIp.isEmpty()) {
+                                    return false;
+                                }
+                                if (portFixedIp.iterator().next().getSubnetUUID()
+                                        .equals(neutronPort.getFixedIPs().iterator().next().getSubnetUUID())) {
+                                    LOG.trace("isLastPortinSubnet: Port is not the only port.");
+                                    return false;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("isLastPortinSubnet: isLastPortinSubnet failed due to ", e);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        LOG.trace("isLastPortinBridge: for {}", terminationPointAugmentation.getName());
+        List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+        /*Check whether the node has any port other than br-int*/
+        if (terminationPoints != null && !terminationPoints.isEmpty()) {
+            for (TerminationPoint tp : terminationPoints) {
+                OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                        tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if (null != ovsdbTerminationPointAugmentation
+                        && !(ovsdbTerminationPointAugmentation.getName().equals(Constants.INTEGRATION_BRIDGE))
+                        && !(terminationPointAugmentation.getInterfaceUuid()
+                        .equals(ovsdbTerminationPointAugmentation.getInterfaceUuid()))) {
+                    LOG.debug("isLastPortinBridge: it the last port in bridge {}",
+                            terminationPointAugmentation.getName());
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public List<Neutron_IPs> getIpAddressList(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.warn("getIpAddress: neutronPortCache is null");
+        }
+        NeutronPort neutronPort = null;
+        LOG.trace("getIpAddress: for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return null;
+        }
+        if (neutronPortCache != null) {
+            neutronPort = neutronPortCache.getPort(neutronPortId);
+        }
+        if (neutronPort == null) {
+            neutronPort = getNeutronPortFromCache(terminationPointAugmentation);
+        }
+        if (neutronPort == null) {
+            LOG.error("getIpAddress: neutron port of {} is not found", neutronPortId);
+            return null;
+        }
+        return neutronPort.getFixedIPs();
+    }
+
+    @Override
+    public List<Neutron_IPs> getVmListForSecurityGroup(String portUuid, String securityGroupUuid) {
+        List<Neutron_IPs> vmListForSecurityGroup = new ArrayList<>();
+        /*For every port check whether security grouplist contains the current
+         * security group.*/
+        try {
+            for (String neutronPortUuid:neutronL3Adapter.getPortCleanupCache().keySet()) {
+                NeutronPort neutronPort = neutronL3Adapter.getPortCleanupCache().get(neutronPortUuid);
+                if (!neutronPort.getDeviceOwner().contains("compute")) {
+                    LOG.debug("getVMListForSecurityGroup : the port {} is not "
+                            + "compute port belongs to {}", neutronPort.getID(), neutronPort.getDeviceOwner());
+                    continue;
+                }
+                if (portUuid.equals(neutronPort.getID())) {
+                    continue;
+                }
+                List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
+                if (null != securityGroups) {
+                    for (NeutronSecurityGroup securityGroup:securityGroups) {
+                        if (securityGroup.getSecurityGroupUUID().equals(securityGroupUuid)) {
+                            LOG.debug("getVMListForSecurityGroup : adding ports with ips {} "
+                                    + "compute port", neutronPort.getFixedIPs());
+                            if (neutronPort.getFixedIPs() != null) {
+                                vmListForSecurityGroup.addAll(neutronPort.getFixedIPs());
+                            }
+                        }
+                    }
+                }
+
+            }
+        } catch (Exception e) {
+            LOG.error("getVMListForSecurityGroup: getVMListForSecurityGroup"
+                    + " failed due to ", e);
+            return null;
+        }
+        return vmListForSecurityGroup;
+
+    }
+
+    @Override
+    public void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroupList, boolean write) {
+        LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + write);
+        if (null != port && null != port.getSecurityGroups()) {
+            Node node = getNode(port);
+            if (node == null) {
+                return;
+            }
+            NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
+            if (null == neutronNetwork) {
+                neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(port.getNetworkUUID());
+            }
+            if (neutronNetwork == null) {
+                return;
+            }
+            String segmentationId = neutronNetwork.getProviderSegmentationID();
+            OvsdbTerminationPointAugmentation intf = getInterface(node, port);
+            if (intf == null) {
+                return;
+            }
+            long localPort = southbound.getOFPort(intf);
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
+                return;
+            }
+            long dpid = getDpidOfIntegrationBridge(node);
+            if (dpid == 0L) {
+                return;
+            }
+            String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
+                                                                           Constants.EXTERNAL_ID_INTERFACE_ID);
+            if (neutronPortId == null) {
+                LOG.debug("syncSecurityGroup: No neutronPortId seen in {}", intf);
+                return;
+            }
+            for (NeutronSecurityGroup securityGroupInPort:securityGroupList) {
+                ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
+                                                          securityGroupInPort, neutronPortId, write);
+                egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
+                                                         securityGroupInPort, neutronPortId, write);
+            }
+        }
+    }
+
+    @Override
+    public void syncSecurityRule(NeutronPort port, NeutronSecurityRule securityRule,Neutron_IPs vmIp, boolean write) {
+        LOG.trace("syncSecurityGroup:" + securityRule + " Write:" + write);
+        if (null != port && null != port.getSecurityGroups()) {
+            Node node = getNode(port);
+            if (node == null) {
+                return;
+            }
+            NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
+            if (null == neutronNetwork) {
+                neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(port.getNetworkUUID());
+            }
+            if (neutronNetwork == null) {
+                return;
+            }
+            String segmentationId = neutronNetwork.getProviderSegmentationID();
+            OvsdbTerminationPointAugmentation intf = getInterface(node, port);
+            if (intf == null) {
+                return;
+            }
+            long localPort = southbound.getOFPort(intf);
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
+                return;
+            }
+            long dpid = getDpidOfIntegrationBridge(node);
+            if (dpid == 0L) {
+                return;
+            }
+            if (NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRule.getSecurityRuleEthertype())) {
+                if (NeutronSecurityRule.DIRECTION_INGRESS.equals(securityRule.getSecurityRuleDirection())) {
+                    ingressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
+                            securityRule, vmIp, write);
+                } else if (NeutronSecurityRule.DIRECTION_EGRESS.equals(securityRule.getSecurityRuleDirection())) {
+                    egressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
+                            securityRule, vmIp, write);
+                }
+            }
+        }
+    }
+
+    private long getDpidOfIntegrationBridge(Node node) {
+        LOG.trace("getDpidOfIntegrationBridge:" + node);
+        long dpid = 0L;
+        if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
+            dpid = getDpid(node);
+        }
+        if (dpid == 0L) {
+            LOG.warn("getDpidOfIntegerationBridge: dpid not found: {}", node);
+        }
+        return dpid;
+    }
+
+    private long getDpid(Node node) {
+        LOG.trace("getDpid" + node);
+        long dpid = southbound.getDataPathId(node);
+        if (dpid == 0) {
+            LOG.warn("getDpid: dpid not found: {}", node);
+        }
+        return dpid;
+    }
+
+    private Node getNode(NeutronPort port) {
+        LOG.trace("getNode:Port" + port);
+        List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
+
+        for (Node topologyNode : toplogyNodes) {
+            try {
+                Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
+                List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
+                for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
+                    String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
+                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
+                    if (null != uuid && uuid.equals(port.getID())) {
+                        return node;
+                    }
+                }
+            } catch (Exception e) {
+                LOG.error("Exception during handlingNeutron network delete", e);
+            }
+        }
+        LOG.info("no node found for port:" + port);
+        return null;
+    }
+
+    private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) {
+        LOG.trace("getInterface:Node:" + node + " Port:" + port);
+        try {
+            List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
+            for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
+                String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
+                                                                      Constants.EXTERNAL_ID_INTERFACE_ID);
+                if (null != uuid && uuid.equals(port.getID())) {
+                    return ovsdbPort;
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Exception during handlingNeutron network delete", e);
+        }
+        LOG.info("no interface found for node: " + node + " port:" + port);
+        return null;
+    }
+
+    @Override
+    public boolean isPortSecurityEnabled(OvsdbTerminationPointAugmentation intf) {
+        NeutronPort neutronPort = getNeutronPortFromCache(intf);
+        if (null == neutronPort) {
+            LOG.error("Neutron Port is null: " + intf);
+            return false;
+        }
+        if (neutronPort.getPortSecurityEnabled()) {
+            LOG.info("Port Security is enabled for Port: " + neutronPort);
+            return true;
+        }
+        LOG.info("Port Security is  not enabled for Port: " + neutronPort);
+        return false;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        neutronNetworkCache =
+                (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        } else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD) impl;
+        } else if (impl instanceof IngressAclProvider) {
+            ingressAclProvider = (IngressAclProvider) impl;
+        } else if (impl instanceof EgressAclProvider) {
+            egressAclProvider = (EgressAclProvider) impl;
+        }
+    }
+
+    @Override
+    public boolean isConntrackEnabled() {
+        return isConntrackEnabled;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SouthboundImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SouthboundImpl.java
new file mode 100644 (file)
index 0000000..a47df25
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.impl;
+
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.openstack.netvirt.ClusterAwareMdsalUtils;
+import org.opendaylight.netvirt.openstack.netvirt.MdsalHelper;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
+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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * Utility class to wrap mdsal transactions.
+ *
+ * @author Sam Hague (shague@redhat.com)
+ */
+public class SouthboundImpl implements Southbound {
+    private static final Logger LOG = LoggerFactory.getLogger(SouthboundImpl.class);
+    private final DataBroker databroker;
+    private static final String PATCH_PORT_TYPE = "patch";
+    private final ClusterAwareMdsalUtils mdsalUtils;
+
+    /**
+     * Class constructor setting the data broker.
+     *
+     * @param dataBroker the {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}
+     */
+    public SouthboundImpl(DataBroker dataBroker) {
+        this.databroker = dataBroker;
+        mdsalUtils = new ClusterAwareMdsalUtils(dataBroker);
+    }
+
+    public DataBroker getDatabroker() {
+        return databroker;
+    }
+
+    public ConnectionInfo getConnectionInfo(Node ovsdbNode) {
+        ConnectionInfo connectionInfo = null;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = extractOvsdbNode(ovsdbNode);
+        if (ovsdbNodeAugmentation != null) {
+            connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
+        }
+        return connectionInfo;
+    }
+
+    public OvsdbNodeAugmentation extractOvsdbNode(Node node) {
+        return node.getAugmentation(OvsdbNodeAugmentation.class);
+    }
+
+    public NodeId extractBridgeOvsdbNodeId(Node bridgeNode) {
+        NodeId ovsdbNodeId = null;
+        OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
+        if (bridgeAugmentation != null) {
+            @SuppressWarnings("unchecked")
+            InstanceIdentifier<Node> ovsdbNodeIid =
+                    (InstanceIdentifier<Node>) (bridgeAugmentation.getManagedBy().getValue());
+            ovsdbNodeId = InstanceIdentifier.keyOf(ovsdbNodeIid).getNodeId();
+        }
+        return ovsdbNodeId;
+    }
+
+    public List<Node> readOvsdbTopologyNodes() {
+        List<Node> ovsdbNodes = new ArrayList<>();
+        InstanceIdentifier<Topology> topologyInstanceIdentifier = MdsalHelper.createInstanceIdentifier();
+        Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, topologyInstanceIdentifier);
+        if (topology != null && topology.getNode() != null) {
+            for (Node node : topology.getNode()) {
+                OvsdbNodeAugmentation ovsdbNodeAugmentation = node.getAugmentation(OvsdbNodeAugmentation.class);
+                if (ovsdbNodeAugmentation != null) {
+                    ovsdbNodes.add(node);
+                }
+            }
+        }
+        return ovsdbNodes;
+    }
+
+    public List<Node> readOvsdbTopologyBridgeNodes() {
+        List<Node> ovsdbNodes = new ArrayList<>();
+        InstanceIdentifier<Topology> topologyInstanceIdentifier = MdsalHelper.createInstanceIdentifier();
+        Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, topologyInstanceIdentifier);
+        if (topology != null && topology.getNode() != null) {
+            for (Node node : topology.getNode()) {
+                OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
+                if (ovsdbBridgeAugmentation != null) {
+                    ovsdbNodes.add(node);
+                }
+            }
+        }
+        return ovsdbNodes;
+    }
+
+    public Node readOvsdbNode(Node bridgeNode) {
+        Node ovsdbNode = null;
+        OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
+        if (bridgeAugmentation != null) {
+            InstanceIdentifier<Node> ovsdbNodeIid =
+                    (InstanceIdentifier<Node>) bridgeAugmentation.getManagedBy().getValue();
+            ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbNodeIid);
+        }else{
+            LOG.debug("readOvsdbNode: Provided node is not a bridge node : {}",bridgeNode);
+        }
+        return ovsdbNode;
+    }
+
+    public String getOvsdbNodeUUID(Node node) {
+        String nodeUUID = null;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = node.getAugmentation(OvsdbNodeAugmentation.class);
+        if (ovsdbNodeAugmentation != null) {
+            // TODO replace with proper uuid and not the system-id
+            nodeUUID = getOsdbNodeExternalIdsValue(ovsdbNodeAugmentation, "system-id");
+        }
+        return nodeUUID;
+    }
+
+    public String getOsdbNodeExternalIdsValue(OvsdbNodeAugmentation ovsdbNodeAugmentation, String key) {
+        String value = null;
+        List<OpenvswitchExternalIds> pairs = ovsdbNodeAugmentation.getOpenvswitchExternalIds();
+        if (pairs != null && !pairs.isEmpty()) {
+            for (OpenvswitchExternalIds pair : pairs) {
+                if (pair.getExternalIdKey().equals(key)) {
+                    value = pair.getExternalIdValue();
+                    break;
+                }
+            }
+        }
+        return value;
+    }
+
+    public boolean addBridge(Node ovsdbNode, String bridgeName, List<String> controllersStr,
+                             final Class<? extends DatapathTypeBase> dpType) {
+        boolean result;
+
+        LOG.info("addBridge: node: {}, bridgeName: {}, controller(s): {}", ovsdbNode, bridgeName, controllersStr);
+        ConnectionInfo connectionInfo = getConnectionInfo(ovsdbNode);
+        if (connectionInfo != null) {
+            NodeBuilder bridgeNodeBuilder = new NodeBuilder();
+            InstanceIdentifier<Node> bridgeIid =
+                    MdsalHelper.createInstanceIdentifier(ovsdbNode.getKey(), bridgeName);
+            NodeId bridgeNodeId = MdsalHelper.createManagedNodeId(bridgeIid);
+            bridgeNodeBuilder.setNodeId(bridgeNodeId);
+            OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
+            ovsdbBridgeAugmentationBuilder.setControllerEntry(createControllerEntries(controllersStr));
+            ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
+            ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
+            ovsdbBridgeAugmentationBuilder.setFailMode(
+                    MdsalHelper.OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
+            BridgeOtherConfigsBuilder bridgeOtherConfigsBuilder = new BridgeOtherConfigsBuilder();
+            bridgeOtherConfigsBuilder.setBridgeOtherConfigKey(MdsalHelper.DISABLE_IN_BAND);
+            bridgeOtherConfigsBuilder.setBridgeOtherConfigValue("true");
+            List<BridgeOtherConfigs> bridgeOtherConfigsList = new ArrayList<>();
+            bridgeOtherConfigsList.add(bridgeOtherConfigsBuilder.build());
+            ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(bridgeOtherConfigsList);
+            setManagedByForBridge(ovsdbBridgeAugmentationBuilder, ovsdbNode.getKey());
+            if (dpType != null) {
+                ovsdbBridgeAugmentationBuilder.setDatapathType(dpType);
+            }
+            if (isOvsdbNodeDpdk(ovsdbNode)) {
+                ovsdbBridgeAugmentationBuilder.setDatapathType(DatapathTypeNetdev.class);
+            }
+            bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
+
+            result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, bridgeIid, bridgeNodeBuilder.build());
+            LOG.info("addBridge: result: {}", result);
+        } else {
+            throw new InvalidParameterException("Could not find ConnectionInfo");
+        }
+        return result;
+    }
+
+    public boolean deleteBridge(Node ovsdbNode) {
+        InstanceIdentifier<Node> bridgeIid =
+                MdsalHelper.createInstanceIdentifier(ovsdbNode.getNodeId());
+
+        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, bridgeIid);
+        LOG.info("deleteBridge node: {}, bridgeName: {} result : {}", ovsdbNode, ovsdbNode.getNodeId(),result);
+        return result;
+    }
+
+    public OvsdbBridgeAugmentation readBridge(Node node, String name) {
+        OvsdbBridgeAugmentation ovsdbBridgeAugmentation = null;
+        ConnectionInfo connectionInfo = getConnectionInfo(node);
+        if (connectionInfo != null) {
+            InstanceIdentifier<Node> bridgeIid =
+            MdsalHelper.createInstanceIdentifier(node.getKey(), name);
+            Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+            if (bridgeNode != null) {
+                ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
+            }
+        }
+        return ovsdbBridgeAugmentation;
+    }
+
+    public Node readBridgeNode(Node node, String name) {
+        Node ovsdbNode = node;
+        if (extractNodeAugmentation(ovsdbNode) == null) {
+            ovsdbNode = readOvsdbNode(node);
+            if (ovsdbNode == null) {
+                return null;
+            }
+        }
+        Node bridgeNode = null;
+        ConnectionInfo connectionInfo = getConnectionInfo(ovsdbNode);
+        if (connectionInfo != null) {
+            InstanceIdentifier<Node> bridgeIid =
+            MdsalHelper.createInstanceIdentifier(node.getKey(), name);
+            bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+        }
+        return bridgeNode;
+    }
+
+    public Node getBridgeNode(Node node, String bridgeName) {
+        OvsdbBridgeAugmentation bridge = extractBridgeAugmentation(node);
+        if (bridge != null && bridge.getBridgeName().getValue().equals(bridgeName)) {
+            return node;
+        } else {
+            return readBridgeNode(node, bridgeName);
+        }
+    }
+
+    public String getBridgeUuid(Node node, String name) {
+        String uuid = null;
+        OvsdbBridgeAugmentation ovsdbBridgeAugmentation = readBridge(node, name);
+        if (ovsdbBridgeAugmentation != null) {
+            uuid = ovsdbBridgeAugmentation.getBridgeUuid().getValue();
+        }
+        return uuid;
+    }
+
+    private void setManagedByForBridge(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
+                NodeKey ovsdbNodeKey) {
+            InstanceIdentifier<Node> connectionNodePath = MdsalHelper.createInstanceIdentifier(ovsdbNodeKey.getNodeId());
+        ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
+    }
+
+    private List<ControllerEntry> createControllerEntries(List<String> controllersStr) {
+        List<ControllerEntry> controllerEntries = new ArrayList<>();
+        if (controllersStr != null) {
+            for (String controllerStr : controllersStr) {
+                ControllerEntryBuilder controllerEntryBuilder = new ControllerEntryBuilder();
+                controllerEntryBuilder.setTarget(new Uri(controllerStr));
+                controllerEntries.add(controllerEntryBuilder.build());
+            }
+        }
+        return controllerEntries;
+    }
+
+    private List<ProtocolEntry> createMdsalProtocols() {
+        List<ProtocolEntry> protocolList = new ArrayList<>();
+        ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
+                MdsalHelper.OVSDB_PROTOCOL_MAP.inverse();
+        protocolList.add(new ProtocolEntryBuilder().
+                setProtocol(mapper.get("OpenFlow13")).build());
+        return protocolList;
+    }
+
+    public long getDataPathId(Node node) {
+        long dpid = 0L;
+        String datapathId = getDatapathId(node);
+        if (datapathId != null) {
+            dpid = new BigInteger(datapathId.replaceAll(":", ""), 16).longValue();
+        }
+        return dpid;
+    }
+
+    public String getDatapathId(Node node) {
+        OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
+        return getDatapathId(ovsdbBridgeAugmentation);
+    }
+
+    public String getDatapathId(OvsdbBridgeAugmentation ovsdbBridgeAugmentation) {
+        String datapathId = null;
+        if (ovsdbBridgeAugmentation != null && ovsdbBridgeAugmentation.getDatapathId() != null) {
+            datapathId = ovsdbBridgeAugmentation.getDatapathId().getValue();
+        }
+        return datapathId;
+    }
+
+    public OvsdbBridgeAugmentation getBridge(Node node, String name) {
+        OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
+        if ((bridge != null) && (!bridge.getBridgeName().getValue().equals(name))) {
+            bridge = null;
+        }
+        return bridge;
+    }
+
+    public OvsdbBridgeAugmentation getBridge(Node node) {
+        return node.getAugmentation(OvsdbBridgeAugmentation.class);
+    }
+
+    public String getBridgeName(Node node) {
+        String bridgeName = null;
+        OvsdbBridgeAugmentation bridge = getBridge(node);
+        if (bridge != null) {
+            bridgeName = bridge.getBridgeName().getValue();
+        }
+        return bridgeName;
+    }
+
+    public String extractBridgeName(Node node) {
+        return node.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue();
+    }
+
+    public OvsdbBridgeAugmentation extractBridgeAugmentation(Node node) {
+        if (node == null) {
+            return null;
+        }
+        return node.getAugmentation(OvsdbBridgeAugmentation.class);
+    }
+
+    public List<Node> getAllBridgesOnOvsdbNode(Node node) {
+        List<Node> nodes = new ArrayList<>();
+        List<ManagedNodeEntry> managedNodes = node.getAugmentation(OvsdbNodeAugmentation.class).getManagedNodeEntry();
+        for (ManagedNodeEntry managedNode : managedNodes) {
+            InstanceIdentifier<?> bridgeIid = managedNode.getBridgeRef().getValue();
+            Node bridgeNode = (Node) mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+            if (bridgeNode != null) {
+                nodes.add(bridgeNode);
+            }
+        }
+        return nodes;
+    }
+
+    public boolean isBridgeOnOvsdbNode(Node ovsdbNode, String bridgeName) {
+        boolean found = false;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = extractNodeAugmentation(ovsdbNode);
+        if (ovsdbNodeAugmentation != null) {
+            List<ManagedNodeEntry> managedNodes = ovsdbNodeAugmentation.getManagedNodeEntry();
+            if (managedNodes != null) {
+                for (ManagedNodeEntry managedNode : managedNodes) {
+                    InstanceIdentifier<?> bridgeIid = managedNode.getBridgeRef().getValue();
+                    if (bridgeIid.toString().contains(bridgeName)) {
+                        found = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return found;
+    }
+
+    public boolean isOvsdbNodeDpdk(Node ovsdbNode) {
+        boolean found = false;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = extractNodeAugmentation(ovsdbNode);
+        if (ovsdbNodeAugmentation != null) {
+            List<InterfaceTypeEntry> ifTypes = ovsdbNodeAugmentation.getInterfaceTypeEntry();
+            if (ifTypes != null) {
+                for (InterfaceTypeEntry ifType : ifTypes) {
+                    if (ifType.getInterfaceType().equals(InterfaceTypeDpdk.class)) {
+                        found = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return found;
+    }
+
+    public OvsdbNodeAugmentation extractNodeAugmentation(Node node) {
+        return node.getAugmentation(OvsdbNodeAugmentation.class);
+    }
+
+    /**
+     * Method read ports from bridge node. Method will check if the provided node
+     * has the ports details, if not, it will read from Operational data store.
+     * @param node Target bridge to getch termination points from.
+     * @return List of termination points on the given bridge
+     */
+    public List<OvsdbTerminationPointAugmentation> getTerminationPointsOfBridge(Node node) {
+        List<OvsdbTerminationPointAugmentation> tpAugmentations = extractTerminationPointAugmentations(node);
+        if(tpAugmentations.isEmpty()){
+            tpAugmentations = readTerminationPointAugmentations(node);
+        }
+        return tpAugmentations;
+    }
+
+    public OvsdbTerminationPointAugmentation getTerminationPointOfBridge(Node node, String portName) {
+        OvsdbTerminationPointAugmentation tpAugmentation = extractTerminationPointAugmentation(node,portName);
+        if(tpAugmentation == null){
+            List<OvsdbTerminationPointAugmentation> tpAugmentations = readTerminationPointAugmentations(node);
+            if(tpAugmentations != null){
+                for(OvsdbTerminationPointAugmentation ovsdbTpAugmentation : tpAugmentations){
+                    if(ovsdbTpAugmentation.getName().equals(portName)){
+                        return ovsdbTpAugmentation;
+                    }
+                }
+            }
+        }
+        return tpAugmentation;
+    }
+
+    public OvsdbTerminationPointAugmentation extractTerminationPointAugmentation(Node bridgeNode, String portName) {
+        if (bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class) != null) {
+            List<OvsdbTerminationPointAugmentation> tpAugmentations = extractTerminationPointAugmentations(bridgeNode);
+            for (OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation : tpAugmentations) {
+                if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
+                    return ovsdbTerminationPointAugmentation;
+                }
+            }
+        }
+        return null;
+    }
+
+    public List<TerminationPoint> extractTerminationPoints(Node node) {
+        List<TerminationPoint> terminationPoints = new ArrayList<>();
+        OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
+        if (ovsdbBridgeAugmentation != null) {
+            terminationPoints.addAll(node.getTerminationPoint());
+        }
+        return terminationPoints;
+    }
+
+    public List<OvsdbTerminationPointAugmentation> extractTerminationPointAugmentations( Node node ) {
+        List<OvsdbTerminationPointAugmentation> tpAugmentations = new ArrayList<>();
+        List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+        if(terminationPoints != null && !terminationPoints.isEmpty()){
+            for(TerminationPoint tp : terminationPoints){
+                OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                        tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if (ovsdbTerminationPointAugmentation != null) {
+                    tpAugmentations.add(ovsdbTerminationPointAugmentation);
+                }
+            }
+        }
+        return tpAugmentations;
+    }
+
+    public List<OvsdbTerminationPointAugmentation> readTerminationPointAugmentations(Node node) {
+        InstanceIdentifier<Node> bridgeNodeIid = MdsalHelper.createInstanceIdentifier(node.getNodeId());
+        Node operNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeNodeIid);
+        if(operNode != null){
+            return extractTerminationPointAugmentations(operNode);
+        }
+        return new ArrayList<>();
+    }
+
+    public String getInterfaceExternalIdsValue(
+            OvsdbTerminationPointAugmentation terminationPointAugmentation, String key) {
+        String value = null;
+        List<InterfaceExternalIds> pairs = terminationPointAugmentation.getInterfaceExternalIds();
+        if (pairs != null && !pairs.isEmpty()) {
+            for (InterfaceExternalIds pair : pairs) {
+                if (pair.getExternalIdKey().equals(key)) {
+                    value = pair.getExternalIdValue();
+                    break;
+                }
+            }
+        }
+        return value;
+    }
+
+    public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type) {
+        InstanceIdentifier<TerminationPoint> tpIid =
+                MdsalHelper.createTerminationPointInstanceIdentifier(bridgeNode, portName);
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder =
+                new OvsdbTerminationPointAugmentationBuilder();
+
+        tpAugmentationBuilder.setName(portName);
+        if (type != null) {
+            tpAugmentationBuilder.setInterfaceType(MdsalHelper.OVSDB_INTERFACE_TYPE_MAP.get(type));
+        }
+        TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
+        tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
+        tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
+        return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
+    }
+
+    public Boolean deleteTerminationPoint(Node bridgeNode, String portName) {
+        InstanceIdentifier<TerminationPoint> tpIid =
+                MdsalHelper.createTerminationPointInstanceIdentifier(bridgeNode, portName);
+        return mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, tpIid);
+    }
+
+    public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName,
+            String type, Map<String, String> options) {
+        InstanceIdentifier<TerminationPoint> tpIid = MdsalHelper.createTerminationPointInstanceIdentifier(
+                bridgeNode, portName);
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
+
+        tpAugmentationBuilder.setName(portName);
+        if (type != null) {
+            tpAugmentationBuilder.setInterfaceType(MdsalHelper.OVSDB_INTERFACE_TYPE_MAP.get(type));
+        }
+
+        List<Options> optionsList = new ArrayList<>();
+        for (Map.Entry<String, String> entry : options.entrySet()) {
+            OptionsBuilder optionsBuilder = new OptionsBuilder();
+            optionsBuilder.setKey(new OptionsKey(entry.getKey()));
+            optionsBuilder.setOption(entry.getKey());
+            optionsBuilder.setValue(entry.getValue());
+            optionsList.add(optionsBuilder.build());
+        }
+        tpAugmentationBuilder.setOptions(optionsList);
+
+        TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
+        tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
+        tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
+        /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */
+        return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
+    }
+
+    public TerminationPoint readTerminationPoint(Node bridgeNode, String bridgeName, String portName) {
+        InstanceIdentifier<TerminationPoint> tpIid = MdsalHelper.createTerminationPointInstanceIdentifier(
+                bridgeNode, portName);
+        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, tpIid);
+    }
+
+    public Boolean addTunnelTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type,
+                                        Map<String, String> options) {
+        return addTerminationPoint(bridgeNode, bridgeName, portName, type, options);
+    }
+
+    public Boolean isTunnelTerminationPointExist(Node bridgeNode, String bridgeName, String portName){
+        return readTerminationPoint(bridgeNode, bridgeName, portName) != null;
+    }
+
+    public Boolean addPatchTerminationPoint(Node node, String bridgeName, String portName, String peerPortName) {
+        Map<String, String> option = new HashMap<>();
+        option.put("peer", peerPortName);
+        return addTerminationPoint(node, bridgeName, portName, PATCH_PORT_TYPE, option);
+    }
+
+    public String getExternalId(Node node, OvsdbTables table, String key) {
+        switch (table) {
+        case BRIDGE:
+            OvsdbBridgeAugmentation bridge = extractBridgeAugmentation(node);
+            if (bridge != null && bridge.getBridgeExternalIds() != null) {
+                for (BridgeExternalIds bridgeExternaIds :bridge.getBridgeExternalIds()) {
+                    if (bridgeExternaIds.getBridgeExternalIdKey().equals(key)) {
+                        return bridgeExternaIds.getBridgeExternalIdValue();
+                    }
+                }
+            }
+            break;
+        case CONTROLLER:
+            LOG.warn("getExternalId: There is no external_id for OvsdbTables: ", table);
+            return null;
+        case OPENVSWITCH:
+            OvsdbNodeAugmentation ovsdbNode = extractNodeAugmentation(node);
+            if (ovsdbNode == null) {
+                Node nodeFromReadOvsdbNode = readOvsdbNode(node);
+                if (nodeFromReadOvsdbNode != null) {
+                    ovsdbNode = extractNodeAugmentation(nodeFromReadOvsdbNode);
+                }
+            }
+            if (ovsdbNode != null && ovsdbNode.getOpenvswitchExternalIds() != null) {
+                for (OpenvswitchExternalIds openvswitchExternalIds : ovsdbNode.getOpenvswitchExternalIds()) {
+                    if (openvswitchExternalIds.getExternalIdKey().equals(key)) {
+                        return openvswitchExternalIds.getExternalIdValue();
+                    }
+                }
+            }
+            break;
+        case PORT:
+            List <OvsdbTerminationPointAugmentation> ports = extractTerminationPointAugmentations(node);
+            for (OvsdbTerminationPointAugmentation port : ports) {
+                if (port != null && port.getPortExternalIds() != null) {
+                    for (PortExternalIds portExternalIds :port.getPortExternalIds()) {
+                        if (portExternalIds.getExternalIdKey().equals(key)) {
+                            return portExternalIds.getExternalIdValue();
+                        }
+                    }
+                }
+            }
+            break;
+        default:
+            LOG.debug("getExternalId: Couldn't find the specified OvsdbTable: ", table);
+            return null;
+        }
+        return null;
+    }
+
+    public String getOtherConfig(Node node, OvsdbTables table, String key) {
+        switch (table) {
+            case BRIDGE:
+                OvsdbBridgeAugmentation bridge = extractBridgeAugmentation(node);
+                if (bridge != null && bridge.getBridgeOtherConfigs() != null) {
+                    for (BridgeOtherConfigs bridgeOtherConfigs : bridge.getBridgeOtherConfigs()) {
+                        if (bridgeOtherConfigs.getBridgeOtherConfigKey().equals(key)) {
+                            return bridgeOtherConfigs.getBridgeOtherConfigValue();
+                        }
+                    }
+                }
+                break;
+            case CONTROLLER:
+                LOG.warn("getOtherConfig: There is no other_config for OvsdbTables: ", table);
+                return null;
+
+            case OPENVSWITCH:
+                OvsdbNodeAugmentation ovsdbNode = extractNodeAugmentation(node);
+                if (ovsdbNode == null) {
+                    Node nodeFromReadOvsdbNode = readOvsdbNode(node);
+                    if (nodeFromReadOvsdbNode != null) {
+                        ovsdbNode = extractNodeAugmentation(nodeFromReadOvsdbNode);
+                    }
+                }
+                if (ovsdbNode != null && ovsdbNode.getOpenvswitchOtherConfigs() != null) {
+                    for (OpenvswitchOtherConfigs openvswitchOtherConfigs : ovsdbNode.getOpenvswitchOtherConfigs()) {
+                        if (openvswitchOtherConfigs.getOtherConfigKey().equals(key)) {
+                            return openvswitchOtherConfigs.getOtherConfigValue();
+                        }
+                    }
+                }
+                break;
+            case PORT:
+                List <OvsdbTerminationPointAugmentation> ports = extractTerminationPointAugmentations(node);
+                for (OvsdbTerminationPointAugmentation port : ports) {
+                    if (port != null && port.getPortOtherConfigs() != null) {
+                        for (PortOtherConfigs portOtherConfigs : port.getPortOtherConfigs()) {
+                            if (portOtherConfigs.getOtherConfigKey().equals(key)) {
+                                return portOtherConfigs.getOtherConfigValue();
+                            }
+                        }
+                    }
+                }
+                break;
+            default:
+                LOG.debug("getOtherConfig: Couldn't find the specified OvsdbTable: ", table);
+                return null;
+        }
+        return null;
+    }
+
+    public boolean addVlanToTp(long vlan) {
+        return false;
+    }
+
+    public boolean isTunnel(OvsdbTerminationPointAugmentation port) {
+        LOG.trace("SouthboundImpl#isTunnel: Interface : {}", port);
+
+        if(port.getInterfaceType() == null){
+            LOG.warn("No type found for the interface : {}", port);
+            return false;
+        }
+        return MdsalHelper.createOvsdbInterfaceType(
+                port.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
+                || MdsalHelper.createOvsdbInterfaceType(
+                port.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE);
+    }
+
+    public String getOptionsValue(List<Options> options, String key) {
+        String value = null;
+        for (Options option : options) {
+            if (option.getOption().equals(key)) {
+                value = option.getValue();
+            }
+        }
+        return value;
+    }
+
+    public Topology getOvsdbTopology() {
+        InstanceIdentifier<Topology> path = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(MdsalHelper.OVSDB_TOPOLOGY_ID));
+
+        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+    }
+
+    public Long getOFPort(OvsdbTerminationPointAugmentation port) {
+        Long ofPort = 0L;
+        if (port.getOfport() != null) {
+            ofPort = port.getOfport();
+        }
+        return ofPort;
+    }
+
+    public Long getOFPort(Node bridgeNode, String portName) {
+        Long ofPort = 0L;
+        OvsdbTerminationPointAugmentation port = extractTerminationPointAugmentation(bridgeNode, portName);
+        if (port != null) {
+            ofPort = getOFPort(port);
+        } else {
+            TerminationPoint tp = readTerminationPoint(bridgeNode, null, portName);
+            if (tp != null) {
+                port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if (port != null) {
+                    ofPort = getOFPort(port);
+                }
+            }
+        }
+        return ofPort;
+    }
+    public OvsdbBridgeAugmentation getBridgeFromConfig(Node node, String bridge) {
+        OvsdbBridgeAugmentation ovsdbBridgeAugmentation = null;
+        InstanceIdentifier<Node> bridgeIid =
+                MdsalHelper.createInstanceIdentifier(node.getKey(), bridge);
+        Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, bridgeIid);
+        if (bridgeNode != null) {
+            ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
+        }
+        return ovsdbBridgeAugmentation;
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/TenantNetworkManagerImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/TenantNetworkManagerImpl.java
new file mode 100644 (file)
index 0000000..4152a79
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013, 2015 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.openstack.netvirt.impl;
+
+import com.google.common.base.Preconditions;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.VlanConfigurationCache;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TenantNetworkManagerImpl implements ConfigInterface, TenantNetworkManager {
+    private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
+    private INeutronNetworkCRUD neutronNetworkCache;
+    private INeutronPortCRUD neutronPortCache;
+    private VlanConfigurationCache vlanConfigurationCache;
+    private Southbound southbound;
+    private volatile NeutronL3Adapter neutronL3Adapter;
+
+    @Override
+    public int getInternalVlan(Node node, String networkId) {
+        Integer vlan = vlanConfigurationCache.getInternalVlan(node, networkId);
+        if (vlan == null) {
+            return 0;
+        }
+        return vlan;
+    }
+
+    @Override
+    public void reclaimInternalVlan(Node node, NeutronNetwork network) {
+        int vlan = vlanConfigurationCache.reclaimInternalVlan(node, network.getID());
+        if (vlan <= 0) {
+            LOG.debug("Unable to get an internalVlan for Network {}", network);
+            return;
+        }
+        LOG.debug("Removed Vlan {} on {}", vlan);
+    }
+
+    @Override
+    public void programInternalVlan(Node node, OvsdbTerminationPointAugmentation tp, NeutronNetwork network) {
+        int vlan = vlanConfigurationCache.getInternalVlan(node, network.getID());
+        LOG.debug("Programming Vlan {} on {}", vlan, tp);
+        if (vlan <= 0) {
+            LOG.debug("Unable to get an internalVlan for Network {}", network);
+            return;
+        }
+
+        southbound.addVlanToTp(vlan);
+    }
+
+    @Override
+    public boolean isTenantNetworkPresentInNode(Node node, String segmentationId) {
+        String networkId = this.getNetworkId(segmentationId);
+        if (networkId == null) {
+            LOG.debug("Tenant Network not found with Segmenation-id {}", segmentationId);
+            return false;
+        }
+
+        try {
+            // Make sure to get fresh list of termination points, and not use the ones provided in node param!
+            List<OvsdbTerminationPointAugmentation> ports = southbound.readTerminationPointAugmentations(node);
+
+            for (OvsdbTerminationPointAugmentation port : ports) {
+                String ifaceId = southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_INTERFACE_ID);
+                if (ifaceId != null && isInterfacePresentInTenantNetwork(ifaceId, networkId)) {
+                    LOG.debug("Tenant Network {} with Segmentation-id {} is present in Node {} / Interface {}",
+                            networkId, segmentationId, node, port);
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Error while trying to determine if network is present on node", e);
+            return false;
+        }
+
+        LOG.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
+                networkId, segmentationId, node);
+
+        return false;
+    }
+
+    @Override
+    public String getNetworkId(String segmentationId) {
+        Preconditions.checkNotNull(neutronNetworkCache);
+        List <NeutronNetwork> networks = neutronNetworkCache.getAllNetworks();
+        for (NeutronNetwork network : networks) {
+            if (network.getProviderSegmentationID() != null &&
+                    network.getProviderSegmentationID().equalsIgnoreCase(segmentationId)) {
+                return network.getNetworkUUID();
+            }
+        }
+        for (String networkUuid : neutronL3Adapter.getNetworkCleanupCache().keySet()) {
+            NeutronNetwork network = neutronL3Adapter.getNetworkFromCleanupCache(networkUuid);
+            if (network.getProviderSegmentationID() != null &&
+                    network.getProviderSegmentationID().equalsIgnoreCase(segmentationId)) {
+                return network.getNetworkUUID();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public NeutronNetwork getTenantNetwork(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        Preconditions.checkNotNull(neutronNetworkCache);
+        Preconditions.checkNotNull(neutronPortCache);
+        NeutronNetwork neutronNetwork = null;
+
+        LOG.debug("getTenantNetwork for {}", terminationPointAugmentation);
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId != null) {
+            NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+            if ( null == neutronPort) {
+                LOG.debug("neutronPort is null, checking the clean up cache.");
+                neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+            }
+            if (neutronPort != null) {
+                neutronNetwork = neutronNetworkCache.getNetwork(neutronPort.getNetworkUUID());
+                if (null == neutronNetwork) {
+                    neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(neutronPort.getNetworkUUID());
+                }
+                if (neutronNetwork != null) {
+                    LOG.debug("mapped to {}", neutronNetwork);
+                } else {
+                    LOG.debug("getTenantNetwork: did not find neutronNetwork in cache from neutronPort {}",
+                                 neutronPortId);
+                }
+            } else {
+                LOG.info("getTenantNetwork did not find neutronPort {} from termination point {}",
+                        neutronPortId, terminationPointAugmentation.getName());
+            }
+        } else {
+            LOG.debug("getTenantNetwork: did not find {} in external_ids", Constants.EXTERNAL_ID_INTERFACE_ID);
+        }
+        return neutronNetwork;
+    }
+
+    @Override
+    public NeutronPort getTenantPort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        Preconditions.checkNotNull(neutronPortCache);
+        NeutronPort neutronPort = null;
+
+        LOG.trace("getTenantPort for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId != null) {
+            neutronPort = neutronPortCache.getPort(neutronPortId);
+            if (null == neutronPort) {
+                LOG.debug("neutronPort is null checking the clean up cache.");
+                neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
+            }
+        }
+        if (neutronPort != null) {
+            LOG.debug("mapped to {}", neutronPort);
+        } else {
+            LOG.warn("getTenantPort did not find port for {}", terminationPointAugmentation.getName());
+        }
+
+        return neutronPort;
+    }
+
+    @Override
+    public int networkCreated (Node node, String networkId) {
+        return vlanConfigurationCache.assignInternalVlan(node, networkId);
+    }
+
+    @Override
+    public void networkDeleted(String id) {
+        //ToDo: Delete? This method does nothing since container support was dropped...
+    }
+
+    private boolean isInterfacePresentInTenantNetwork (String portId, String networkId) {
+        NeutronPort neutronPort = neutronPortCache.getPort(portId);
+        if (null == neutronPort) {
+            LOG.debug("neutronPort is null checking the clean up cache.");
+            neutronPort = neutronL3Adapter.getPortFromCleanupCache(portId);
+        }
+        return neutronPort != null && neutronPort.getNetworkUUID().equalsIgnoreCase(networkId);
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        vlanConfigurationCache =
+                (VlanConfigurationCache) ServiceHelper.getGlobalInstance(VlanConfigurationCache.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        neutronL3Adapter =
+                (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/VlanConfigurationCacheImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/VlanConfigurationCacheImpl.java
new file mode 100644 (file)
index 0000000..d0b53f1
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2013, 2015 Hewlett-Packard Development Company, L.P. 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.openstack.netvirt.impl;
+
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
+import org.opendaylight.netvirt.openstack.netvirt.NodeConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.VlanConfigurationCache;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import com.google.common.collect.Maps;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Dave Tucker
+ * @author Sam Hague
+ */
+public class VlanConfigurationCacheImpl implements ConfigInterface, VlanConfigurationCache {
+    private static final Logger LOG = LoggerFactory.getLogger(VlanConfigurationCacheImpl.class);
+    private Map<String, NodeConfiguration> configurationCache = Maps.newConcurrentMap();
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile Southbound southbound;
+
+    private NodeConfiguration getNodeConfiguration(Node node){
+        String nodeUuid = getNodeUUID(node);
+        if (configurationCache.get(nodeUuid) != null) {
+            return configurationCache.get(nodeUuid);
+        }
+
+        // Cache miss
+        initializeNodeConfiguration(node, nodeUuid);
+
+        return configurationCache.get(nodeUuid);
+    }
+
+    private String getNodeUUID(Node node) {
+        return southbound.getOvsdbNodeUUID(node);
+    }
+
+    private void initializeNodeConfiguration(Node node, String nodeUuid) {
+        NodeConfiguration nodeConfiguration = new NodeConfiguration();
+        List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(node);
+        for (OvsdbTerminationPointAugmentation port : ports) {
+            Integer vlan = port.getVlanTag().getValue();
+            String networkId = tenantNetworkManager.getTenantNetwork(port).getNetworkUUID();
+            if (vlan != 0 && networkId != null) {
+                internalVlanInUse(nodeConfiguration, vlan);
+                nodeConfiguration.getTenantVlanMap().put(networkId, vlan);
+            } else {
+                LOG.debug("Node: {} initialized without a vlan", node);
+            }
+        }
+        configurationCache.put(nodeUuid, nodeConfiguration);
+    }
+
+    /**
+     * Return the currently mapped internal vlan or get the next
+     * free internal vlan from the available pool and map it to the networkId.
+     */
+    @Override
+    public Integer assignInternalVlan (Node node, String networkId) {
+        NodeConfiguration nodeConfiguration = getNodeConfiguration(node);
+        Integer mappedVlan = nodeConfiguration.getTenantVlanMap().get(networkId);
+        if (mappedVlan != null) {
+            return mappedVlan;
+        }
+        mappedVlan = nodeConfiguration.getInternalVlans().poll();
+        if (mappedVlan != null) {
+            nodeConfiguration.getTenantVlanMap().put(networkId, mappedVlan);
+        }
+        return mappedVlan;
+    }
+
+    /**
+     * Return the mapped internal vlan to the available pool.
+     */
+    @Override
+    public Integer reclaimInternalVlan(Node node, String networkId) {
+        NodeConfiguration nodeConfiguration = getNodeConfiguration(node);
+        Integer mappedVlan = nodeConfiguration.getTenantVlanMap().get(networkId);
+        if (mappedVlan != null) {
+            nodeConfiguration.getTenantVlanMap().remove(networkId);
+            nodeConfiguration.getInternalVlans().add(mappedVlan);
+            return mappedVlan;
+        }
+        return 0;
+    }
+
+    private void internalVlanInUse(NodeConfiguration nodeConfiguration, Integer vlan) {
+        nodeConfiguration.getInternalVlans().remove(vlan);
+    }
+
+    @Override
+    public Integer getInternalVlan(Node node, String networkId) {
+        NodeConfiguration nodeConfiguration = getNodeConfiguration(node);
+        Integer vlan = nodeConfiguration.getTenantVlanMap().get(networkId);
+        return vlan == null ? 0 : vlan;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/INeutronObject.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/INeutronObject.java
new file mode 100644 (file)
index 0000000..fa2e2b1
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+/**
+ * This class contains behaviour common to Neutron configuration objects
+ */
+public interface INeutronObject {
+
+    String getID();
+
+    void setID(String id);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewall.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewall.java
new file mode 100644 (file)
index 0000000..7e29a68
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * admin_state_up     Bool
+ * status             String
+ * shared             Bool
+ * firewall_policy_id uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewall implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String firewallUUID;
+
+    @XmlElement (name = "tenant_id")
+    String firewallTenantID;
+
+    @XmlElement (name = "name")
+    String firewallName;
+
+    @XmlElement (name = "description")
+    String firewallDescription;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean firewallAdminStateIsUp;
+
+    @XmlElement (name = "status")
+    String firewallStatus;
+
+    @XmlElement (defaultValue = "false", name = "shared")
+    Boolean firewallIsShared;
+
+    @XmlElement (name = "firewall_policy_id")
+    String neutronFirewallPolicyID;
+
+    public String getID() {
+        return firewallUUID;
+    }
+
+    public void setID(String id) {
+        firewallUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFirewallUUID() {
+        return firewallUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFirewallUUID(String firewallUUID) {
+        this.firewallUUID = firewallUUID;
+    }
+
+    public String getFirewallTenantID() {
+        return firewallTenantID;
+    }
+
+    public void setFirewallTenantID(String firewallTenantID) {
+        this.firewallTenantID = firewallTenantID;
+    }
+
+    public String getFirewallName() {
+        return firewallName;
+    }
+
+    public void setFirewallName(String firewallName) {
+        this.firewallName = firewallName;
+    }
+
+    public String getFirewallDescription() {
+        return firewallDescription;
+    }
+
+    public void setFirewallDescription(String firewallDescription) {
+        this.firewallDescription = firewallDescription;
+    }
+
+    public Boolean getFirewallAdminStateIsUp() {
+        return firewallAdminStateIsUp;
+    }
+
+    public void setFirewallAdminStateIsUp(Boolean firewallAdminStateIsUp) {
+        this.firewallAdminStateIsUp = firewallAdminStateIsUp;
+    }
+
+    public String getFirewallStatus() {
+        return firewallStatus;
+    }
+
+    public void setFirewallStatus(String firewallStatus) {
+        this.firewallStatus = firewallStatus;
+    }
+
+    public Boolean getFirewallIsShared() {
+        return firewallIsShared;
+    }
+
+    public void setFirewallIsShared(Boolean firewallIsShared) {
+        this.firewallIsShared = firewallIsShared;
+    }
+
+    public String getFirewallPolicyID() {
+        return neutronFirewallPolicyID;
+    }
+
+    public void setNeutronFirewallPolicyID(String firewallPolicy) {
+        this.neutronFirewallPolicyID = firewallPolicy;
+    }
+
+    public NeutronFirewall extractFields(List<String> fields) {
+        NeutronFirewall ans = new NeutronFirewall();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "tenant_id":
+                    ans.setFirewallTenantID(this.getFirewallTenantID());
+                    break;
+                case "name":
+                    ans.setFirewallName(this.getFirewallName());
+                    break;
+                case "description":
+                    ans.setFirewallDescription(this.getFirewallDescription());
+                    break;
+                case "admin_state_up":
+                    ans.setFirewallAdminStateIsUp(firewallAdminStateIsUp);
+                    break;
+                case "status":
+                    ans.setFirewallStatus(this.getFirewallStatus());
+                    break;
+                case "shared":
+                    ans.setFirewallIsShared(firewallIsShared);
+                    break;
+                case "firewall_policy_id":
+                    ans.setNeutronFirewallPolicyID(this.getFirewallPolicyID());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronFirewall{" +
+            "firewallUUID='" + firewallUUID + '\'' +
+            ", firewallTenantID='" + firewallTenantID + '\'' +
+            ", firewallName='" + firewallName + '\'' +
+            ", firewallDescription='" + firewallDescription + '\'' +
+            ", firewallAdminStateIsUp=" + firewallAdminStateIsUp +
+            ", firewallStatus='" + firewallStatus + '\'' +
+            ", firewallIsShared=" + firewallIsShared +
+            ", firewallRulePolicyID=" + neutronFirewallPolicyID +
+            '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewallPolicy.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewallPolicy.java
new file mode 100644 (file)
index 0000000..9028f33
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields.
+ * The implemented fields are as follows:
+ *
+ * id             uuid-str
+ * tenant_id      uuid-str
+ * name           String
+ * description    String
+ * shared         Boolean
+ * firewall_rules List
+ * audited        Boolean
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewallPolicy implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String firewallPolicyUUID;
+
+    @XmlElement (name = "tenant_id")
+    String firewallPolicyTenantID;
+
+    @XmlElement (name = "name")
+    String firewallPolicyName;
+
+    @XmlElement (name = "description")
+    String firewallPolicyDescription;
+
+    @XmlElement (defaultValue = "false", name = "shared")
+    Boolean firewallPolicyIsShared;
+
+    @XmlElement (name = "firewall_rules")
+    List<String> firewallPolicyRules;
+
+    @XmlElement (defaultValue = "false", name = "audited")
+    Boolean firewallPolicyIsAudited;
+
+    public Boolean getFirewallPolicyIsAudited() {
+        return firewallPolicyIsAudited;
+    }
+
+    public void setFirewallPolicyIsAudited(Boolean firewallPolicyIsAudited) {
+        this.firewallPolicyIsAudited = firewallPolicyIsAudited;
+    }
+
+    public void setFirewallPolicyRules(List<String> firewallPolicyRules) {
+        this.firewallPolicyRules = firewallPolicyRules;
+    }
+
+    public List<String> getFirewallPolicyRules() {
+        return firewallPolicyRules;
+    }
+
+    public Boolean getFirewallPolicyIsShared() {
+        return firewallPolicyIsShared;
+    }
+
+    public void setFirewallPolicyIsShared(Boolean firewallPolicyIsShared) {
+        this.firewallPolicyIsShared = firewallPolicyIsShared;
+    }
+
+    public String getFirewallPolicyDescription() {
+        return firewallPolicyDescription;
+    }
+
+    public void setFirewallPolicyDescription(String firewallPolicyDescription) {
+        this.firewallPolicyDescription = firewallPolicyDescription;
+    }
+
+    public String getFirewallPolicyName() {
+        return firewallPolicyName;
+    }
+
+    public void setFirewallPolicyName(String firewallPolicyName) {
+        this.firewallPolicyName = firewallPolicyName;
+    }
+
+    public String getFirewallPolicyTenantID() {
+        return firewallPolicyTenantID;
+    }
+
+    public void setFirewallPolicyTenantID(String firewallPolicyTenantID) {
+        this.firewallPolicyTenantID = firewallPolicyTenantID;
+    }
+
+    public String getID() {
+        return firewallPolicyUUID;
+    }
+
+    public void setID(String id) {
+        firewallPolicyUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFirewallPolicyUUID() {
+        return firewallPolicyUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFirewallPolicyUUID(String firewallPolicyUUID) {
+        this.firewallPolicyUUID = firewallPolicyUUID;
+    }
+
+    public NeutronFirewallPolicy extractFields(List<String> fields) {
+        NeutronFirewallPolicy ans = new NeutronFirewallPolicy();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "tenant_id":
+                    ans.setFirewallPolicyTenantID(this.getFirewallPolicyTenantID());
+                    break;
+                case "name":
+                    ans.setFirewallPolicyName(this.getFirewallPolicyName());
+                    break;
+                case "description":
+                    ans.setFirewallPolicyDescription(this.getFirewallPolicyDescription());
+                    break;
+                case "shared":
+                    ans.setFirewallPolicyIsShared(firewallPolicyIsShared);
+                    break;
+                case "firewall_rules":
+                    List<String> firewallRuleList = new ArrayList<>();
+                    firewallRuleList.addAll(this.getFirewallPolicyRules());
+                    ans.setFirewallPolicyRules(firewallRuleList);
+                    break;
+                case "audited":
+                    ans.setFirewallPolicyIsAudited(firewallPolicyIsAudited);
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronFirewallPolicy{" +
+            "firewallPolicyUUID='" + firewallPolicyUUID + '\'' +
+            ", firewallPolicyTenantID='" + firewallPolicyTenantID + '\'' +
+            ", firewallPolicyName='" + firewallPolicyName + '\'' +
+            ", firewallPolicyDescription='" + firewallPolicyDescription + '\'' +
+            ", firewallPolicyIsShared=" + firewallPolicyIsShared +
+            ", firewallPolicyRules=" + firewallPolicyRules +
+            ", firewallPolicyIsAudited='" + firewallPolicyIsAudited + '\'' +
+            '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewallRule.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFirewallRule.java
new file mode 100644 (file)
index 0000000..51dbbcb
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2015 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields.
+ * The implemented fields are as follows:
+ *
+ * tenant_id               uuid-str
+ * name                    String
+ * description             String
+ * admin_state_up          Bool
+ * status                  String
+ * shared                  Bool
+ * firewall_policy_id      uuid-str
+ * protocol                String
+ * ip_version              Integer
+ * source_ip_address       String (IP addr or CIDR)
+ * destination_ip_address  String (IP addr or CIDR)
+ * source_port             Integer
+ * destination_port        Integer
+ * position                Integer
+ * action                  String
+ * enabled                 Bool
+ * id                      uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewallRule implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String firewallRuleUUID;
+
+    @XmlElement(name = "tenant_id")
+    String firewallRuleTenantID;
+
+    @XmlElement(name = "name")
+    String firewallRuleName;
+
+    @XmlElement(name = "description")
+    String firewallRuleDescription;
+
+    @XmlElement(name = "status")
+    String firewallRuleStatus;
+
+    @XmlElement(defaultValue = "false", name = "shared")
+    Boolean firewallRuleIsShared;
+
+    @XmlElement(name = "firewall_policy_id")
+    String firewallRulePolicyID;
+
+    @XmlElement(name = "protocol")
+    String firewallRuleProtocol;
+
+    @XmlElement(name = "ip_version")
+    Integer firewallRuleIpVer;
+
+    @XmlElement(name = "source_ip_address")
+    String firewallRuleSrcIpAddr;
+
+    @XmlElement(name = "destination_ip_address")
+    String firewallRuleDstIpAddr;
+
+    @XmlElement(name = "source_port")
+    Integer firewallRuleSrcPort;
+
+    @XmlElement(name = "destination_port")
+    Integer firewallRuleDstPort;
+
+    @XmlElement(name = "position")
+    Integer firewallRulePosition;
+
+    @XmlElement(name = "action")
+    String firewallRuleAction;
+
+    @XmlElement(name = "enabled")
+    Boolean firewallRuleIsEnabled;
+
+    public Boolean getFirewallRuleIsEnabled() {
+        return firewallRuleIsEnabled;
+    }
+
+    public void setFirewallRuleIsEnabled(Boolean firewallRuleIsEnabled) {
+        this.firewallRuleIsEnabled = firewallRuleIsEnabled;
+    }
+
+    public String getFirewallRuleAction() {
+        return firewallRuleAction;
+    }
+
+    public void setFirewallRuleAction(String firewallRuleAction) {
+        this.firewallRuleAction = firewallRuleAction;
+    }
+
+    public Integer getFirewallRulePosition() {
+        return firewallRulePosition;
+    }
+
+    public void setFirewallRulePosition(Integer firewallRulePosition) {
+        this.firewallRulePosition = firewallRulePosition;
+    }
+
+    public Integer getFirewallRuleDstPort() {
+        return firewallRuleDstPort;
+    }
+
+    public void setFirewallRuleDstPort(Integer firewallRuleDstPort) {
+        this.firewallRuleDstPort = firewallRuleDstPort;
+    }
+
+    public Integer getFirewallRuleSrcPort() {
+        return firewallRuleSrcPort;
+    }
+
+    public void setFirewallRuleSrcPort(Integer firewallRuleSrcPort) {
+        this.firewallRuleSrcPort = firewallRuleSrcPort;
+    }
+
+    public String getFirewallRuleDstIpAddr() {
+        return firewallRuleDstIpAddr;
+    }
+
+    public void setFirewallRuleDstIpAddr(String firewallRuleDstIpAddr) {
+        this.firewallRuleDstIpAddr = firewallRuleDstIpAddr;
+    }
+
+    public String getFirewallRuleSrcIpAddr() {
+        return firewallRuleSrcIpAddr;
+    }
+
+    public void setFirewallRuleSrcIpAddr(String firewallRuleSrcIpAddr) {
+        this.firewallRuleSrcIpAddr = firewallRuleSrcIpAddr;
+    }
+
+    public Integer getFirewallRuleIpVer() {
+        return firewallRuleIpVer;
+    }
+
+    public void setFirewallRuleIpVer(Integer firewallRuleIpVer) {
+        this.firewallRuleIpVer = firewallRuleIpVer;
+    }
+
+    public String getFirewallRuleProtocol() {
+        return firewallRuleProtocol;
+    }
+
+    public void setFirewallRuleProtocol(String firewallRuleProtocol) {
+        this.firewallRuleProtocol = firewallRuleProtocol;
+    }
+
+    public String getFirewallRulePolicyID() {
+        return firewallRulePolicyID;
+    }
+
+    public void setFirewallRulesPolicyID(String firewallRulePolicyID) {
+        this.firewallRulePolicyID = firewallRulePolicyID;
+    }
+
+    public Boolean getFirewallRuleIsShared() {
+        return firewallRuleIsShared;
+    }
+
+    public void setFirewallRuleIsShared(Boolean firewallRuleIsShared) {
+        this.firewallRuleIsShared = firewallRuleIsShared;
+    }
+
+    public String getFirewallRuleStatus() {
+        return firewallRuleStatus;
+    }
+
+    public void setFirewallRuleStatus(String firewallRuleStatus) {
+        this.firewallRuleStatus = firewallRuleStatus;
+    }
+
+    public String getFirewallRuleDescription() {
+        return firewallRuleDescription;
+    }
+
+    public void setFirewallRuleDescription(String firewallRuleDescription) {
+        this.firewallRuleDescription = firewallRuleDescription;
+    }
+
+    public String getFirewallRuleName() {
+        return firewallRuleName;
+    }
+
+    public void setFirewallRuleName(String firewallRuleName) {
+        this.firewallRuleName = firewallRuleName;
+    }
+
+    public String getFirewallRuleTenantID() {
+        return firewallRuleTenantID;
+    }
+
+    public void setFirewallRuleTenantID(String firewallRuleTenantID) {
+        this.firewallRuleTenantID = firewallRuleTenantID;
+    }
+
+    public String getID() {
+        return firewallRuleUUID;
+    }
+
+    public void setID(String id) {
+        firewallRuleUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFirewallRuleUUID() {
+        return firewallRuleUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFireWallRuleID(String firewallRuleUUID) {
+        this.firewallRuleUUID = firewallRuleUUID;
+    }
+
+    public NeutronFirewallRule extractFields(List<String> fields) {
+        NeutronFirewallRule ans = new NeutronFirewallRule();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "tenant_id":
+                    ans.setFirewallRuleTenantID(this.getFirewallRuleTenantID());
+                    break;
+                case "name":
+                    ans.setFirewallRuleName(this.getFirewallRuleName());
+                    break;
+                case "description":
+                    ans.setFirewallRuleDescription(this.getFirewallRuleDescription());
+                    break;
+                case "status":
+                    ans.setFirewallRuleStatus(this.getFirewallRuleStatus());
+                    break;
+                case "shared":
+                    ans.setFirewallRuleIsShared(firewallRuleIsShared);
+                    break;
+                case "firewall_policy_id":
+                    ans.setFirewallRulesPolicyID(this.getFirewallRulePolicyID());
+                    break;
+                case "protocol":
+                    ans.setFirewallRuleProtocol(this.getFirewallRuleProtocol());
+                    break;
+                case "source_ip_address":
+                    ans.setFirewallRuleSrcIpAddr(this.getFirewallRuleSrcIpAddr());
+                    break;
+                case "destination_ip_address":
+                    ans.setFirewallRuleDstIpAddr(this.getFirewallRuleDstIpAddr());
+                    break;
+                case "source_port":
+                    ans.setFirewallRuleSrcPort(this.getFirewallRuleSrcPort());
+                    break;
+                case "destination_port":
+                    ans.setFirewallRuleDstPort(this.getFirewallRuleDstPort());
+                    break;
+                case "position":
+                    ans.setFirewallRulePosition(this.getFirewallRulePosition());
+                    break;
+                case "action":
+                    ans.setFirewallRuleAction(this.getFirewallRuleAction());
+                    break;
+                case "enabled":
+                    ans.setFirewallRuleIsEnabled(firewallRuleIsEnabled);
+                    break;
+            }
+
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "firewallPolicyRules{" +
+            "firewallRuleUUID='" + firewallRuleUUID + '\'' +
+            ", firewallRuleTenantID='" + firewallRuleTenantID + '\'' +
+            ", firewallRuleName='" + firewallRuleName + '\'' +
+            ", firewallRuleDescription='" + firewallRuleDescription + '\'' +
+            ", firewallRuleStatus='" + firewallRuleStatus + '\'' +
+            ", firewallRuleIsShared=" + firewallRuleIsShared +
+            ", firewallRulePolicyID=" + firewallRulePolicyID +
+            ", firewallRuleProtocol='" + firewallRuleProtocol + '\'' +
+            ", firewallRuleIpVer=" + firewallRuleIpVer +
+            ", firewallRuleSrcIpAddr='" + firewallRuleSrcIpAddr + '\'' +
+            ", firewallRuleDstIpAddr='" + firewallRuleDstIpAddr + '\'' +
+            ", firewallRuleSrcPort=" + firewallRuleSrcPort +
+            ", firewallRuleDstPort=" + firewallRuleDstPort +
+            ", firewallRulePosition=" + firewallRulePosition +
+            ", firewallRuleAction='" + firewallRuleAction + '\'' +
+            ", firewallRuleIsEnabled=" + firewallRuleIsEnabled +
+            '}';
+    }
+
+    public void initDefaults() {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFloatingIP.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronFloatingIP.java
new file mode 100644 (file)
index 0000000..0d652ea
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFloatingIP implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "id")
+    String floatingIPUUID;
+
+    @XmlElement (name = "floating_network_id")
+    String floatingNetworkUUID;
+
+    @XmlElement (name = "port_id")
+    String portUUID;
+
+    @XmlElement (name = "fixed_ip_address")
+    String fixedIPAddress;
+
+    @XmlElement (name = "floating_ip_address")
+    String floatingIPAddress;
+
+    @XmlElement (name = "tenant_id")
+    String tenantUUID;
+
+    @XmlElement (name="router_id")
+    String routerUUID;
+
+    @XmlElement (name="status")
+    String status;
+
+    public NeutronFloatingIP() {
+    }
+
+    public String getID() {
+        return floatingIPUUID;
+    }
+
+    public void setID(String id) {
+        floatingIPUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFloatingIPUUID() {
+        return floatingIPUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFloatingIPUUID(String floatingIPUUID) {
+        this.floatingIPUUID = floatingIPUUID;
+    }
+
+    public String getFloatingNetworkUUID() {
+        return floatingNetworkUUID;
+    }
+
+    public void setFloatingNetworkUUID(String floatingNetworkUUID) {
+        this.floatingNetworkUUID = floatingNetworkUUID;
+    }
+
+    public String getPortUUID() {
+        return portUUID;
+    }
+
+    public String getRouterUUID() {
+        return routerUUID;
+    }
+
+    public void setPortUUID(String portUUID) {
+        this.portUUID = portUUID;
+    }
+
+    public String getFixedIPAddress() {
+        return fixedIPAddress;
+    }
+
+    public void setFixedIPAddress(String fixedIPAddress) {
+        this.fixedIPAddress = fixedIPAddress;
+    }
+
+    public String getFloatingIPAddress() {
+        return floatingIPAddress;
+    }
+
+    public void setFloatingIPAddress(String floatingIPAddress) {
+        this.floatingIPAddress = floatingIPAddress;
+    }
+
+    public String getTenantUUID() {
+        return tenantUUID;
+    }
+
+    public void setTenantUUID(String tenantUUID) {
+        this.tenantUUID = tenantUUID;
+    }
+
+    public void setRouterUUID(String routerUUID) {
+        this.routerUUID = routerUUID;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackFloatingIPs object with only the selected fields
+     * populated
+     */
+
+    public NeutronFloatingIP extractFields(List<String> fields) {
+        NeutronFloatingIP ans = new NeutronFloatingIP();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "floating_network_id":
+                    ans.setFloatingNetworkUUID(this.getFloatingNetworkUUID());
+                    break;
+                case "port_id":
+                    ans.setPortUUID(this.getPortUUID());
+                    break;
+                case "fixed_ip_address":
+                    ans.setFixedIPAddress(this.getFixedIPAddress());
+                    break;
+                case "floating_ip_address":
+                    ans.setFloatingIPAddress(this.getFloatingIPAddress());
+                    break;
+                case "tenant_id":
+                    ans.setTenantUUID(this.getTenantUUID());
+                    break;
+                case "router_id":
+                    ans.setRouterUUID(this.getRouterUUID());
+                    break;
+                case "status":
+                    ans.setStatus(this.getStatus());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronFloatingIP{" +
+            "fipUUID='" + floatingIPUUID + '\'' +
+            ", fipFloatingNetworkId='" + floatingNetworkUUID + '\'' +
+            ", fipPortUUID='" + portUUID + '\'' +
+            ", fipFixedIPAddress='" + fixedIPAddress + '\'' +
+            ", fipFloatingIPAddress=" + floatingIPAddress +
+            ", fipTenantId='" + tenantUUID + '\'' +
+            ", fipRouterId='" + routerUUID + '\'' +
+            ", fipStatus='" + status + '\'' +
+            '}';
+    }
+
+    public void initDefaults() {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancer.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancer.java
new file mode 100644 (file)
index 0000000..857373a
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * status             String
+ * vip_address        IP address
+ * vip_subnet         uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancer implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerID;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerTenantID;
+
+    @XmlElement (name = "name")
+    String loadBalancerName;
+
+    @XmlElement (name = "description")
+    String loadBalancerDescription;
+
+    @XmlElement (name = "status")
+    String loadBalancerStatus;
+
+    @XmlElement (name = "admin_state_up")
+    Boolean loadBalancerAdminStateUp;
+
+    @XmlElement (name = "vip_address")
+    String loadBalancerVipAddress;
+
+    @XmlElement (name = "vip_subnet_id")
+    String loadBalancerVipSubnetID;
+
+    public String getID() {
+        return loadBalancerID;
+    }
+
+    public void setID(String id) {
+        loadBalancerID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerID() {
+        return loadBalancerID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerID(String loadBalancerID) {
+        this.loadBalancerID = loadBalancerID;
+    }
+
+    public String getLoadBalancerTenantID() {
+        return loadBalancerTenantID;
+    }
+
+    public void setLoadBalancerTenantID(String loadBalancerTenantID) {
+        this.loadBalancerTenantID = loadBalancerTenantID;
+    }
+
+    public String getLoadBalancerName() {
+        return loadBalancerName;
+    }
+
+    public void setLoadBalancerName(String loadBalancerName) {
+        this.loadBalancerName = loadBalancerName;
+    }
+
+    public String getLoadBalancerDescription() {
+        return loadBalancerDescription;
+    }
+
+    public void setLoadBalancerDescription(String loadBalancerDescription) {
+        this.loadBalancerDescription = loadBalancerDescription;
+    }
+
+    public String getLoadBalancerStatus() {
+        return loadBalancerStatus;
+    }
+
+    public void setLoadBalancerStatus(String loadBalancerStatus) {
+        this.loadBalancerStatus = loadBalancerStatus;
+    }
+
+    public Boolean getLoadBalancerAdminStateUp() {
+        return loadBalancerAdminStateUp;
+    }
+
+    public void setLoadBalancerAdminStateUp(Boolean loadBalancerAdminStateUp) {
+        this.loadBalancerAdminStateUp = loadBalancerAdminStateUp;
+    }
+
+    public String getLoadBalancerVipAddress() {
+        return loadBalancerVipAddress;
+    }
+
+    public void setLoadBalancerVipAddress(String loadBalancerVipAddress) {
+        this.loadBalancerVipAddress = loadBalancerVipAddress;
+    }
+
+    public String getLoadBalancerVipSubnetID() {
+        return loadBalancerVipSubnetID;
+    }
+
+    public void setLoadBalancerVipSubnetID(String loadBalancerVipSubnetID) {
+        this.loadBalancerVipSubnetID = loadBalancerVipSubnetID;
+    }
+
+    public NeutronLoadBalancer extractFields(List<String> fields) {
+        NeutronLoadBalancer ans = new NeutronLoadBalancer();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "tenant_id":
+                    ans.setLoadBalancerTenantID(this.getLoadBalancerTenantID());
+                    break;
+                case "name":
+                    ans.setLoadBalancerName(this.getLoadBalancerName());
+                    break;
+                case "description":
+                    ans.setLoadBalancerDescription(this.getLoadBalancerDescription());
+                    break;
+                case "vip_address":
+                    ans.setLoadBalancerVipAddress(this.getLoadBalancerVipAddress());
+                    break;
+                case "vip_subnet_id":
+                    ans.setLoadBalancerVipSubnetID(this.getLoadBalancerVipSubnetID());
+                    break;
+                case "status":
+                    ans.setLoadBalancerStatus(this.getLoadBalancerStatus());
+                    break;
+                case "admin_state_up":
+                    ans.setLoadBalancerAdminStateUp(this.getLoadBalancerAdminStateUp());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancer{" +
+                "loadBalancerID='" + loadBalancerID + '\'' +
+                ", loadBalancerTenantID='" + loadBalancerTenantID + '\'' +
+                ", loadBalancerName='" + loadBalancerName + '\'' +
+                ", loadBalancerDescription='" + loadBalancerDescription + '\'' +
+                ", loadBalancerStatus='" + loadBalancerStatus + '\'' +
+                ", loadBalancerAdminStateUp='" + loadBalancerAdminStateUp + '\'' +
+                ", loadBalancerVipAddress='" + loadBalancerVipAddress + '\'' +
+                ", loadBalancerVipSubnetID='" + loadBalancerVipSubnetID + '\'' +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerHealthMonitor.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerHealthMonitor.java
new file mode 100644 (file)
index 0000000..6683ae6
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * type               String
+ * delay              Integer
+ * timeout            Integer
+ * max_retries        Integer
+ * http_method        String
+ * url_path           String
+ * expected_codes     String
+ * admin_state_up     Boolean
+ * status             String
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerHealthMonitor
+    implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerHealthMonitorID;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerHealthMonitorTenantID;
+
+    @XmlElement (name = "type")
+    String loadBalancerHealthMonitorType;
+
+    @XmlElement (name = "delay")
+    Integer loadBalancerHealthMonitorDelay;
+
+    @XmlElement (name = "timeout")
+    Integer loadBalancerHealthMonitorTimeout;
+
+    @XmlElement (name = "max_retries")
+    Integer loadBalancerHealthMonitorMaxRetries;
+
+    @XmlElement (name = "http_method")
+    String loadBalancerHealthMonitorHttpMethod;
+
+    @XmlElement (name = "url_path")
+    String loadBalancerHealthMonitorUrlPath;
+
+    @XmlElement (name = "expected_codes")
+    String loadBalancerHealthMonitorExpectedCodes;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean loadBalancerHealthMonitorAdminStateIsUp;
+
+    @XmlElement (name = "pools")
+    List<Neutron_ID> loadBalancerHealthMonitorPools;
+
+    public String getID() {
+        return loadBalancerHealthMonitorID;
+    }
+
+    public void setID(String id) {
+        loadBalancerHealthMonitorID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerHealthMonitorID() {
+        return loadBalancerHealthMonitorID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerHealthMonitorID(String loadBalancerHealthMonitorID) {
+        this.loadBalancerHealthMonitorID = loadBalancerHealthMonitorID;
+    }
+
+    public String getLoadBalancerHealthMonitorTenantID() {
+        return loadBalancerHealthMonitorTenantID;
+    }
+
+    public void setLoadBalancerHealthMonitorTenantID(String loadBalancerHealthMonitorTenantID) {
+        this.loadBalancerHealthMonitorTenantID = loadBalancerHealthMonitorTenantID;
+    }
+
+    public String getLoadBalancerHealthMonitorType() {
+        return loadBalancerHealthMonitorType;
+    }
+
+    public void setLoadBalancerHealthMonitorType(String loadBalancerHealthMonitorType) {
+        this.loadBalancerHealthMonitorType = loadBalancerHealthMonitorType;
+    }
+
+    public Integer getLoadBalancerHealthMonitorDelay() {
+        return loadBalancerHealthMonitorDelay;
+    }
+
+    public void setLoadBalancerHealthMonitorDelay(Integer loadBalancerHealthMonitorDelay) {
+        this.loadBalancerHealthMonitorDelay = loadBalancerHealthMonitorDelay;
+    }
+
+    public Integer getLoadBalancerHealthMonitorTimeout() {
+        return loadBalancerHealthMonitorTimeout;
+    }
+
+    public void setLoadBalancerHealthMonitorTimeout(Integer loadBalancerHealthMonitorTimeout) {
+        this.loadBalancerHealthMonitorTimeout = loadBalancerHealthMonitorTimeout;
+    }
+
+    public Integer getLoadBalancerHealthMonitorMaxRetries() {
+        return loadBalancerHealthMonitorMaxRetries;
+    }
+
+    public void setLoadBalancerHealthMonitorMaxRetries(Integer loadBalancerHealthMonitorMaxRetries) {
+        this.loadBalancerHealthMonitorMaxRetries = loadBalancerHealthMonitorMaxRetries;
+    }
+
+    public String getLoadBalancerHealthMonitorHttpMethod() {
+        return loadBalancerHealthMonitorHttpMethod;
+    }
+
+    public void setLoadBalancerHealthMonitorHttpMethod(String loadBalancerHealthMonitorHttpMethod) {
+        this.loadBalancerHealthMonitorHttpMethod = loadBalancerHealthMonitorHttpMethod;
+    }
+
+    public String getLoadBalancerHealthMonitorUrlPath() {
+        return loadBalancerHealthMonitorUrlPath;
+    }
+
+    public void setLoadBalancerHealthMonitorUrlPath(String loadBalancerHealthMonitorUrlPath) {
+        this.loadBalancerHealthMonitorUrlPath = loadBalancerHealthMonitorUrlPath;
+    }
+
+    public String getLoadBalancerHealthMonitorExpectedCodes() {
+        return loadBalancerHealthMonitorExpectedCodes;
+    }
+
+    public void setLoadBalancerHealthMonitorExpectedCodes(String loadBalancerHealthMonitorExpectedCodes) {
+        this.loadBalancerHealthMonitorExpectedCodes = loadBalancerHealthMonitorExpectedCodes;
+    }
+
+    public Boolean getLoadBalancerHealthMonitorAdminStateIsUp() {
+        return loadBalancerHealthMonitorAdminStateIsUp;
+    }
+
+    public void setLoadBalancerHealthMonitorAdminStateIsUp(Boolean loadBalancerHealthMonitorAdminStateIsUp) {
+        this.loadBalancerHealthMonitorAdminStateIsUp = loadBalancerHealthMonitorAdminStateIsUp;
+    }
+
+    public List<Neutron_ID> getLoadBalancerHealthMonitorPools() {
+        return loadBalancerHealthMonitorPools;
+    }
+
+    public void setLoadBalancerHealthMonitorPools(List<Neutron_ID> loadBalancerHealthMonitorPools) {
+        this.loadBalancerHealthMonitorPools = loadBalancerHealthMonitorPools;
+    }
+
+    public NeutronLoadBalancerHealthMonitor extractFields(List<String> fields) {
+        NeutronLoadBalancerHealthMonitor ans = new NeutronLoadBalancerHealthMonitor();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "tenant_id":
+                    ans.setLoadBalancerHealthMonitorTenantID(this.getLoadBalancerHealthMonitorTenantID());
+                    break;
+                case "type":
+                    ans.setLoadBalancerHealthMonitorType(this.getLoadBalancerHealthMonitorType());
+                    break;
+                case "delay":
+                    ans.setLoadBalancerHealthMonitorDelay(this.getLoadBalancerHealthMonitorDelay());
+                    break;
+                case "timeout":
+                    ans.setLoadBalancerHealthMonitorTimeout(this.getLoadBalancerHealthMonitorTimeout());
+                    break;
+                case "max_retries":
+                    ans.setLoadBalancerHealthMonitorMaxRetries(this.getLoadBalancerHealthMonitorMaxRetries());
+                    break;
+                case "http_method":
+                    ans.setLoadBalancerHealthMonitorHttpMethod(this.getLoadBalancerHealthMonitorHttpMethod());
+                    break;
+                case "url_path":
+                    ans.setLoadBalancerHealthMonitorUrlPath(this.getLoadBalancerHealthMonitorUrlPath());
+                    break;
+                case "expected_codes":
+                    ans.setLoadBalancerHealthMonitorExpectedCodes(this.getLoadBalancerHealthMonitorExpectedCodes());
+                    break;
+                case "admin_state_up":
+                    ans.setLoadBalancerHealthMonitorAdminStateIsUp(loadBalancerHealthMonitorAdminStateIsUp);
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancerHealthMonitor{" +
+                "loadBalancerHealthMonitorID='" + loadBalancerHealthMonitorID + '\'' +
+                ", loadBalancerHealthMonitorTenantID='" + loadBalancerHealthMonitorTenantID + '\'' +
+                ", loadBalancerHealthMonitorType='" + loadBalancerHealthMonitorType + '\'' +
+                ", loadBalancerHealthMonitorDelay=" + loadBalancerHealthMonitorDelay +
+                ", loadBalancerHealthMonitorTimeout=" + loadBalancerHealthMonitorTimeout +
+                ", loadBalancerHealthMonitorMaxRetries=" + loadBalancerHealthMonitorMaxRetries +
+                ", loadBalancerHealthMonitorHttpMethod='" + loadBalancerHealthMonitorHttpMethod + '\'' +
+                ", loadBalancerHealthMonitorUrlPath='" + loadBalancerHealthMonitorUrlPath + '\'' +
+                ", loadBalancerHealthMonitorExpectedCodes='" + loadBalancerHealthMonitorExpectedCodes + '\'' +
+                ", loadBalancerHealthMonitorAdminStateIsUp=" + loadBalancerHealthMonitorAdminStateIsUp +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerListener.java
new file mode 100644 (file)
index 0000000..b39604d
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * default_pool_id    String
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * shared             Bool
+ * protocol           String
+ * protocol_port      String
+ * load_balancer_id   String
+ * admin_state_up     Boolean
+ * status             String
+ *
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerListener
+    implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerListenerID;
+
+    @XmlElement (name = "default_pool_id")
+    String neutronLoadBalancerListenerDefaultPoolID;
+
+    @XmlElement (name = "connection_limit")
+    Integer neutronLoadBalancerListenerConnectionLimit;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerListenerTenantID;
+
+    @XmlElement (name = "name")
+    String loadBalancerListenerName;
+
+    @XmlElement (name = "description")
+    String loadBalancerListenerDescription;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean loadBalancerListenerAdminStateIsUp;
+
+    @XmlElement (name = "protocol")
+    String neutronLoadBalancerListenerProtocol;
+
+    @XmlElement (name = "protocol_port")
+    String neutronLoadBalancerListenerProtocolPort;
+
+    @XmlElement (name = "load_balancers")
+    List<Neutron_ID> neutronLoadBalancerListenerLoadBalancerIDs;
+
+    public String getID() {
+        return loadBalancerListenerID;
+    }
+
+    public void setID(String id) {
+        loadBalancerListenerID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerListenerID() {
+        return loadBalancerListenerID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerListenerID(String loadBalancerListenerID) {
+        this.loadBalancerListenerID = loadBalancerListenerID;
+    }
+
+    public String getLoadBalancerListenerTenantID() {
+        return loadBalancerListenerTenantID;
+    }
+
+    public void setLoadBalancerListenerTenantID(String loadBalancerListenerTenantID) {
+        this.loadBalancerListenerTenantID = loadBalancerListenerTenantID;
+    }
+
+    public String getLoadBalancerListenerName() {
+        return loadBalancerListenerName;
+    }
+
+    public void setLoadBalancerListenerName(String loadBalancerListenerName) {
+        this.loadBalancerListenerName = loadBalancerListenerName;
+    }
+
+    public String getLoadBalancerListenerDescription() {
+        return loadBalancerListenerDescription;
+    }
+
+    public void setLoadBalancerListenerDescription(String loadBalancerListenerDescription) {
+        this.loadBalancerListenerDescription = loadBalancerListenerDescription;
+    }
+
+    public Boolean getLoadBalancerListenerAdminStateIsUp() {
+        return loadBalancerListenerAdminStateIsUp;
+    }
+
+    public void setLoadBalancerListenerAdminStateIsUp(Boolean loadBalancerListenerAdminStateIsUp) {
+        this.loadBalancerListenerAdminStateIsUp = loadBalancerListenerAdminStateIsUp;
+    }
+
+    public String getNeutronLoadBalancerListenerProtocol() {
+        return neutronLoadBalancerListenerProtocol;
+    }
+
+    public void setNeutronLoadBalancerListenerProtocol(String neutronLoadBalancerListenerProtocol) {
+        this.neutronLoadBalancerListenerProtocol = neutronLoadBalancerListenerProtocol;
+    }
+
+    public String getNeutronLoadBalancerListenerProtocolPort() {
+        return neutronLoadBalancerListenerProtocolPort;
+    }
+
+    public void setNeutronLoadBalancerListenerProtocolPort(String neutronLoadBalancerListenerProtocolPort) {
+        this.neutronLoadBalancerListenerProtocolPort = neutronLoadBalancerListenerProtocolPort;
+    }
+
+    public String getNeutronLoadBalancerListenerDefaultPoolID() {
+        return neutronLoadBalancerListenerDefaultPoolID;
+    }
+
+    public void setNeutronLoadBalancerListenerDefaultPoolID(String neutronLoadBalancerListenerDefaultPoolID) {
+        this.neutronLoadBalancerListenerDefaultPoolID = neutronLoadBalancerListenerDefaultPoolID;
+    }
+
+    public Integer getNeutronLoadBalancerListenerConnectionLimit() {
+        return neutronLoadBalancerListenerConnectionLimit;
+    }
+
+    public void setNeutronLoadBalancerListenerConnectionLimit(Integer neutronLoadBalancerListenerConnectionLimit) {
+        this.neutronLoadBalancerListenerConnectionLimit = neutronLoadBalancerListenerConnectionLimit;
+    }
+
+    public List<Neutron_ID> getNeutronLoadBalancerListenerLoadBalancerIDs() {
+        return neutronLoadBalancerListenerLoadBalancerIDs;
+    }
+
+    public void setNeutronLoadBalancerListenerLoadBalancerIDs(List<Neutron_ID> neutronLoadBalancerListenerLoadBalancerIDs) {
+        this.neutronLoadBalancerListenerLoadBalancerIDs = neutronLoadBalancerListenerLoadBalancerIDs;
+    }
+
+    public NeutronLoadBalancerListener extractFields(List<String> fields) {
+        NeutronLoadBalancerListener ans = new NeutronLoadBalancerListener();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "default_pool_id":
+                    ans.setNeutronLoadBalancerListenerDefaultPoolID(this.getNeutronLoadBalancerListenerDefaultPoolID());
+                    break;
+                case "tenant_id":
+                    ans.setLoadBalancerListenerTenantID(this.getLoadBalancerListenerTenantID());
+                    break;
+                case "name":
+                    ans.setLoadBalancerListenerName(this.getLoadBalancerListenerName());
+                    break;
+                case "description":
+                    ans.setLoadBalancerListenerDescription(this.getLoadBalancerListenerDescription());
+                    break;
+                case "protocol":
+                    ans.setNeutronLoadBalancerListenerProtocol(this.getNeutronLoadBalancerListenerProtocol());
+                    break;
+                case "protocol_port":
+                    ans.setNeutronLoadBalancerListenerProtocolPort(this.getNeutronLoadBalancerListenerProtocolPort());
+                    break;
+                case "admin_state_up":
+                    ans.setLoadBalancerListenerAdminStateIsUp(loadBalancerListenerAdminStateIsUp);
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancerListener{" +
+                "loadBalancerListenerID='" + loadBalancerListenerID + '\'' +
+                ", neutronLoadBalancerListenerDefaultPoolID='" + neutronLoadBalancerListenerDefaultPoolID + '\'' +
+                ", neutronLoadBalancerListenerConnectionLimit='" + neutronLoadBalancerListenerConnectionLimit + '\'' +
+                ", loadBalancerListenerTenantID='" + loadBalancerListenerTenantID + '\'' +
+                ", loadBalancerListenerName='" + loadBalancerListenerName + '\'' +
+                ", loadBalancerListenerDescription='" + loadBalancerListenerDescription + '\'' +
+                ", loadBalancerListenerAdminStateIsUp=" + loadBalancerListenerAdminStateIsUp +
+                ", neutronLoadBalancerListenerProtocol='" + neutronLoadBalancerListenerProtocol + '\'' +
+                ", neutronLoadBalancerListenerProtocolPort='" + neutronLoadBalancerListenerProtocolPort + '\'' +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerPool.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerPool.java
new file mode 100644 (file)
index 0000000..a27a9a3
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * protocol           String
+ * lb_algorithm       String
+ * healthmonitor_id   String
+ * admin_state_up     Bool
+ * status             String
+ * members            List &lt;NeutronLoadBalancerPoolMember&gt;
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPool implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerPoolID;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerPoolTenantID;
+
+    @XmlElement (name = "name")
+    String loadBalancerPoolName;
+
+    @XmlElement (name = "description")
+    String loadBalancerPoolDescription;
+
+    @XmlElement (name = "protocol")
+    String loadBalancerPoolProtocol;
+
+    @XmlElement (name = "lb_algorithm")
+    String loadBalancerPoolLbAlgorithm;
+
+    @XmlElement (name = "healthmonitor_id")
+    String neutronLoadBalancerPoolHealthMonitorID;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean loadBalancerPoolAdminStateIsUp;
+
+    @XmlElement(name = "listeners")
+    List<Neutron_ID> loadBalancerPoolListeners;
+
+    @XmlElement(name = "session_persistence")
+    NeutronLoadBalancer_SessionPersistence loadBalancerPoolSessionPersistence;
+
+    @XmlElement(name = "members")
+    List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers;
+
+    public NeutronLoadBalancerPool() {
+    }
+
+    public String getID() {
+        return loadBalancerPoolID;
+    }
+
+    public void setID(String id) {
+        loadBalancerPoolID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerPoolID() {
+        return loadBalancerPoolID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerPoolID(String loadBalancerPoolID) {
+        this.loadBalancerPoolID = loadBalancerPoolID;
+    }
+
+    public String getLoadBalancerPoolTenantID() {
+        return loadBalancerPoolTenantID;
+    }
+
+    public void setLoadBalancerPoolTenantID(String loadBalancerPoolTenantID) {
+        this.loadBalancerPoolTenantID = loadBalancerPoolTenantID;
+    }
+
+    public String getLoadBalancerPoolName() {
+        return loadBalancerPoolName;
+    }
+
+    public void setLoadBalancerPoolName(String loadBalancerPoolName) {
+        this.loadBalancerPoolName = loadBalancerPoolName;
+    }
+
+    public String getLoadBalancerPoolDescription() {
+        return loadBalancerPoolDescription;
+    }
+
+    public void setLoadBalancerPoolDescription(String loadBalancerPoolDescription) {
+        this.loadBalancerPoolDescription = loadBalancerPoolDescription;
+    }
+
+    public String getLoadBalancerPoolProtocol() {
+        return loadBalancerPoolProtocol;
+    }
+
+    public void setLoadBalancerPoolProtocol(String loadBalancerPoolProtocol) {
+        this.loadBalancerPoolProtocol = loadBalancerPoolProtocol;
+    }
+
+    public String getLoadBalancerPoolLbAlgorithm() {
+        return loadBalancerPoolLbAlgorithm;
+    }
+
+    public void setLoadBalancerPoolLbAlgorithm(String loadBalancerPoolLbAlgorithm) {
+        this.loadBalancerPoolLbAlgorithm = loadBalancerPoolLbAlgorithm;
+    }
+
+    public String getNeutronLoadBalancerPoolHealthMonitorID() {
+        return neutronLoadBalancerPoolHealthMonitorID;
+    }
+
+    public void setNeutronLoadBalancerPoolHealthMonitorID(String neutronLoadBalancerPoolHealthMonitorID) {
+        this.neutronLoadBalancerPoolHealthMonitorID = neutronLoadBalancerPoolHealthMonitorID;
+    }
+
+    public Boolean getLoadBalancerPoolAdminIsStateIsUp() {
+        return loadBalancerPoolAdminStateIsUp;
+    }
+
+    public void setLoadBalancerPoolAdminStateIsUp(Boolean loadBalancerPoolAdminStateIsUp) {
+        this.loadBalancerPoolAdminStateIsUp = loadBalancerPoolAdminStateIsUp;
+    }
+
+    public NeutronLoadBalancer_SessionPersistence getLoadBalancerPoolSessionPersistence() {
+        return loadBalancerPoolSessionPersistence;
+    }
+
+    public void setLoadBalancerSessionPersistence(NeutronLoadBalancer_SessionPersistence loadBalancerPoolSessionPersistence) {
+        this.loadBalancerPoolSessionPersistence = loadBalancerPoolSessionPersistence;
+    }
+
+    public List<Neutron_ID> getLoadBalancerPoolListeners() {
+        return loadBalancerPoolListeners;
+    }
+
+    public void setLoadBalancerPoolListeners(List<Neutron_ID> loadBalancerPoolListeners) {
+        this.loadBalancerPoolListeners = loadBalancerPoolListeners;
+    }
+
+    public List<NeutronLoadBalancerPoolMember> getLoadBalancerPoolMembers() {
+        /*
+         * Update the pool_id of the member to that this.loadBalancerPoolID
+         */
+        if (loadBalancerPoolMembers != null) {
+            for (NeutronLoadBalancerPoolMember member: loadBalancerPoolMembers) {
+                member.setPoolID(loadBalancerPoolID);
+            }
+            return loadBalancerPoolMembers;
+        }
+        return loadBalancerPoolMembers;
+    }
+
+    public void setLoadBalancerPoolMembers(List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers) {
+        this.loadBalancerPoolMembers = loadBalancerPoolMembers;
+    }
+
+    public void addLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember) {
+        this.loadBalancerPoolMembers.add(loadBalancerPoolMember);
+    }
+
+    public void removeLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember) {
+        this.loadBalancerPoolMembers.remove(loadBalancerPoolMember);
+    }
+
+    public NeutronLoadBalancerPool extractFields(List<String> fields) {
+        NeutronLoadBalancerPool ans = new NeutronLoadBalancerPool();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "tenant_id":
+                    ans.setLoadBalancerPoolTenantID(this.getLoadBalancerPoolTenantID());
+                    break;
+                case "name":
+                    ans.setLoadBalancerPoolName(this.getLoadBalancerPoolName());
+                    break;
+                case "description":
+                    ans.setLoadBalancerPoolDescription(this.getLoadBalancerPoolDescription());
+                    break;
+                case "protocol":
+                    ans.setLoadBalancerPoolProtocol(this.getLoadBalancerPoolProtocol());
+                    break;
+                case "lb_algorithm":
+                    ans.setLoadBalancerPoolLbAlgorithm(this.getLoadBalancerPoolLbAlgorithm());
+                    break;
+                case "healthmonitor_id":
+                    ans.setNeutronLoadBalancerPoolHealthMonitorID(this.getNeutronLoadBalancerPoolHealthMonitorID());
+                    break;
+                case "admin_state_up":
+                    ans.setLoadBalancerPoolAdminStateIsUp(loadBalancerPoolAdminStateIsUp);
+                    break;
+                case "members":
+                    ans.setLoadBalancerPoolMembers(getLoadBalancerPoolMembers());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronLoadBalancerPool{" +
+            "id='" + loadBalancerPoolID + '\'' +
+            ", tenantID='" + loadBalancerPoolTenantID + '\'' +
+            ", name='" + loadBalancerPoolName + '\'' +
+            ", description='" + loadBalancerPoolDescription + '\'' +
+            ", protocol=" + loadBalancerPoolProtocol +'\''+
+            ", lbAlgorithm='" + loadBalancerPoolLbAlgorithm + '\'' +
+            ", healthmonitorID=" + neutronLoadBalancerPoolHealthMonitorID +
+            ", adminStateUp=" + loadBalancerPoolAdminStateIsUp +
+// todo: add loadBalancerPoolMembers as joined string
+            '}';
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerPoolMember.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancerPoolMember.java
new file mode 100644 (file)
index 0000000..12f0209
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import java.io.Serializable;
+import java.util.List;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPoolMember
+    implements Serializable, INeutronObject {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * TODO: Plumb into LBaaS Pool. Members are nested underneath Pool CRUD.
+     */
+    @XmlElement (name = "id")
+    String poolMemberID;
+
+    @XmlElement (name = "tenant_id")
+    String poolMemberTenantID;
+
+    @XmlElement (name = "address")
+    String poolMemberAddress;
+
+    @XmlElement (name = "protocol_port")
+    Integer poolMemberProtoPort;
+
+    @XmlElement (name = "admin_state_up")
+    Boolean poolMemberAdminStateIsUp;
+
+    @XmlElement (name = "weight")
+    Integer poolMemberWeight;
+
+    @XmlElement (name = "subnet_id")
+    String poolMemberSubnetID;
+
+    String poolID;
+
+    public NeutronLoadBalancerPoolMember() {
+    }
+
+    @XmlTransient
+    public String getPoolID() {
+        return poolID;
+    }
+
+    public void setPoolID(String poolID) {
+        this.poolID = poolID;
+    }
+
+    public String getID() {
+        return poolMemberID;
+    }
+
+    public void setID(String id) {
+        poolMemberID = id;
+    }
+
+    // @deprecated use getID()
+    public String getPoolMemberID() {
+        return poolMemberID;
+    }
+
+    // @deprecated use setID()
+    public void setPoolMemberID(String poolMemberID) {
+        this.poolMemberID = poolMemberID;
+    }
+
+    public String getPoolMemberTenantID() {
+        return poolMemberTenantID;
+    }
+
+    public void setPoolMemberTenantID(String poolMemberTenantID) {
+        this.poolMemberTenantID = poolMemberTenantID;
+    }
+
+    public String getPoolMemberAddress() {
+        return poolMemberAddress;
+    }
+
+    public void setPoolMemberAddress(String poolMemberAddress) {
+        this.poolMemberAddress = poolMemberAddress;
+    }
+
+    public Integer getPoolMemberProtoPort() {
+        return poolMemberProtoPort;
+    }
+
+    public void setPoolMemberProtoPort(Integer poolMemberProtoPort) {
+        this.poolMemberProtoPort = poolMemberProtoPort;
+    }
+
+    public Boolean getPoolMemberAdminStateIsUp() {
+        return poolMemberAdminStateIsUp;
+    }
+
+    public void setPoolMemberAdminStateIsUp(Boolean poolMemberAdminStateIsUp) {
+        this.poolMemberAdminStateIsUp = poolMemberAdminStateIsUp;
+    }
+
+    public Integer getPoolMemberWeight() {
+        return poolMemberWeight;
+    }
+
+    public void setPoolMemberWeight(Integer poolMemberWeight) {
+        this.poolMemberWeight = poolMemberWeight;
+    }
+
+    public String getPoolMemberSubnetID() {
+        return poolMemberSubnetID;
+    }
+
+    public void setPoolMemberSubnetID(String poolMemberSubnetID) {
+        this.poolMemberSubnetID = poolMemberSubnetID;
+    }
+
+    public NeutronLoadBalancerPoolMember extractFields(List<String> fields) {
+        NeutronLoadBalancerPoolMember ans = new NeutronLoadBalancerPoolMember();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "pool_id":
+                    ans.setPoolID(this.getPoolID());
+                    break;
+                case "tenant_id":
+                    ans.setPoolMemberTenantID(this.getPoolMemberTenantID());
+                    break;
+                case "address":
+                    ans.setPoolMemberAddress(this.getPoolMemberAddress());
+                    break;
+                case "protocol_port":
+                    ans.setPoolMemberProtoPort(this.getPoolMemberProtoPort());
+                    break;
+                case "admin_state_up":
+                    ans.setPoolMemberAdminStateIsUp(poolMemberAdminStateIsUp);
+                    break;
+                case "weight":
+                    ans.setPoolMemberWeight(this.getPoolMemberWeight());
+                    break;
+                case "subnet_id":
+                    ans.setPoolMemberSubnetID(this.getPoolMemberSubnetID());
+                    break;
+            }
+        }
+        return ans;
+    }
+    @Override public String toString() {
+        return "NeutronLoadBalancerPoolMember{" +
+                "poolMemberID='" + poolMemberID + '\'' +
+                ", poolID='" + poolID + '\'' +
+                ", poolMemberTenantID='" + poolMemberTenantID + '\'' +
+                ", poolMemberAddress='" + poolMemberAddress + '\'' +
+                ", poolMemberProtoPort=" + poolMemberProtoPort +
+                ", poolMemberAdminStateIsUp=" + poolMemberAdminStateIsUp +
+                ", poolMemberWeight=" + poolMemberWeight +
+                ", poolMemberSubnetID='" + poolMemberSubnetID + '\'' +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancer_SessionPersistence.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronLoadBalancer_SessionPersistence.java
new file mode 100644 (file)
index 0000000..10b7d3e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronLoadBalancer_SessionPersistence implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "cookie_name")
+    String cookieName;
+
+    @XmlElement(name = "type")
+    String type;
+
+    public NeutronLoadBalancer_SessionPersistence() {
+    }
+
+    public NeutronLoadBalancer_SessionPersistence(String cookieName, String type) {
+        this.cookieName = cookieName;
+        this.type = type;
+    }
+
+    public String getCookieName() {
+        return cookieName;
+    }
+
+    public void setCookieName(String cookieName) {
+        this.cookieName = cookieName;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronNetwork.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronNetwork.java
new file mode 100644 (file)
index 0000000..769ee3b
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "network")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronNetwork implements Serializable, INeutronObject {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "id")
+    String networkUUID;
+
+    @XmlElement (name = "name")
+    String networkName;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean adminStateUp;
+
+    @XmlElement (defaultValue = "false", name = "shared")
+    Boolean shared;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    //    @XmlElement (defaultValue = "false", name = "router:external")
+    @XmlElement (defaultValue="false", namespace="router", name="external")
+    Boolean routerExternal;
+
+    //    @XmlElement (defaultValue = "flat", name = "provider:network_type")
+    @XmlElement (namespace="provider", name="network_type")
+    String providerNetworkType;
+
+    //    @XmlElement (name = "provider:physical_network")
+    @XmlElement (namespace="provider", name="physical_network")
+    String providerPhysicalNetwork;
+
+    //    @XmlElement (name = "provider:segmentation_id")
+    @XmlElement (namespace="provider", name="segmentation_id")
+    String providerSegmentationID;
+
+    @XmlElement (name = "status")
+    String status;
+
+    @XmlElement (name="segments")
+    List<NeutronNetwork_Segment> segments;
+
+    @XmlElement (name="vlan_transparent")
+    Boolean vlanTransparent;
+
+    @XmlElement (name="mtu")
+    Integer mtu;
+
+    /* This attribute lists the ports associated with an instance
+     * which is needed for determining if that instance can be deleted
+     */
+
+    public NeutronNetwork() {
+    }
+
+    public void initDefaults() {
+        if (status == null) {
+            status = "ACTIVE";
+        }
+        if (adminStateUp == null) {
+            adminStateUp = true;
+        }
+        if (shared == null) {
+            shared = false;
+        }
+        if (routerExternal == null) {
+            routerExternal = false;
+        }
+        if (providerNetworkType == null) {
+            providerNetworkType = "flat";
+        }
+    }
+
+    public String getID() { return networkUUID; }
+
+    public void setID(String id) { this.networkUUID = id; }
+
+    public String getNetworkUUID() {
+        return networkUUID;
+    }
+
+    public void setNetworkUUID(String networkUUID) {
+        this.networkUUID = networkUUID;
+    }
+
+    public String getNetworkName() {
+        return networkName;
+    }
+
+    public void setNetworkName(String networkName) {
+        this.networkName = networkName;
+    }
+
+    public boolean isAdminStateUp() {
+        return adminStateUp;
+    }
+
+    public Boolean getAdminStateUp() { return adminStateUp; }
+
+    public void setAdminStateUp(boolean newValue) {
+        adminStateUp = newValue;
+    }
+
+    public boolean isShared() { return shared; }
+
+    public Boolean getShared() { return shared; }
+
+    public void setShared(boolean newValue) {
+        shared = newValue;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public boolean isRouterExternal() { return routerExternal; }
+
+    public Boolean getRouterExternal() { return routerExternal; }
+
+    public void setRouterExternal(boolean newValue) {
+        routerExternal = newValue;
+    }
+
+    public String getProviderNetworkType() {
+        return providerNetworkType;
+    }
+
+    public void setProviderNetworkType(String providerNetworkType) {
+        this.providerNetworkType = providerNetworkType;
+    }
+
+    public String getProviderPhysicalNetwork() {
+        return providerPhysicalNetwork;
+    }
+
+    public void setProviderPhysicalNetwork(String providerPhysicalNetwork) {
+        this.providerPhysicalNetwork = providerPhysicalNetwork;
+    }
+
+    public String getProviderSegmentationID() {
+        return providerSegmentationID;
+    }
+
+    public void setProviderSegmentationID(String providerSegmentationID) {
+        this.providerSegmentationID = providerSegmentationID;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public void setSegments(List<NeutronNetwork_Segment> segments) {
+        this.segments = segments;
+    }
+
+    public List<NeutronNetwork_Segment> getSegments() {
+        return segments;
+    }
+
+    public Boolean getVlanTransparent() {
+        return vlanTransparent;
+    }
+
+    public void setVlanTransparent(Boolean input) {
+        this.vlanTransparent = input;
+    }
+
+    public Integer getMtu() {
+        return mtu;
+    }
+
+    public void setMtu(Integer input) {
+        mtu = input;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackNetworks object with only the selected fields
+     * populated
+     */
+
+    public NeutronNetwork extractFields(List<String> fields) {
+        NeutronNetwork ans = new NeutronNetwork();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setNetworkUUID(this.getNetworkUUID());
+                    break;
+                case "name":
+                    ans.setNetworkName(this.getNetworkName());
+                    break;
+                case "admin_state_up":
+                    ans.setAdminStateUp(adminStateUp);
+                    break;
+                case "status":
+                    ans.setStatus(this.getStatus());
+                    break;
+                case "shared":
+                    ans.setShared(shared);
+                    break;
+                case "tenant_id":
+                    ans.setTenantID(this.getTenantID());
+                    break;
+                case "external":
+                    ans.setRouterExternal(this.getRouterExternal());
+                    break;
+                case "segmentation_id":
+                    ans.setProviderSegmentationID(this.getProviderSegmentationID());
+                    break;
+                case "physical_network":
+                    ans.setProviderPhysicalNetwork(this.getProviderPhysicalNetwork());
+                    break;
+                case "network_type":
+                    ans.setProviderNetworkType(this.getProviderNetworkType());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronNetwork [networkUUID=" + networkUUID + ", networkName=" + networkName + ", adminStateUp="
+                + adminStateUp + ", shared=" + shared + ", tenantID=" + tenantID + ", routerExternal=" + routerExternal
+                + ", providerNetworkType=" + providerNetworkType + ", providerPhysicalNetwork="
+                + providerPhysicalNetwork + ", providerSegmentationID=" + providerSegmentationID + ", status=" + status
+                + ", segments = " + segments + "]";
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronNetwork_Segment.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronNetwork_Segment.java
new file mode 100644 (file)
index 0000000..e0f8a81
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "network")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronNetwork_Segment implements Serializable {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    private static final long serialVersionUID = 1L;
+
+    //    @XmlElement (defaultValue="flat", name="provider:network_type")
+    @XmlElement (defaultValue="flat", namespace="provider", name="network_type")
+    String providerNetworkType;
+
+    //    @XmlElement (name="provider:physical_network")
+    @XmlElement (namespace="provider", name="physical_network")
+    String providerPhysicalNetwork;
+
+    //    @XmlElement (name="provider:segmentation_id")
+    @XmlElement (namespace="provider", name="segmentation_id")
+    String providerSegmentationID;
+
+    public NeutronNetwork_Segment() {
+    }
+
+    public String getProviderNetworkType() {
+        return providerNetworkType;
+    }
+
+    public void setProviderNetworkType(String providerNetworkType) {
+        this.providerNetworkType = providerNetworkType;
+    }
+
+    public String getProviderPhysicalNetwork() {
+        return providerPhysicalNetwork;
+    }
+
+    public void setProviderPhysicalNetwork(String providerPhysicalNetwork) {
+        this.providerPhysicalNetwork = providerPhysicalNetwork;
+    }
+
+    public String getProviderSegmentationID() {
+        return providerSegmentationID;
+    }
+
+    public void setProviderSegmentationID(String providerSegmentationID) {
+        this.providerSegmentationID = providerSegmentationID;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronNetwork_Segment [ " +
+               ", providerNetworkType=" + providerNetworkType +
+               ", providerPhysicalNetwork=" + providerPhysicalNetwork +
+               ", providerSegmentationID=" + providerSegmentationID + "]";
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort.java
new file mode 100644 (file)
index 0000000..a7b4a61
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronPort implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "id")
+    String portUUID;
+
+    @XmlElement (name = "network_id")
+    String networkUUID;
+
+    @XmlElement (name = "name")
+    String name;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean adminStateUp;
+
+    @XmlElement (name = "status")
+    String status;
+
+    @XmlElement (name = "mac_address")
+    String macAddress;
+
+    @XmlElement (name = "fixed_ips")
+    List<Neutron_IPs> fixedIPs;
+
+    @XmlElement (name = "device_id")
+    String deviceID;
+
+    @XmlElement (name = "device_owner")
+    String deviceOwner;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    @XmlElement (name = "security_groups")
+    List<NeutronSecurityGroup> securityGroups;
+
+    @XmlElement (name = "allowed_address_pairs")
+    List<NeutronPort_AllowedAddressPairs> allowedAddressPairs;
+
+    //@XmlElement (name = "binding:host_id")
+    @XmlElement (namespace = "binding", name = "host_id")
+    String bindinghostID;
+
+    //@XmlElement (name = "binding:vnic_type")
+    @XmlElement (namespace = "binding", name = "vnic_type")
+    String bindingvnicType;
+
+    //@XmlElement (name = "binding:vif_type")
+    @XmlElement (namespace = "binding", name = "vif_type")
+    String bindingvifType;
+
+    //@XmlElement (name = "binding:vif_details")
+    @XmlElement (namespace = "binding", name = "vif_details")
+    List<NeutronPort_VIFDetail> vifDetails;
+
+    @XmlElement (name = "extra_dhcp_opts")
+    List<NeutronPort_ExtraDHCPOption> extraDHCPOptions;
+
+    //Port security is enabled by default for backward compatibility.
+    @XmlElement (defaultValue = "true", name = "port_security_enabled")
+    Boolean portSecurityEnabled;
+
+
+    NeutronPort originalPort;
+
+    public NeutronPort() {
+    }
+
+    public String getID() { return portUUID; }
+
+    public void setID(String id) { this.portUUID = id; }
+
+    public String getPortUUID() {
+        return portUUID;
+    }
+
+    public void setPortUUID(String portUUID) {
+        this.portUUID = portUUID;
+    }
+
+    public String getNetworkUUID() {
+        return networkUUID;
+    }
+
+    public void setNetworkUUID(String networkUUID) {
+        this.networkUUID = networkUUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isAdminStateUp() {
+        if (adminStateUp == null) {
+            return true;
+        }
+        return adminStateUp;
+    }
+
+    public Boolean getAdminStateUp() { return adminStateUp; }
+
+    public void setAdminStateUp(Boolean newValue) {
+            adminStateUp = newValue;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getMacAddress() {
+        return macAddress;
+    }
+
+    public void setMacAddress(String macAddress) {
+        this.macAddress = macAddress;
+    }
+
+    public List<Neutron_IPs> getFixedIPs() {
+        return fixedIPs;
+    }
+
+    public void setFixedIPs(List<Neutron_IPs> fixedIPs) {
+        this.fixedIPs = fixedIPs;
+    }
+
+    public String getDeviceID() {
+        return deviceID;
+    }
+
+    public void setDeviceID(String deviceID) {
+        this.deviceID = deviceID;
+    }
+
+    public String getDeviceOwner() {
+        return deviceOwner;
+    }
+
+    public void setDeviceOwner(String deviceOwner) {
+        this.deviceOwner = deviceOwner;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public List<NeutronSecurityGroup> getSecurityGroups() {
+        return securityGroups;
+    }
+
+    public void setSecurityGroups(List<NeutronSecurityGroup> securityGroups) {
+        this.securityGroups = securityGroups;
+    }
+
+    public List<NeutronPort_AllowedAddressPairs> getAllowedAddressPairs() {
+        return allowedAddressPairs;
+    }
+
+    public void setAllowedAddressPairs(List<NeutronPort_AllowedAddressPairs> allowedAddressPairs) {
+        this.allowedAddressPairs = allowedAddressPairs;
+    }
+
+    public List<NeutronPort_ExtraDHCPOption> getExtraDHCPOptions() {
+        return extraDHCPOptions;
+    }
+
+    public void setExtraDHCPOptions(List<NeutronPort_ExtraDHCPOption> extraDHCPOptions) {
+        this.extraDHCPOptions = extraDHCPOptions;
+    }
+
+    public List<NeutronPort_VIFDetail> getVIFDetail() {
+        return vifDetails;
+    }
+
+    public void setVIFDetail(List<NeutronPort_VIFDetail> vifDetails) {
+        this.vifDetails = vifDetails;
+    }
+
+    public String getBindinghostID() {
+      return bindinghostID;
+    }
+
+    public void setBindinghostID(String bindinghostID) {
+      this.bindinghostID = bindinghostID;
+    }
+
+    public String getBindingvnicType() {
+        return bindingvnicType;
+    }
+
+    public void setBindingvnicType(String bindingvnicType) {
+        this.bindingvnicType = bindingvnicType;
+    }
+
+    public String getBindingvifType() {
+        return bindingvifType;
+    }
+
+    public void setBindingvifType(String bindingvifType) {
+        this.bindingvifType = bindingvifType;
+    }
+
+    public Boolean getPortSecurityEnabled() {
+        if (portSecurityEnabled == null) {
+            return true;
+        }
+        return portSecurityEnabled;
+    }
+
+    public void setPortSecurityEnabled(Boolean newValue) {
+        portSecurityEnabled = newValue;
+    }
+
+
+    public NeutronPort getOriginalPort() {
+        return originalPort;
+    }
+
+
+    public void setOriginalPort(NeutronPort originalPort) {
+        this.originalPort = originalPort;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackPorts object with only the selected fields
+     * populated
+     */
+
+    public NeutronPort extractFields(List<String> fields) {
+        NeutronPort ans = new NeutronPort();
+        for (String field: fields) {
+            if ("id".equals(field)) {
+                ans.setPortUUID(this.getPortUUID());
+            }
+            if ("network_id".equals(field)) {
+                ans.setNetworkUUID(this.getNetworkUUID());
+            }
+            if ("name".equals(field)) {
+                ans.setName(this.getName());
+            }
+            if ("admin_state_up".equals(field)) {
+                ans.setAdminStateUp(this.getAdminStateUp());
+            }
+            if ("status".equals(field)) {
+                ans.setStatus(this.getStatus());
+            }
+            if ("mac_address".equals(field)) {
+                ans.setMacAddress(this.getMacAddress());
+            }
+            if ("fixed_ips".equals(field)) {
+                ans.setFixedIPs(new ArrayList<>(this.getFixedIPs()));
+            }
+            if ("device_id".equals(field)) {
+                ans.setDeviceID(this.getDeviceID());
+            }
+            if ("device_owner".equals(field)) {
+                ans.setDeviceOwner(this.getDeviceOwner());
+            }
+            if ("tenant_id".equals(field)) {
+                ans.setTenantID(this.getTenantID());
+            }
+            if ("security_groups".equals(field)) {
+                ans.setSecurityGroups(new ArrayList<>(this.getSecurityGroups()));
+            }
+            if ("port_security_enabled".equals(field)) {
+                ans.setPortSecurityEnabled(this.getPortSecurityEnabled());
+            }
+        }
+        return ans;
+    }
+
+    public void initDefaults() {
+        adminStateUp = true;
+        portSecurityEnabled = true;
+        if (status == null) {
+            status = "ACTIVE";
+        }
+        if (fixedIPs == null) {
+            fixedIPs = new ArrayList<>();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronPort [portUUID=" + portUUID + ", networkUUID=" + networkUUID + ", name=" + name
+                + ", adminStateUp=" + adminStateUp + ", status=" + status + ", macAddress=" + macAddress
+                + ", fixedIPs=" + fixedIPs + ", deviceID=" + deviceID + ", deviceOwner=" + deviceOwner + ", tenantID="
+                + tenantID + ", securityGroups=" + securityGroups
+                + ", bindinghostID=" + bindinghostID + ", bindingvnicType=" + bindingvnicType
+                + ", bindingvnicType=" + bindingvnicType + ", portSecurityEnabled=" + portSecurityEnabled +"]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_AllowedAddressPairs.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_AllowedAddressPairs.java
new file mode 100644 (file)
index 0000000..54f8f00
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_AllowedAddressPairs implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "port_id")
+    String portID;
+
+    @XmlElement (name = "mac_address")
+    String macAddress;
+
+    @XmlElement (name = "ip_address")
+    String ipAddress;
+
+    public NeutronPort_AllowedAddressPairs() {
+    }
+
+    public NeutronPort_AllowedAddressPairs(String portID, String macAddress, String ipAddress) {
+        this.portID = portID;
+        this.macAddress = macAddress;
+        this.ipAddress = ipAddress;
+    }
+
+    public String getPortID() { return(portID); }
+
+    public void setPortID(String portID) { this.portID = portID; }
+
+    public String getMacAddress() { return(macAddress); }
+
+    public void setMacAddress(String macAddress) { this.macAddress = macAddress; }
+
+    public String getIpAddress() { return(ipAddress); }
+
+    public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_ExtraDHCPOption.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_ExtraDHCPOption.java
new file mode 100644 (file)
index 0000000..bd97aa9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_ExtraDHCPOption implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "opt_value")
+    String value;
+
+    @XmlElement (name = "opt_name")
+    String name;
+
+    public NeutronPort_ExtraDHCPOption() {
+    }
+
+    public NeutronPort_ExtraDHCPOption(String value, String name) {
+        this.value = value;
+        this.name = name;
+    }
+
+    public String getValue() { return(value); }
+
+    public void setValue(String value) { this.value = value; }
+
+    public String getName() { return(name); }
+
+    public void setName(String name) { this.name = name; }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_VIFDetail.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronPort_VIFDetail.java
new file mode 100644 (file)
index 0000000..f4668b3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_VIFDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "port_filter")
+    Boolean portFilter;
+
+    @XmlElement (name = "ovs_hybrid_plug")
+    Boolean ovsHybridPlug;
+
+    public NeutronPort_VIFDetail() {
+    }
+
+    public NeutronPort_VIFDetail(Boolean portFilter, Boolean ovsHybridPlug) {
+        this.portFilter = portFilter;
+        this.ovsHybridPlug = ovsHybridPlug;
+    }
+
+    public Boolean getPortFilter() { return(portFilter); }
+
+    public void setPortFilter(Boolean portFilter) { this.portFilter = portFilter; }
+
+    public Boolean getOvsHybridPlug() { return(ovsHybridPlug); }
+
+    public void setOvsHybridPlug(Boolean ovsHybridPlug) { this.ovsHybridPlug = ovsHybridPlug; }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter.java
new file mode 100644 (file)
index 0000000..050c784
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouter implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+    @XmlElement (name = "id")
+    String routerUUID;
+
+    @XmlElement (name = "name")
+    String name;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean adminStateUp;
+
+    @XmlElement (name = "status")
+    String status;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    @XmlElement (name = "external_gateway_info", nillable = true)
+    NeutronRouter_NetworkReference externalGatewayInfo;
+
+    @XmlElement (name = "distributed")
+    Boolean distributed;
+
+    @XmlElement (name = "gw_port_id", nillable = true)
+    String gatewayPortId;
+
+    @XmlElement (name = "routes")
+    List<Routes> routes;
+
+    /* Holds a map of OpenStackRouterInterfaces by subnet UUID
+     * used for internal mapping to DOVE
+     */
+    Map<String, NeutronRouter_Interface> interfaces;
+
+    public NeutronRouter() {
+        interfaces = new HashMap<>();
+    }
+
+    public String getID() { return routerUUID; }
+
+    public void setID(String id) { this.routerUUID = id; }
+
+    public String getRouterUUID() {
+        return routerUUID;
+    }
+
+    public void setRouterUUID(String routerUUID) {
+        this.routerUUID = routerUUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isAdminStateUp() {
+        if (adminStateUp == null) {
+            return true;
+        }
+        return adminStateUp;
+    }
+
+    public Boolean getAdminStateUp() { return adminStateUp; }
+
+    public void setAdminStateUp(Boolean newValue) {
+        adminStateUp = newValue;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public NeutronRouter_NetworkReference getExternalGatewayInfo() {
+        return externalGatewayInfo;
+    }
+
+    public void setExternalGatewayInfo(NeutronRouter_NetworkReference externalGatewayInfo) {
+        this.externalGatewayInfo = externalGatewayInfo;
+    }
+
+    public Boolean getDistributed() {
+        return distributed;
+    }
+
+    public void setDistributed(Boolean distributed) {
+        this.distributed = distributed;
+    }
+
+    public String getGatewayPortId() {
+        return gatewayPortId;
+    }
+
+    public void setGatewayPortId(String gatewayPortId) {
+        this.gatewayPortId = gatewayPortId;
+    }
+
+    public List<Routes> getRoutes() {
+        return routes;
+    }
+
+    public void setRoutes(List<Routes> routes) {
+        this.routes = routes;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackRouters object with only the selected fields
+     * populated
+     */
+    public NeutronRouter extractFields(List<String> fields) {
+        NeutronRouter ans = new NeutronRouter();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setRouterUUID(this.getRouterUUID());
+                    break;
+                case "name":
+                    ans.setName(this.getName());
+                    break;
+                case "admin_state_up":
+                    ans.setAdminStateUp(this.getAdminStateUp());
+                    break;
+                case "status":
+                    ans.setStatus(this.getStatus());
+                    break;
+                case "tenant_id":
+                    ans.setTenantID(this.getTenantID());
+                    break;
+                case "external_gateway_info":
+                    ans.setExternalGatewayInfo(this.getExternalGatewayInfo());
+                    break;
+                case "distributed":
+                    ans.setDistributed(this.getDistributed());
+                    break;
+                case "gw_port_id":
+                    ans.setGatewayPortId(this.getGatewayPortId());
+                    break;
+                case "routes":
+                    ans.setRoutes(this.getRoutes());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    public void setInterfaces(Map<String, NeutronRouter_Interface> input) {
+        interfaces = input;
+    }
+
+    public Map<String, NeutronRouter_Interface> getInterfaces() {
+        return interfaces;
+    }
+
+    public void addInterface(String s, NeutronRouter_Interface i) {
+        interfaces.put(s, i);
+    }
+
+    public void removeInterface(String s) {
+        interfaces.remove(s);
+    }
+
+    public void initDefaults() {
+        adminStateUp = true;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronRouter [" +
+            "id=" + routerUUID +
+            ", name=" + name +
+            ", adminStateUp=" + adminStateUp +
+            ", status=" + status +
+            ", tenantID=" + tenantID +
+            ", external_gateway_info=" + externalGatewayInfo +
+            ", distributed=" + distributed +
+            ", gw_port_id=" + gatewayPortId +
+            ", routes=" + routes +
+            ", interfaces=" + interfaces +
+            "]";
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter_Interface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter_Interface.java
new file mode 100644 (file)
index 0000000..694b0d4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronRouter_Interface implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "subnet_id")
+    String subnetUUID;
+
+    @XmlElement (name = "port_id")
+    String portUUID;
+
+    @XmlElement (name = "id")
+    String id;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    public NeutronRouter_Interface() {
+    }
+
+    public NeutronRouter_Interface(String subnetUUID, String portUUID) {
+        this.subnetUUID = subnetUUID;
+        this.portUUID = portUUID;
+    }
+
+    public String getSubnetUUID() {
+        return subnetUUID;
+    }
+
+    public void setSubnetUUID(String subnetUUID) {
+        this.subnetUUID = subnetUUID;
+    }
+
+    public String getPortUUID() {
+        return portUUID;
+    }
+
+    public void setPortUUID(String portUUID) {
+        this.portUUID = portUUID;
+    }
+
+    public String getID() {
+        return id;
+    }
+
+    public void setID(String id) {
+        this.id = id;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronRouterInterface [" +
+            "subnetUUID=" + subnetUUID +
+            ", portUUID=" + portUUID +
+            ", id=" + id +
+            ", tenantID=" + tenantID + "]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter_NetworkReference.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronRouter_NetworkReference.java
new file mode 100644 (file)
index 0000000..9e0ceca
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouter_NetworkReference implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "network_id")
+    String networkID;
+
+    @XmlElement(name = "enable_snat")
+    Boolean enableSNAT;
+
+    @XmlElement(name = "external_fixed_ips")
+    List<Neutron_IPs> externalFixedIPs;
+
+    public NeutronRouter_NetworkReference() {
+    }
+
+    public String getNetworkID() {
+        return networkID;
+    }
+
+    public void setNetworkID(String networkID) {
+        this.networkID = networkID;
+    }
+
+    public Boolean getEnableSNAT() {
+        return enableSNAT;
+    }
+
+    public void setEnableSNAT(Boolean enableSNAT) {
+        this.enableSNAT = enableSNAT;
+    }
+
+    public List<Neutron_IPs> getExternalFixedIPs() {
+        return externalFixedIPs;
+    }
+
+    public void setExternalFixedIPs(List<Neutron_IPs> externalFixedIPs) {
+        this.externalFixedIPs = externalFixedIPs;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronRouterNetworkReference [networkID=" + networkID +
+            " enableSNAT=" + enableSNAT +
+            " externalFixedIPs=" + externalFixedIPs + "]";
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSecurityGroup.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSecurityGroup.java
new file mode 100644 (file)
index 0000000..78a61dd
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * OpenStack Neutron v2.0 Security Group bindings.
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p>
+ * id                   uuid-str unique ID for the security group.
+ * name                 String name of the security group.
+ * description          String name of the security group.
+ * tenant_id            uuid-str Owner of security rule..
+ * security_group_rules List&lt;NeutronSecurityRule&gt; nested RO in the sec group.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityGroup implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String securityGroupUUID;
+
+    @XmlElement(name = "name")
+    String securityGroupName;
+
+    @XmlElement(name = "description")
+    String securityGroupDescription;
+
+    @XmlElement(name = "tenant_id")
+    String securityGroupTenantID;
+
+    @XmlElement(name = "security_group_rules")
+    List<NeutronSecurityRule> neutronSecurityRule;
+
+    public NeutronSecurityGroup() {
+        neutronSecurityRule = new ArrayList<>();
+
+    }
+
+    public String getID() {
+        return securityGroupUUID;
+    }
+
+    public void setID(String id) {
+        securityGroupUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getSecurityGroupUUID() {
+        return securityGroupUUID;
+    }
+
+    // @deprecated use setID()
+    public void setSecurityGroupUUID(String securityGroupUUID) {
+        this.securityGroupUUID = securityGroupUUID;
+    }
+
+    public String getSecurityGroupName() {
+        return securityGroupName;
+    }
+
+    public void setSecurityGroupName(String securityGroupName) {
+        this.securityGroupName = securityGroupName;
+    }
+
+    public String getSecurityGroupDescription() {
+        return securityGroupDescription;
+    }
+
+    public void setSecurityGroupDescription(String securityGroupDescription) {
+        this.securityGroupDescription = securityGroupDescription;
+    }
+
+    public String getSecurityGroupTenantID() {
+        return securityGroupTenantID;
+    }
+
+    public void setSecurityGroupTenantID(String securityGroupTenantID) {
+        this.securityGroupTenantID = securityGroupTenantID;
+    }
+
+    // Rules In Group
+    public List<NeutronSecurityRule> getSecurityRules() {
+        return neutronSecurityRule;
+    }
+
+    public void setSecurityRules(List<NeutronSecurityRule> neutronSecurityRule) {
+        this.neutronSecurityRule = neutronSecurityRule;
+    }
+
+    public NeutronSecurityGroup extractFields(List<String> fields) {
+        NeutronSecurityGroup ans = new NeutronSecurityGroup ();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "name":
+                    ans.setSecurityGroupName(this.getSecurityGroupName());
+                    break;
+                case "description":
+                    ans.setSecurityGroupDescription(this.getSecurityGroupDescription());
+                    break;
+                case "tenant_id":
+                    ans.setSecurityGroupTenantID(this.getSecurityGroupTenantID());
+                    break;
+                case "security_group_rules":
+                    ans.setSecurityRules(this.getSecurityRules());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSecurityGroup{" +
+                "securityGroupUUID='" + securityGroupUUID + '\'' +
+                ", securityGroupName='" + securityGroupName + '\'' +
+                ", securityGroupDescription='" + securityGroupDescription + '\'' +
+                ", securityGroupTenantID='" + securityGroupTenantID + '\'' +
+                ", securityRules=" + neutronSecurityRule + "]";
+    }
+
+    public void initDefaults() {
+        //TODO verify no defaults values are nessecary required.
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSecurityRule.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSecurityRule.java
new file mode 100644 (file)
index 0000000..f354e5b
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p>
+ * id                uuid (String) UUID for the security group rule.
+ * security_rule_id  uuid (String) The security group to associate rule.
+ * direction         String Direction the VM traffic  (ingress/egress).
+ * security_group_id The security group to associate rule with.
+ * protocol          String IP Protocol (icmp, tcp, udp, etc).
+ * port_range_min    Integer Port at start of range
+ * port_range_max    Integer Port at end of range
+ * ethertype         String ethertype in L2 packet (IPv4, IPv6, etc)
+ * remote_ip_prefix  String (IP cidr) CIDR for address range.
+ * remote_group_id   uuid-str Source security group to apply to rule.
+ * tenant_id         uuid-str Owner of security rule. Admin only outside tenant.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityRule implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String securityRuleUUID;
+
+    public static final String DIRECTION_EGRESS = "egress";
+    public static final String DIRECTION_INGRESS = "ingress";
+
+    @XmlElement(name = "direction")
+    String securityRuleDirection;
+
+    public static final String PROTOCOL_ICMP = "icmp";
+    public static final String PROTOCOL_TCP = "tcp";
+    public static final String PROTOCOL_UDP = "udp";
+    public static final String PROTOCOL_ICMPV6 = "icmpv6";
+
+    @XmlElement(name = "protocol")
+    String securityRuleProtocol;
+
+    @XmlElement(name = "port_range_min")
+    Integer securityRulePortMin;
+
+    @XmlElement(name = "port_range_max")
+    Integer securityRulePortMax;
+
+    public static final String ETHERTYPE_IPV4 = "IPv4";
+    public static final String ETHERTYPE_IPV6 = "IPv6";
+
+    @XmlElement(name = "ethertype")
+    String securityRuleEthertype;
+
+    @XmlElement(name = "remote_ip_prefix")
+    String securityRuleRemoteIpPrefix;
+
+    @XmlElement(name = "remote_group_id")
+    String securityRemoteGroupID;
+
+    @XmlElement(name = "security_group_id")
+    String securityRuleGroupID;
+
+    @XmlElement(name = "tenant_id")
+    String securityRuleTenantID;
+
+    public NeutronSecurityRule() {
+    }
+
+    public String getID() {
+        return securityRuleUUID;
+    }
+
+    public void setID(String id) {
+        securityRuleUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getSecurityRuleUUID() {
+        return securityRuleUUID;
+    }
+
+    // @deprecated use setID()
+    public void setSecurityRuleUUID(String securityRuleUUID) {
+        this.securityRuleUUID = securityRuleUUID;
+    }
+
+    public String getSecurityRuleDirection() {
+        return securityRuleDirection;
+    }
+
+    public void setSecurityRuleDirection(String securityRuleDirection) {
+        this.securityRuleDirection = securityRuleDirection;
+    }
+
+    public String getSecurityRuleProtocol() {
+        return securityRuleProtocol;
+    }
+
+    public void setSecurityRuleProtocol(String securityRuleProtocol) {
+        this.securityRuleProtocol = securityRuleProtocol;
+    }
+
+    public Integer getSecurityRulePortMin() {
+        return securityRulePortMin;
+    }
+
+    public void setSecurityRulePortMin(Integer securityRulePortMin) {
+        this.securityRulePortMin = securityRulePortMin;
+    }
+
+    public Integer getSecurityRulePortMax() {
+        return securityRulePortMax;
+    }
+
+    public void setSecurityRulePortMax(Integer securityRulePortMax) {
+        this.securityRulePortMax = securityRulePortMax;
+    }
+
+    public String getSecurityRuleEthertype() {
+        return securityRuleEthertype;
+    }
+
+    public void setSecurityRuleEthertype(String securityRuleEthertype) {
+        this.securityRuleEthertype = securityRuleEthertype;
+    }
+
+    public String getSecurityRuleRemoteIpPrefix() {
+        return securityRuleRemoteIpPrefix;
+    }
+
+    public void setSecurityRuleRemoteIpPrefix(String securityRuleRemoteIpPrefix) {
+        this.securityRuleRemoteIpPrefix = securityRuleRemoteIpPrefix;
+    }
+
+    public String getSecurityRemoteGroupID() {
+        return securityRemoteGroupID;
+    }
+
+    public void setSecurityRemoteGroupID(String securityRemoteGroupID) {
+        this.securityRemoteGroupID = securityRemoteGroupID;
+    }
+
+    public String getSecurityRuleGroupID() {
+        return securityRuleGroupID;
+    }
+
+    public void setSecurityRuleGroupID(String securityRuleGroupID) {
+        this.securityRuleGroupID = securityRuleGroupID;
+    }
+
+    public String getSecurityRuleTenantID() {
+        return securityRuleTenantID;
+    }
+
+    public void setSecurityRuleTenantID(String securityRuleTenantID) {
+        this.securityRuleTenantID = securityRuleTenantID;
+    }
+
+    public NeutronSecurityRule extractFields(List<String> fields) {
+        NeutronSecurityRule ans = new NeutronSecurityRule();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setID(this.getID());
+                    break;
+                case "direction":
+                    ans.setSecurityRuleDirection(this.getSecurityRuleDirection());
+                    break;
+                case "protocol":
+                    ans.setSecurityRuleProtocol(this.getSecurityRuleProtocol());
+                    break;
+                case "port_range_min":
+                    ans.setSecurityRulePortMin(this.getSecurityRulePortMin());
+                    break;
+                case "port_range_max":
+                    ans.setSecurityRulePortMax(this.getSecurityRulePortMax());
+                    break;
+                case "ethertype":
+                    ans.setSecurityRuleEthertype(this.getSecurityRuleEthertype());
+                    break;
+                case "remote_ip_prefix":
+                    ans.setSecurityRuleRemoteIpPrefix(this.getSecurityRuleRemoteIpPrefix());
+                    break;
+                case "remote_group_id":
+                    ans.setSecurityRemoteGroupID(this.getSecurityRemoteGroupID());
+                    break;
+                case "security_group_id":
+                    ans.setSecurityRuleGroupID(this.getSecurityRuleGroupID());
+                    break;
+                case "tenant_id":
+                    ans.setSecurityRuleTenantID(this.getSecurityRuleTenantID());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSecurityRule{" +
+            "securityRuleUUID='" + securityRuleUUID + '\'' +
+            ", securityRuleDirection='" + securityRuleDirection + '\'' +
+            ", securityRuleProtocol='" + securityRuleProtocol + '\'' +
+            ", securityRulePortMin=" + securityRulePortMin +
+            ", securityRulePortMax=" + securityRulePortMax +
+            ", securityRuleEthertype='" + securityRuleEthertype + '\'' +
+            ", securityRuleRemoteIpPrefix='" + securityRuleRemoteIpPrefix + '\'' +
+            ", securityRemoteGroupID=" + securityRemoteGroupID +
+            ", securityRuleGroupID='" + securityRuleGroupID + '\'' +
+            ", securityRuleTenantID='" + securityRuleTenantID + '\'' +
+            '}';
+    }
+
+    public void initDefaults() {
+        //TODO verify no defaults values are nessecary required.
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnet.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnet.java
new file mode 100644 (file)
index 0000000..9dd4935
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSubnet implements Serializable, INeutronObject {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronCRUDInterfaces.class);
+
+    private static final long serialVersionUID = 1L;
+    private static final int IPV4_VERSION = 4;
+    private static final int IPV6_VERSION = 6;
+    private static final int IPV6_LENGTH = 128;
+    private static final int IPV6_LENGTH_BYTES = 8;
+    private static final long IPV6_LSB_MASK = 0x000000FF;
+    private static final int IPV6_BYTE_OFFSET = 7;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "id")
+    String subnetUUID;
+
+    @XmlElement (name = "network_id")
+    String networkUUID;
+
+    @XmlElement (name = "name")
+    String name;
+
+    @XmlElement (defaultValue = "4", name = "ip_version")
+    Integer ipVersion;
+
+    @XmlElement (name = "cidr")
+    String cidr;
+
+    @XmlElement (name = "gateway_ip")
+    String gatewayIP;
+
+    @XmlElement (name = "dns_nameservers")
+    List<String> dnsNameservers;
+
+    @XmlElement (name = "allocation_pools")
+    List<NeutronSubnetIPAllocationPool> allocationPools;
+
+    @XmlElement (name = "host_routes")
+    List<NeutronSubnet_HostRoute> hostRoutes;
+
+    @XmlElement (defaultValue = "true", name = "enable_dhcp")
+    Boolean enableDHCP;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    @XmlElement (name = "ipv6_address_mode", nillable = true)
+    String ipV6AddressMode;
+
+    @XmlElement (name = "ipv6_ra_mode", nillable = true)
+    String ipV6RaMode;
+
+    /* stores the OpenStackPorts associated with an instance
+     * used to determine if that instance can be deleted.
+     *
+     * @deprecated, will be removed in Boron
+     */
+
+    List<NeutronPort> myPorts;
+
+    public NeutronSubnet() {
+        myPorts = new ArrayList<>();
+    }
+
+    // @deprecated - will be removed in Boron
+    public void setPorts(List<NeutronPort> arg) {
+        myPorts = arg;
+    }
+
+    public String getID() { return subnetUUID; }
+
+    public void setID(String id) { this.subnetUUID = id; }
+
+    public String getSubnetUUID() {
+        return subnetUUID;
+    }
+
+    public void setSubnetUUID(String subnetUUID) {
+        this.subnetUUID = subnetUUID;
+    }
+
+    public String getNetworkUUID() {
+        return networkUUID;
+    }
+
+    public void setNetworkUUID(String networkUUID) {
+        this.networkUUID = networkUUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getIpVersion() {
+        return ipVersion;
+    }
+
+    public void setIpVersion(Integer ipVersion) {
+        this.ipVersion = ipVersion;
+    }
+
+    public String getCidr() {
+        return cidr;
+    }
+
+    public void setCidr(String cidr) {
+        this.cidr = cidr;
+    }
+
+    public String getGatewayIP() {
+        return gatewayIP;
+    }
+
+    public void setGatewayIP(String gatewayIP) {
+        this.gatewayIP = gatewayIP;
+    }
+
+    public List<String> getDnsNameservers() {
+        return dnsNameservers;
+    }
+
+    public void setDnsNameservers(List<String> dnsNameservers) {
+        this.dnsNameservers = dnsNameservers;
+    }
+
+    public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
+        return allocationPools;
+    }
+
+    public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
+        this.allocationPools = allocationPools;
+    }
+
+    public List<NeutronSubnet_HostRoute> getHostRoutes() {
+        return hostRoutes;
+    }
+
+    public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
+        this.hostRoutes = hostRoutes;
+    }
+
+    public boolean isEnableDHCP() {
+        if (enableDHCP == null) {
+            return true;
+        }
+        return enableDHCP;
+    }
+
+    public Boolean getEnableDHCP() { return enableDHCP; }
+
+    public void setEnableDHCP(Boolean newValue) {
+            enableDHCP = newValue;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public String getIpV6AddressMode() { return ipV6AddressMode; }
+
+    public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
+
+    public String getIpV6RaMode() { return ipV6RaMode; }
+
+    public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackSubnets object with only the selected fields
+     * populated
+     */
+
+    public NeutronSubnet extractFields(List<String> fields) {
+        NeutronSubnet ans = new NeutronSubnet();
+        for (String s : fields) {
+            switch (s) {
+                case "id":
+                    ans.setSubnetUUID(this.getSubnetUUID());
+                    break;
+                case "network_id":
+                    ans.setNetworkUUID(this.getNetworkUUID());
+                    break;
+                case "name":
+                    ans.setName(this.getName());
+                    break;
+                case "ip_version":
+                    ans.setIpVersion(this.getIpVersion());
+                    break;
+                case "cidr":
+                    ans.setCidr(this.getCidr());
+                    break;
+                case "gateway_ip":
+                    ans.setGatewayIP(this.getGatewayIP());
+                    break;
+                case "dns_nameservers":
+                    List<String> nsList = new ArrayList<>();
+                    nsList.addAll(this.getDnsNameservers());
+                    ans.setDnsNameservers(nsList);
+                    break;
+                case "allocation_pools":
+                    List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<>();
+                    aPools.addAll(this.getAllocationPools());
+                    ans.setAllocationPools(aPools);
+                    break;
+                case "host_routes":
+                    List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<>();
+                    hRoutes.addAll(this.getHostRoutes());
+                    ans.setHostRoutes(hRoutes);
+                    break;
+                case "enable_dhcp":
+                    ans.setEnableDHCP(this.getEnableDHCP());
+                    break;
+                case "tenant_id":
+                    ans.setTenantID(this.getTenantID());
+                    break;
+                case "ipv6_address_mode":
+                    ans.setIpV6AddressMode(this.getIpV6AddressMode());
+                    break;
+                case "ipv6_ra_mode":
+                    ans.setIpV6RaMode(this.getIpV6RaMode());
+                    break;
+            }
+        }
+        return ans;
+    }
+
+    // @deprecated - will be removed in Boron
+    public List<NeutronPort> getPortsInSubnet() {
+        return myPorts;
+    }
+
+    // @deprecated - will be removed in Boron
+    public List<NeutronPort> getPortsInSubnet(String ignore) {
+       List<NeutronPort> answer = new ArrayList<>();
+       for (NeutronPort port : myPorts) {
+           if (!port.getDeviceOwner().equalsIgnoreCase(ignore)) {
+                answer.add(port);
+            }
+        }
+        return answer;
+    }
+
+    /* test to see if the cidr address used to define this subnet
+     * is a valid network address (an necessary condition when creating
+     * a new subnet)
+     */
+    public boolean isValidCIDR() {
+        // fix for Bug 2290 - need to wrap the existing test as
+        // IPv4 because SubnetUtils doesn't support IPv6
+        if (ipVersion == IPV4_VERSION) {
+            try {
+                SubnetUtils util = new SubnetUtils(cidr);
+                SubnetInfo info = util.getInfo();
+                if (!info.getNetworkAddress().equals(info.getAddress())) {
+                    return false;
+                }
+            } catch (IllegalArgumentException e) {
+                LOGGER.warn("Failure in isValidCIDR()", e);
+                return false;
+            }
+            return true;
+        }
+        if (ipVersion == IPV6_VERSION) {
+            // fix for Bug2290 - this is custom code because no classes
+            // with ODL-friendly licenses have been found
+            // extract address (in front of /) and length (after /)
+            String[] parts = cidr.split("/");
+            if (parts.length != 2) {
+                return false;
+            }
+            try {
+                int length = Integer.parseInt(parts[1]);
+                //TODO?: limit check on length
+                // convert to byte array
+                byte[] addrBytes = InetAddress.getByName(parts[0]).getAddress();
+                int i;
+                for (i = length; i < IPV6_LENGTH; i++) {
+                    if (((((int) addrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) != 0) {
+                        return(false);
+                    }
+                }
+                return(true);
+            } catch (UnknownHostException e) {
+                LOGGER.warn("Failure in isValidCIDR()", e);
+                return(false);
+            }
+        }
+        return false;
+    }
+
+    /* test to see if the gateway IP specified overlaps with specified
+     * allocation pools (an error condition when creating a new subnet
+     * or assigning a gateway IP)
+     */
+    public boolean gatewayIP_Pool_overlap() {
+        for (NeutronSubnetIPAllocationPool pool : allocationPools) {
+            if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
+                return true;
+            }
+            if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean initDefaults() {
+        if (enableDHCP == null) {
+            enableDHCP = true;
+        }
+        if (ipVersion == null) {
+            ipVersion = IPV4_VERSION;
+        }
+        dnsNameservers = new ArrayList<>();
+        if (hostRoutes == null) {
+            hostRoutes = new ArrayList<>();
+        }
+        if (allocationPools == null) {
+            allocationPools = new ArrayList<>();
+            if (ipVersion == IPV4_VERSION) {
+                try {
+                    SubnetUtils util = new SubnetUtils(cidr);
+                    SubnetInfo info = util.getInfo();
+                    if (gatewayIP == null || ("").equals(gatewayIP)) {
+                        gatewayIP = info.getLowAddress();
+                    }
+                    if (allocationPools.size() < 1) {
+                        NeutronSubnetIPAllocationPool source =
+                            new NeutronSubnetIPAllocationPool(info.getLowAddress(),
+                                    info.getHighAddress());
+                        allocationPools = source.splitPool(gatewayIP);
+                    }
+                } catch (IllegalArgumentException e) {
+                    LOGGER.warn("Failure in initDefault()", e);
+                    return false;
+                }
+            }
+            if (ipVersion == IPV6_VERSION) {
+                String[] parts = cidr.split("/");
+                if (parts.length != 2) {
+                    return false;
+                }
+                try {
+                    int length = Integer.parseInt(parts[1]);
+                    BigInteger lowAddress_bi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
+                    String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
+                    BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
+                    String highAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
+                    if (gatewayIP == null || ("").equals(gatewayIP)) {
+                        gatewayIP = lowAddress;
+                    }
+                    if (allocationPools.size() < 1) {
+                        NeutronSubnetIPAllocationPool source =
+                            new NeutronSubnetIPAllocationPool(lowAddress,
+                                    highAddress);
+                        allocationPools = source.splitPoolV6(gatewayIP);
+                    }
+                } catch (Exception e) {
+                    LOGGER.warn("Failure in initDefault()", e);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /* this method tests to see if the supplied IPv4 address
+     * is valid for this subnet or not
+     */
+    public boolean isValidIP(String ipAddress) {
+        if (ipVersion == IPV4_VERSION) {
+            try {
+                SubnetUtils util = new SubnetUtils(cidr);
+                SubnetInfo info = util.getInfo();
+                return info.isInRange(ipAddress);
+            } catch (IllegalArgumentException e) {
+                LOGGER.warn("Failure in isValidIP()", e);
+                return false;
+            }
+        }
+
+        if (ipVersion == IPV6_VERSION) {
+            String[] parts = cidr.split("/");
+            try {
+                int length = Integer.parseInt(parts[1]);
+                byte[] cidrBytes = InetAddress.getByName(parts[0]).getAddress();
+                byte[] ipBytes =  InetAddress.getByName(ipAddress).getAddress();
+                int i;
+                for (i = 0; i < length; i++) {
+                    if (((((int) cidrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) !=
+                        ((((int) ipBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES))))) {
+                        return(false);
+                    }
+                }
+                return(true);
+            } catch (UnknownHostException e) {
+                LOGGER.warn("Failure in isValidIP()", e);
+                return(false);
+            }
+        }
+        return false;
+    }
+
+    /* method to get the lowest available address of the subnet.
+     * go through all the allocation pools and keep the lowest of their
+     * low addresses.
+     */
+    public String getLowAddr() {
+        String ans = null;
+        for (NeutronSubnetIPAllocationPool pool : allocationPools) {
+            if (ans == null) {
+                ans = pool.getPoolStart();
+            } else {
+                if (ipVersion == IPV4_VERSION &&
+                        NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
+                                NeutronSubnetIPAllocationPool.convert(ans)) {
+                    ans = pool.getPoolStart();
+                }
+                if (ipVersion == IPV6_VERSION &&
+                        NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(
+                                NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
+                    ans = pool.getPoolStart();
+                }
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
+                + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
+                + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
+                + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID
+                + ", ipv6AddressMode=" + ipV6AddressMode
+                + ", ipv6RaMode=" + ipV6RaMode + "]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnetIPAllocationPool.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnetIPAllocationPool.java
new file mode 100644 (file)
index 0000000..541aa69
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnetIPAllocationPool implements Serializable {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronSubnetIPAllocationPool.class);
+
+    private static final long serialVersionUID = 1L;
+
+    private static final int BYTE_LENGTH = 8;
+    private static final int IPV4_DOTTED_QUADS = 4;
+    private static final int IPV4_DOTTED_QUAD_OFFSET = 3;
+    private static final int IPV4_DOTTED_QUAD_MASK = 255;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "start")
+    String poolStart;
+
+    @XmlElement(name = "end")
+    String poolEnd;
+
+    public NeutronSubnetIPAllocationPool() {
+    }
+
+    public NeutronSubnetIPAllocationPool(String lowAddress, String highAddress) {
+        poolStart = lowAddress;
+        poolEnd = highAddress;
+    }
+
+    public String getPoolStart() {
+        return poolStart;
+    }
+
+    public void setPoolStart(String poolStart) {
+        this.poolStart = poolStart;
+    }
+
+    public String getPoolEnd() {
+        return poolEnd;
+    }
+
+    public void setPoolEnd(String poolEnd) {
+        this.poolEnd = poolEnd;
+    }
+
+    /**
+     * This method determines if this allocation pool contains the
+     * input IPv4 address
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @return a boolean on whether the pool contains the address or not
+     */
+
+    public boolean contains(String inputString) {
+        long inputIP = convert(inputString);
+        long startIP = convert(poolStart);
+        long endIP = convert(poolEnd);
+        return (inputIP >= startIP && inputIP <= endIP);
+    }
+
+    /**
+     * This static method converts the supplied IPv4 address to a long
+     * integer for comparison
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @return high-endian representation of the IPv4 address as a long.
+     *          This method will return 0 if the input is null.
+     */
+
+    static long convert(String inputString) {
+        long ans = 0;
+        if (inputString != null) {
+            String[] parts = inputString.split("\\.");
+            for (String part: parts) {
+                ans <<= BYTE_LENGTH;
+                ans |= Integer.parseInt(part);
+            }
+        }
+        return ans;
+    }
+
+    /**
+     * This method determines if this allocation pool contains the
+     * input IPv4 address
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @return a boolean on whether the pool contains the address or not
+     */
+
+    public boolean containsV6(String inputString) {
+        BigInteger inputIP = convertV6(inputString);
+        BigInteger startIP = convertV6(poolStart);
+        BigInteger endIP = convertV6(poolEnd);
+        return (inputIP.compareTo(startIP) >= 0 && inputIP.compareTo(endIP) <= 0);
+    }
+
+    /**
+     * This static method converts the supplied IPv4 address to a long
+     * integer for comparison
+     *
+     * @param inputString
+     *            IPv6 address in dotted decimal format
+     * @return high-endian representation of the IPv4 address as a BigInteger.
+     *          This method will return 0 if the input is null.
+     */
+
+    static BigInteger convertV6(String inputString) {
+        if (inputString == null) {
+            return BigInteger.ZERO;
+        }
+        try {
+            return new BigInteger(InetAddress.getByName(inputString).getAddress());
+        } catch (Exception e) {
+            LOGGER.error("convertV6 error", e);
+            return BigInteger.ZERO;
+        }
+    }
+
+    /**
+     * This static method converts the supplied high-ending long back
+     * into a dotted decimal representation of an IPv4 address
+     *
+     * @param l
+     *            high-endian representation of the IPv4 address as a long
+     * @return IPv4 address in dotted decimal format
+     */
+    static String longToIP(long input) {
+        int part;
+        long ipLong = input;
+        String[] parts = new String[IPV4_DOTTED_QUADS];
+        for (part = 0; part < IPV4_DOTTED_QUADS; part++) {
+            parts[IPV4_DOTTED_QUAD_OFFSET-part] = String.valueOf(ipLong & IPV4_DOTTED_QUAD_MASK);
+            ipLong >>= BYTE_LENGTH;
+        }
+        return join(parts,".");
+    }
+
+    /**
+     * This static method converts the supplied high-ending long back
+     * into a dotted decimal representation of an IPv4 address
+     *
+     * @param l
+     *            high-endian representation of the IPv4 address as a long
+     * @return IPv4 address in dotted decimal format
+     */
+    static String bigIntegerToIP(BigInteger b) {
+        try {
+            return Inet6Address.getByAddress(b.toByteArray()).getHostAddress();
+        } catch (Exception e) {
+            LOGGER.error("bigIntegerToIP", e);
+            return "ERROR";
+        }
+    }
+
+    /*
+     * helper routine used by longToIP
+     */
+    public static String join(String r[],String separator)
+    {
+        if (r.length == 0) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        int i;
+        for(i = 0;i < r.length - 1;i++) {
+            sb.append(r[i]);
+            sb.append(separator);
+        }
+        return sb.toString() + r[i];
+    }
+
+    /*
+     * This method splits the current instance by removing the supplied
+     * parameter.
+     *
+     * If the parameter is either the low or high address,
+     * then that member is adjusted and a list containing just this instance
+     * is returned.
+     *
+     * If the parameter is in the middle of the pool, then
+     * create two new instances, one ranging from low to parameter-1
+     * the other ranging from parameter+1 to high
+     */
+    public List<NeutronSubnetIPAllocationPool> splitPool(String ipAddress) {
+        List<NeutronSubnetIPAllocationPool> ans = new ArrayList<>();
+        long gIP = NeutronSubnetIPAllocationPool.convert(ipAddress);
+        long sIP = NeutronSubnetIPAllocationPool.convert(poolStart);
+        long eIP = NeutronSubnetIPAllocationPool.convert(poolEnd);
+        long i;
+        NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+        boolean poolStarted = false;
+        for (i = sIP; i <= eIP; i++) {
+            if (i == sIP) {
+                if (i != gIP) {
+                    p.setPoolStart(poolStart);
+                    poolStarted = true;
+                } else {
+                    //FIX for bug 533
+                    p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i+1));
+                }
+            }
+            if (i == eIP) {
+                if (i != gIP) {
+                    p.setPoolEnd(poolEnd);
+                } else {
+                    p.setPoolEnd(NeutronSubnetIPAllocationPool.longToIP(i-1));
+                }
+                ans.add(p);
+            }
+            if (i != sIP && i != eIP) {
+                if (i != gIP) {
+                    if (!poolStarted) {
+                        p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i));
+                        poolStarted = true;
+                    }
+                } else {
+                    p.setPoolEnd(NeutronSubnetIPAllocationPool.longToIP(i-1));
+                    poolStarted = false;
+                    ans.add(p);
+                    p = new NeutronSubnetIPAllocationPool();
+                    // Fix for 2120
+                    p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i+1));
+                    poolStarted = true;
+                }
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSubnetIPAllocationPool [" +
+            "start=" + poolStart +
+            ", end=" + poolEnd + "]";
+    }
+
+    /*
+     * This method splits the current instance by removing the supplied
+     * parameter.
+     *
+     * If the parameter is either the low or high address,
+     * then that member is adjusted and a list containing just this instance
+     * is returned.
+     new *
+     * If the parameter is in the middle of the pool, then
+     * create two new instances, one ranging from low to parameter-1
+     * the other ranging from parameter+1 to high
+     * If the pool is a single address, return null
+     */
+    public List<NeutronSubnetIPAllocationPool> splitPoolV6(String ipAddress) {
+        List<NeutronSubnetIPAllocationPool> ans = new ArrayList<>();
+        BigInteger gIP = NeutronSubnetIPAllocationPool.convertV6(ipAddress);
+        BigInteger sIP = NeutronSubnetIPAllocationPool.convertV6(poolStart);
+        BigInteger eIP = NeutronSubnetIPAllocationPool.convertV6(poolEnd);
+        if (gIP.compareTo(sIP) == 0 && gIP.compareTo(eIP) < 0) {
+            NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+            p.setPoolStart(NeutronSubnetIPAllocationPool.bigIntegerToIP(sIP.add(BigInteger.ONE)));
+            p.setPoolEnd(poolEnd);
+            ans.add(p);
+            return(ans);
+        }
+        if (gIP.compareTo(eIP) == 0 && gIP.compareTo(sIP) > 0) {
+            NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+            p.setPoolStart(poolStart);
+            p.setPoolEnd(NeutronSubnetIPAllocationPool.bigIntegerToIP(eIP.subtract(BigInteger.ONE)));
+            ans.add(p);
+            return(ans);
+        }
+        if (gIP.compareTo(eIP) < 0 && gIP.compareTo(sIP) > 0) {
+            NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+            p.setPoolStart(poolStart);
+            p.setPoolEnd(NeutronSubnetIPAllocationPool.bigIntegerToIP(gIP.subtract(BigInteger.ONE)));
+            ans.add(p);
+            NeutronSubnetIPAllocationPool p2 = new NeutronSubnetIPAllocationPool();
+            p2.setPoolStart(NeutronSubnetIPAllocationPool.bigIntegerToIP(gIP.add(BigInteger.ONE)));
+            p2.setPoolEnd(poolEnd);
+            ans.add(p2);
+            return ans;
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnet_HostRoute.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/NeutronSubnet_HostRoute.java
new file mode 100644 (file)
index 0000000..9224bd6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnet_HostRoute implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "destination")
+    String destination;
+
+    @XmlElement(name = "nexthop")
+    String nextHop;
+
+    /**
+     *  HostRoute constructor
+     */
+    public NeutronSubnet_HostRoute() { }
+
+    @Override
+    public String toString() {
+        return "NeutronSubnetHostRoute [" +
+            "destination=" + destination +
+            ", nextHop=" + nextHop + "]";
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/Neutron_ID.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/Neutron_ID.java
new file mode 100644 (file)
index 0000000..4a1e6e4
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Neutron_ID implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "id")
+    String uuid;
+
+    public Neutron_ID() { }
+
+    public Neutron_ID(String uuid) {
+        this.uuid = uuid;
+    }
+
+    public String getID() {
+        return uuid;
+    }
+
+    public void setID(String uuid) {
+        this.uuid = uuid;
+    }
+
+    @Override
+    public String toString() {
+        return "Neutron_ID{" + "id='" + uuid + '\'' + "}";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/Neutron_IPs.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/Neutron_IPs.java
new file mode 100644 (file)
index 0000000..0fde03f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Neutron_IPs implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "ip_address")
+    String ipAddress;
+
+    @XmlElement(name = "subnet_id")
+    String subnetUUID;
+
+    public Neutron_IPs() { }
+
+    public Neutron_IPs(String uuid) {
+        subnetUUID = uuid;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public String getSubnetUUID() {
+        return subnetUUID;
+    }
+
+    public void setSubnetUUID(String subnetUUID) {
+        this.subnetUUID = subnetUUID;
+    }
+
+    @Override
+    public String toString() {
+        return "Neutron_IPs{" +
+               "ipAddress='" + ipAddress + '\'' +
+               ", subnetUUID='" + subnetUUID + '\'' + "}";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallCRUD.java
new file mode 100644 (file)
index 0000000..dc53a09
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewall;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall objects
+ */
+
+public interface INeutronFirewallCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *Firewall object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall object
+     * @return boolean
+     */
+
+    boolean neutronFirewallExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Firewall object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall object
+     * @return {@link NeutronFirewall}
+     *          OpenStackFirewall class
+     */
+
+    NeutronFirewall getNeutronFirewall(String uuid);
+
+    /**
+     * Applications call this interface method to return all Firewall objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronFirewall> getAllNeutronFirewalls();
+
+    /**
+     * Applications call this interface method to add a Firewall object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronFirewall(NeutronFirewall input);
+
+    /**
+     * Applications call this interface method to remove a Neutron Firewall object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Firewall object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronFirewall(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Firewall object
+     *
+     * @param uuid
+     *            identifier of the Firewall object
+     * @param delta
+     *            OpenStackFirewall object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronFirewall(String uuid, NeutronFirewall delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the Firewall object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronFirewallInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallPolicyCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallPolicyCRUD.java
new file mode 100644 (file)
index 0000000..9d1d5f3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallPolicy;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall Policy objects
+ *
+ */
+
+public interface INeutronFirewallPolicyCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *FirewallPolicy object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Policy object
+     * @return boolean
+     */
+
+    boolean neutronFirewallPolicyExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * FirewallPolicy object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Policy object
+     * @return {@link NeutronFirewallPolicy}
+     *          OpenStackFirewallPolicy class
+     */
+
+    NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid);
+
+    /**
+     * Applications call this interface method to return all Firewall Policy objects
+     *
+     * @return List of OpenStack Firewall Policy objects
+     */
+
+    List<NeutronFirewallPolicy> getAllNeutronFirewallPolicies();
+
+    /**
+     * Applications call this interface method to add a Firewall Policy object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input);
+
+    /**
+     * Applications call this interface method to remove a Neutron FirewallPolicy object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Firewall Policy object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronFirewallPolicy(String uuid);
+
+    /**
+     * Applications call this interface method to edit a FirewallPolicy object
+     *
+     * @param uuid
+     *            identifier of the Firewall Policy object
+     * @param delta
+     *            OpenStackFirewallPolicy object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronFirewallPolicy(String uuid, NeutronFirewallPolicy delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the Firewall Policy object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronFirewallPolicyInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallRuleCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFirewallRuleCRUD.java
new file mode 100644 (file)
index 0000000..6aec58e
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallRule;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall Rule objects
+ *
+ */
+
+public interface INeutronFirewallRuleCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *FirewallRule object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Rule object
+     * @return boolean
+     */
+
+    boolean neutronFirewallRuleExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * FirewallRule object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Rule object
+     * @return {@link NeutronFirewallRule}
+     *          OpenStackFirewall Rule class
+     */
+
+    NeutronFirewallRule getNeutronFirewallRule(String uuid);
+
+    /**
+     * Applications call this interface method to return all Firewall Rule objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronFirewallRule> getAllNeutronFirewallRules();
+
+    /**
+     * Applications call this interface method to add a Firewall Rule object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronFirewallRule(NeutronFirewallRule input);
+
+    /**
+     * Applications call this interface method to remove a Neutron FirewallRule object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Firewall Rule object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronFirewallRule(String uuid);
+
+    /**
+     * Applications call this interface method to edit a FirewallRule object
+     *
+     * @param uuid
+     *            identifier of the Firewall Rule object
+     * @param delta
+     *            OpenStackFirewallRule object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronFirewallRule(String uuid, NeutronFirewallRule delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the Firewall Rule object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronFirewallRuleInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFloatingIPCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronFloatingIPCRUD.java
new file mode 100644 (file)
index 0000000..88c5b97
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+
+/**
+ * This interface defines the methods for CRUD of NB FloatingIP objects
+ *
+ */
+
+public interface INeutronFloatingIPCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * FloatingIP object exists
+     *
+     * @param uuid
+     *            UUID of the FloatingIP object
+     * @return boolean
+     */
+
+    boolean floatingIPExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * FloatingIP object exists
+     *
+     * @param uuid
+     *            UUID of the FloatingIP object
+     * @return {@link NeutronFloatingIP}
+     *          OpenStack FloatingIP class
+     */
+
+    NeutronFloatingIP getFloatingIP(String uuid);
+
+    /**
+     * Applications call this interface method to return all FloatingIP objects
+     *
+     * @return a Set of OpenStackFloatingIPs objects
+     */
+
+    List<NeutronFloatingIP> getAllFloatingIPs();
+
+    /**
+     * Applications call this interface method to add a FloatingIP object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackFloatingIP object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addFloatingIP(NeutronFloatingIP input);
+
+    /**
+     * Applications call this interface method to remove a FloatingIP object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the FloatingIP object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeFloatingIP(String uuid);
+
+    /**
+     * Applications call this interface method to edit a FloatingIP object
+     *
+     * @param uuid
+     *            identifier of the FloatingIP object
+     * @param delta
+     *            OpenStackFloatingIP object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateFloatingIP(String uuid, NeutronFloatingIP delta);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerCRUD.java
new file mode 100644 (file)
index 0000000..cf0f2d0
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancer objects
+ *
+ */
+
+public interface INeutronLoadBalancerCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancer object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancer object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancer object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancer object
+     * @return {@link NeutronLoadBalancer}
+     *          OpenStackLoadBalancer class
+     */
+
+    NeutronLoadBalancer getNeutronLoadBalancer(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancer objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancer> getAllNeutronLoadBalancers();
+
+    /**
+     * Applications call this interface method to add a LoadBalancer object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancer(NeutronLoadBalancer input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancer object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancer object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancer(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancer object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancer object
+     * @param delta
+     *            OpenStackLoadBalancer object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancer object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerHealthMonitorCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerHealthMonitorCRUD.java
new file mode 100644 (file)
index 0000000..3bb7103
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerHealthMonitor objects
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerHealthMonitor object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerHealthMonitor object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerHealthMonitorExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerHealthMonitor object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerHealthMonitor object
+     * @return {@link NeutronLoadBalancerHealthMonitor}
+     *          OpenStackLoadBalancerHealthMonitor class
+     */
+
+    NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerHealthMonitor objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerHealthMonitor object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerHealthMonitor object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerHealthMonitor object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerHealthMonitor(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerHealthMonitor object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerHealthMonitor object
+     * @param delta
+     *            OpenStackLoadBalancerHealthMonitor object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerHealthMonitor(String uuid, NeutronLoadBalancerHealthMonitor delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerHealthMonitor object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerHealthMonitorInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerListenerCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerListenerCRUD.java
new file mode 100644 (file)
index 0000000..f6a96b9
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerListener;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerListener objects
+ *
+ */
+
+public interface INeutronLoadBalancerListenerCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerListener object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerListener object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerListenerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerListener object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerListener object
+     * @return {@link NeutronLoadBalancerListener}
+     *          OpenStackLoadBalancerListener class
+     */
+
+    NeutronLoadBalancerListener getNeutronLoadBalancerListener(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerListener objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerListener object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerListener(NeutronLoadBalancerListener input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerListener object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerListener object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerListener(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerListener object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerListener object
+     * @param delta
+     *            OpenStackLoadBalancerListener object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerListener(String uuid, NeutronLoadBalancerListener delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerListener object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerListenerInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolCRUD.java
new file mode 100644 (file)
index 0000000..678707b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerPool objects
+ *
+ */
+
+public interface INeutronLoadBalancerPoolCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerPool object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerPool object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerPoolExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerPool object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerPool object
+     * @return {@link NeutronLoadBalancerPool}
+     *          OpenStackLoadBalancerPool class
+     */
+
+    NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerPool objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerPool object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerPool object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerPool object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerPool(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerPool object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerPool object
+     * @param delta
+     *            OpenStackLoadBalancerPool object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerPool object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerPoolInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolMemberCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolMemberCRUD.java
new file mode 100644 (file)
index 0000000..81945ad
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+
+public interface INeutronLoadBalancerPoolMemberCRUD {
+
+    /**
+     * Applications call this interface method to determine if a particular
+     *NeutronLoadBalancerPoolMember object exists
+     *
+     * @param uuid
+     *            UUID of the NeutronLoadBalancerPoolMember object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerPoolMemberExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * NeutronLoadBalancerPoolMember object exists
+     *
+     * @param uuid
+     *            UUID of the NeutronLoadBalancerPoolMember object
+     * @return {@link NeutronLoadBalancerPoolMember}
+     *          OpenStackNeutronLoadBalancerPoolMember class
+     */
+
+    NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(String uuid);
+
+    /**
+     * Applications call this interface method to return all NeutronLoadBalancerPoolMember objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers();
+
+    /**
+     * Applications call this interface method to add a NeutronLoadBalancerPoolMember object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember input);
+
+    /**
+     * Applications call this interface method to remove a Neutron NeutronLoadBalancerPoolMember object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the NeutronLoadBalancerPoolMember object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerPoolMember(String uuid);
+
+    /**
+     * Applications call this interface method to edit a NeutronLoadBalancerPoolMember object
+     *
+     * @param uuid
+     *            identifier of the NeutronLoadBalancerPoolMember object
+     * @param delta
+     *            OpenStackNeutronLoadBalancerPoolMember object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerPoolMember(String uuid, NeutronLoadBalancerPoolMember delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the NeutronLoadBalancerPoolMember object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerPoolMemberInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronNetworkCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronNetworkCRUD.java
new file mode 100644 (file)
index 0000000..04a35ee
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+
+/**
+ * This interface defines the methods for CRUD of NB network objects
+ *
+ */
+
+public interface INeutronNetworkCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Network object exists
+     *
+     * @param uuid
+     *            UUID of the Network object
+     * @return boolean
+     */
+
+    boolean networkExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Network object exists
+     *
+     * @param uuid
+     *            UUID of the Network object
+     * @return {@link NeutronNetwork}
+     *          OpenStack Network class
+     */
+
+    NeutronNetwork getNetwork(String uuid);
+
+    /**
+     * Applications call this interface method to return all Network objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronNetwork> getAllNetworks();
+
+    /**
+     * Applications call this interface method to add a Network object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNetwork(NeutronNetwork input);
+
+    /**
+     * Applications call this interface method to remove a Network object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the network object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNetwork(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Network object
+     *
+     * @param uuid
+     *            identifier of the network object
+     * @param delta
+     *            OpenStackNetwork object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNetwork(String uuid, NeutronNetwork delta);
+
+    /**
+     * Applications call this interface method to determine if a Network object
+     * is use
+     *
+     * @param netUUID
+     *            identifier of the network object
+     *
+     * @return boolean on whether the network is in use or not
+     */
+
+    boolean networkInUse(String netUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronPortCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronPortCRUD.java
new file mode 100644 (file)
index 0000000..850c5d7
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+
+/**
+ * This interface defines the methods for CRUD of NB Port objects
+ *
+ */
+
+public interface INeutronPortCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Port object exists
+     *
+     * @param uuid
+     *            UUID of the Port object
+     * @return boolean
+     */
+
+    boolean portExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Port object exists
+     *
+     * @param uuid
+     *            UUID of the Port object
+     * @return {@link NeutronPort}
+     *          OpenStack Port class
+     */
+
+    NeutronPort getPort(String uuid);
+
+    /**
+     * Applications call this interface method to return all Port objects
+     *
+     * @return List of OpenStackPorts objects
+     */
+
+    List<NeutronPort> getAllPorts();
+
+    /**
+     * Applications call this interface method to add a Port object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackPort object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addPort(NeutronPort input);
+
+    /**
+     * Applications call this interface method to remove a Port object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Port object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removePort(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Port object
+     *
+     * @param uuid
+     *            identifier of the Port object
+     * @param delta
+     *            OpenStackPort object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updatePort(String uuid, NeutronPort delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param macAddress
+     *            mac Address to be tested
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     *
+     * @deprecated - will be removed in Boron
+     */
+
+    boolean macInUse(String macAddress);
+
+    /**
+     * Applications call this interface method to retrieve the port associated with
+     * the gateway address of a subnet
+     *
+     * @param subnetUUID
+     *            identifier of the subnet
+     * @return OpenStackPorts object if the port exists and null if it does not
+     *
+     * @deprecated - will be removed in Boron
+     */
+
+    NeutronPort getGatewayPort(String subnetUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronRouterCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronRouterCRUD.java
new file mode 100644 (file)
index 0000000..e4e7681
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+
+/**
+ * This interface defines the methods for CRUD of NB Router objects
+ *
+ */
+
+public interface INeutronRouterCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Router object exists
+     *
+     * @param uuid
+     *            UUID of the Router object
+     * @return boolean
+     */
+
+    boolean routerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Router object exists
+     *
+     * @param uuid
+     *            UUID of the Router object
+     * @return {@link NeutronRouter}
+     *          OpenStack Router class
+     */
+
+    NeutronRouter getRouter(String uuid);
+
+    /**
+     * Applications call this interface method to return all Router objects
+     *
+     * @return List of OpenStackRouters objects
+     */
+
+    List<NeutronRouter> getAllRouters();
+
+    /**
+     * Applications call this interface method to add a Router object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackRouter object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addRouter(NeutronRouter input);
+
+    /**
+     * Applications call this interface method to remove a Router object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Router object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeRouter(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Router object
+     *
+     * @param uuid
+     *            identifier of the Router object
+     * @param delta
+     *            OpenStackRouter object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateRouter(String uuid, NeutronRouter delta);
+
+    /**
+     * Applications call this interface method to check if a router is in use
+     *
+     * @param routerUUID
+     *            identifier of the Router object
+     * @return boolean on whether the router is in use or not
+     */
+
+    boolean routerInUse(String routerUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSecurityGroupCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSecurityGroupCRUD.java
new file mode 100644 (file)
index 0000000..022a0dc
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Group objects
+ */
+
+public interface INeutronSecurityGroupCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Security Group object exists
+     *
+     * @param uuid UUID of the Security Group object
+     * @return boolean
+     */
+
+    boolean neutronSecurityGroupExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Security Group object exists
+     *
+     * @param uuid UUID of the Security Group object
+     * @return {@link NeutronSecurityGroup}
+     * OpenStack Security Group class
+     */
+
+    NeutronSecurityGroup getNeutronSecurityGroup(String uuid);
+
+    /**
+     * Applications call this interface method to return all Security Group objects
+     *
+     * @return List of OpenStackSecurity Groups objects
+     */
+
+    List<NeutronSecurityGroup> getAllNeutronSecurityGroups();
+
+    /**
+     * Applications call this interface method to add a Security Group object to the
+     * concurrent map
+     *
+     * @param input OpenStackSecurity Group object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronSecurityGroup(NeutronSecurityGroup input);
+
+    /**
+     * Applications call this interface method to remove a Neutron Security Group object to the
+     * concurrent map
+     *
+     * @param uuid identifier for the security group object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronSecurityGroup(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Security Group object
+     *
+     * @param uuid  identifier of the security group object
+     * @param delta OpenStackSecurity Group object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid identifier of the security group object
+     * @return boolean on whether the Security Groups is already in use
+     */
+
+    boolean neutronSecurityGroupInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSecurityRuleCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSecurityRuleCRUD.java
new file mode 100644 (file)
index 0000000..caf7aeb
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Rule objects
+ */
+
+public interface INeutronSecurityRuleCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Security Rule object exists
+     *
+     * @param uuid UUID of theSecurity Rule object
+     * @return boolean
+     */
+
+    boolean neutronSecurityRuleExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Security Rule object exists
+     *
+     * @param uuid UUID of the security rule object
+     * @return {@link NeutronSecurityRule}
+     * OpenStackSecurity Rule class
+     */
+
+    NeutronSecurityRule getNeutronSecurityRule(String uuid);
+
+    /**
+     * Applications call this interface method to return all Security Rule objects
+     *
+     * @return List of OpenStack SecurityRules objects
+     */
+
+    List<NeutronSecurityRule> getAllNeutronSecurityRules();
+
+    /**
+     * Applications call this interface method to add a Security Rule object to the
+     * concurrent map
+     *
+     * @param input OpenStack security rule object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronSecurityRule(NeutronSecurityRule input);
+
+    /**
+     * Applications call this interface method to remove a Neutron Security Rule object to the
+     * concurrent map
+     *
+     * @param uuid identifier for the security rule object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronSecurityRule(String uuid);
+
+    /**
+     * Applications call this interface method to edit aSecurity Rule object
+     *
+     * @param uuid  identifier of the security rule object
+     * @param delta OpenStackSecurity Rule object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid identifier of the security rule object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronSecurityRuleInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSubnetCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/INeutronSubnetCRUD.java
new file mode 100644 (file)
index 0000000..3a49bda
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+
+/**
+ * This interface defines the methods for CRUD of NB Subnet objects
+ *
+ */
+
+public interface INeutronSubnetCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Subnet object exists
+     *
+     * @param uuid
+     *            UUID of the Subnet object
+     * @return boolean
+     */
+
+    boolean subnetExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Subnet object exists
+     *
+     * @param uuid
+     *            UUID of the Subnet object
+     * @return {@link NeutronSubnet}
+     *          OpenStack Subnet class
+     */
+
+    NeutronSubnet getSubnet(String uuid);
+
+    /**
+     * Applications call this interface method to return all Subnet objects
+     *
+     * @return List of OpenStackSubnets objects
+     */
+
+    List<NeutronSubnet> getAllSubnets();
+
+    /**
+     * Applications call this interface method to add a Subnet object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackSubnet object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addSubnet(NeutronSubnet input);
+
+    /**
+     * Applications call this interface method to remove a Subnet object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Subnet object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeSubnet(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Subnet object
+     *
+     * @param uuid
+     *            identifier of the Subnet object
+     * @param delta
+     *            OpenStackSubnet object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateSubnet(String uuid, NeutronSubnet delta);
+
+    /**
+     * Applications call this interface method to determine if a Subnet object
+     * is use
+     *
+     * @param subnetUUID
+     *            identifier of the subnet object
+     *
+     * @return boolean on whether the subnet is in use or not
+     *
+     * @deprecated - will be removed in Boron
+     */
+
+    boolean subnetInUse(String subnetUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/NeutronCRUDInterfaces.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/NeutronCRUDInterfaces.java
new file mode 100644 (file)
index 0000000..3a567da
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronCRUDInterfaces {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronCRUDInterfaces.class);
+
+    private INeutronNetworkCRUD networkInterface;
+    private INeutronSubnetCRUD subnetInterface;
+    private INeutronPortCRUD portInterface;
+    private INeutronRouterCRUD routerInterface;
+    private INeutronFloatingIPCRUD fipInterface;
+    private INeutronSecurityGroupCRUD sgInterface;
+    private INeutronSecurityRuleCRUD srInterface;
+    private INeutronFirewallCRUD fwInterface;
+    private INeutronFirewallPolicyCRUD fwpInterface;
+    private INeutronFirewallRuleCRUD fwrInterface;
+    private INeutronLoadBalancerCRUD lbInterface;
+    private INeutronLoadBalancerPoolCRUD lbpInterface;
+    private INeutronLoadBalancerListenerCRUD lblInterface;
+    private INeutronLoadBalancerHealthMonitorCRUD lbhmInterface;
+    private INeutronLoadBalancerPoolMemberCRUD lbpmInterface;
+    public NeutronCRUDInterfaces() {
+    }
+
+    public INeutronNetworkCRUD getNetworkInterface() {
+        return networkInterface;
+    }
+
+    public INeutronSubnetCRUD getSubnetInterface() {
+        return subnetInterface;
+    }
+
+    public INeutronPortCRUD getPortInterface() {
+        return portInterface;
+    }
+
+    public INeutronRouterCRUD getRouterInterface() {
+        return routerInterface;
+    }
+
+    public INeutronFloatingIPCRUD getFloatingIPInterface() {
+        return fipInterface;
+    }
+
+    public INeutronSecurityGroupCRUD getSecurityGroupInterface() {
+        return sgInterface;
+    }
+
+    public INeutronSecurityRuleCRUD getSecurityRuleInterface() {
+        return srInterface;
+    }
+
+    public INeutronFirewallCRUD getFirewallInterface() {
+        return fwInterface;
+    }
+
+    public INeutronFirewallPolicyCRUD getFirewallPolicyInterface() {
+        return fwpInterface;
+    }
+
+    public INeutronFirewallRuleCRUD getFirewallRuleInterface() {
+        return fwrInterface;
+    }
+
+    public INeutronLoadBalancerCRUD getLoadBalancerInterface() {
+        return lbInterface;
+    }
+
+    public INeutronLoadBalancerPoolCRUD getLoadBalancerPoolInterface() {
+        return lbpInterface;
+    }
+
+    public INeutronLoadBalancerListenerCRUD getLoadBalancerListenerInterface() {
+        return lblInterface;
+    }
+
+    public INeutronLoadBalancerHealthMonitorCRUD getLoadBalancerHealthMonitorInterface() {
+        return lbhmInterface;
+    }
+
+    public INeutronLoadBalancerPoolMemberCRUD getLoadBalancerPoolMemberInterface() {
+        return lbpmInterface;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronNetworkCRUD(Object obj) {
+        networkInterface = (INeutronNetworkCRUD) getInstances(INeutronNetworkCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronSubnetCRUD(Object obj) {
+        subnetInterface = (INeutronSubnetCRUD) getInstances(INeutronSubnetCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronPortCRUD(Object obj) {
+        portInterface = (INeutronPortCRUD) getInstances(INeutronPortCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronRouterCRUD(Object obj) {
+        routerInterface = (INeutronRouterCRUD) getInstances(INeutronRouterCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFloatingIPCRUD(Object obj) {
+        fipInterface = (INeutronFloatingIPCRUD) getInstances(INeutronFloatingIPCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronSecurityGroupCRUD(Object obj) {
+        sgInterface = (INeutronSecurityGroupCRUD) getInstances(INeutronSecurityGroupCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronSecurityRuleCRUD(Object obj) {
+        srInterface = (INeutronSecurityRuleCRUD) getInstances(INeutronSecurityRuleCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFirewallCRUD(Object obj) {
+        fwInterface = (INeutronFirewallCRUD) getInstances(INeutronFirewallCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFirewallPolicyCRUD(Object obj) {
+        fwpInterface = (INeutronFirewallPolicyCRUD) getInstances(INeutronFirewallPolicyCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFirewallRuleCRUD(Object obj) {
+        fwrInterface = (INeutronFirewallRuleCRUD) getInstances(INeutronFirewallRuleCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerCRUD(Object obj) {
+        lbInterface = (INeutronLoadBalancerCRUD) getInstances(INeutronLoadBalancerCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerPoolCRUD(Object obj) {
+        lbpInterface = (INeutronLoadBalancerPoolCRUD) getInstances(INeutronLoadBalancerPoolCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerListenerCRUD(Object obj) {
+        lblInterface = (INeutronLoadBalancerListenerCRUD) getInstances(INeutronLoadBalancerListenerCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerHealthMonitorCRUD(Object obj) {
+        lbhmInterface = (INeutronLoadBalancerHealthMonitorCRUD) getInstances(INeutronLoadBalancerHealthMonitorCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerPoolMemberCRUD(Object obj) {
+        lbpmInterface = (INeutronLoadBalancerPoolMemberCRUD) getInstances(INeutronLoadBalancerPoolMemberCRUD.class, obj);
+        return this;
+    }
+
+    public Object getInstances(Class<?> clazz, Object bundle) {
+        try {
+            BundleContext bCtx = FrameworkUtil.getBundle(bundle.getClass()).getBundleContext();
+
+            ServiceReference<?>[] services = null;
+            services = bCtx.getServiceReferences(clazz.getName(), null);
+            if (services != null) {
+                return bCtx.getService(services[0]);
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error in getInstances", e);
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/AbstractNeutronInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/AbstractNeutronInterface.java
new file mode 100644 (file)
index 0000000..5986d14
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.openstack.netvirt.translator.crud.impl;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+
+
+public abstract class AbstractNeutronInterface<T extends DataObject, S extends INeutronObject> implements AutoCloseable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNeutronInterface.class);
+    private static final int DEDASHED_UUID_LENGTH = 32;
+    private static final int DEDASHED_UUID_START = 0;
+    private static final int DEDASHED_UUID_DIV1 = 8;
+    private static final int DEDASHED_UUID_DIV2 = 12;
+    private static final int DEDASHED_UUID_DIV3 = 16;
+    private static final int DEDASHED_UUID_DIV4 = 20;
+
+    private DataBroker db;
+
+    AbstractNeutronInterface(ProviderContext providerContext) {
+        this.db = providerContext.getSALService(DataBroker.class);
+    }
+
+    public DataBroker getDataBroker() {
+        return db;
+    }
+
+    protected abstract InstanceIdentifier<T> createInstanceIdentifier(T item);
+
+    protected abstract T toMd(S neutronObject);
+
+    protected abstract T toMd(String uuid);
+
+    protected <B extends org.opendaylight.yangtools.yang.binding.DataObject> B readMd(InstanceIdentifier<B> path) {
+        B result = null;
+        final ReadOnlyTransaction transaction = getDataBroker().newReadOnlyTransaction();
+        CheckedFuture<Optional<B>, ReadFailedException> future = transaction.read(LogicalDatastoreType.CONFIGURATION, path);
+        if (future != null) {
+            try {
+                result = future.checkedGet().orNull();
+            } catch (ReadFailedException e) {
+                LOGGER.warn("Failed to read {}", path, e);
+            }
+        }
+        transaction.close();
+        return result;
+    }
+
+    protected boolean addMd(S neutronObject) {
+        // TODO think about adding existence logic
+        return updateMd(neutronObject);
+    }
+
+    protected boolean updateMd(S neutronObject) {
+        WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+        T item = toMd(neutronObject);
+        InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, item,true);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.warn("Transation failed ",e);
+            return false;
+        }
+        return true;
+    }
+
+    protected boolean removeMd(T item) {
+        WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+        InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+        transaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.warn("Transation failed ",e);
+            return false;
+        }
+        return true;
+    }
+
+    protected Uuid toUuid(String uuid) {
+        Preconditions.checkNotNull(uuid);
+        Uuid result;
+        try {
+            result = new Uuid(uuid);
+        } catch(IllegalArgumentException e) {
+            // OK... someone didn't follow RFC 4122... lets try this the hard way
+            String dedashed = uuid.replace("-", "");
+            if(dedashed.length() == DEDASHED_UUID_LENGTH) {
+                String redashed = dedashed.substring(DEDASHED_UUID_START, DEDASHED_UUID_DIV1)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV1, DEDASHED_UUID_DIV2)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV2, DEDASHED_UUID_DIV3)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV3, DEDASHED_UUID_DIV4)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV4, DEDASHED_UUID_LENGTH);
+                result = new Uuid(redashed);
+            } else {
+                throw e;
+            }
+        }
+        return result;
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    protected boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for(Method toMethod: methods){
+            if(toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")){
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[])null);
+                    if(value != null){
+                        toMethod.invoke(target, value);
+                    }
+                } catch (Exception e) {
+                    LOGGER.error("Error in overwrite", e);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void close() throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallInterface.java
new file mode 100644 (file)
index 0000000..92d42b0
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFirewallCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronFirewallInterface extends AbstractNeutronInterface implements INeutronFirewallCRUD {
+
+    NeutronFirewallInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFirewallInterface neutronFirewallInterface = new NeutronFirewallInterface(providerContext);
+        ServiceRegistration<INeutronFirewallCRUD> neutronFirewallInterfaceRegistration = context.registerService(INeutronFirewallCRUD.class, neutronFirewallInterface, null);
+        if(neutronFirewallInterfaceRegistration != null) {
+            registrations.add(neutronFirewallInterfaceRegistration);
+        }
+    }
+
+    @Override
+    public boolean neutronFirewallExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronFirewall getNeutronFirewall(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronFirewall> getAllNeutronFirewalls() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronFirewall(NeutronFirewall input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronFirewall(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronFirewall(String uuid, NeutronFirewall delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronFirewallInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(INeutronObject neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallPolicyInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallPolicyInterface.java
new file mode 100644 (file)
index 0000000..a970cf7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFirewallPolicyCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ */
+
+public class NeutronFirewallPolicyInterface extends AbstractNeutronInterface implements INeutronFirewallPolicyCRUD {
+
+    NeutronFirewallPolicyInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronFirewallPolicyExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronFirewallPolicy> getAllNeutronFirewallPolicies() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronFirewallPolicy(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronFirewallPolicy(String uuid,
+            NeutronFirewallPolicy delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronFirewallPolicyInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(INeutronObject neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFirewallPolicyInterface neutronFirewallPolicyInterface = new NeutronFirewallPolicyInterface(providerContext);
+        ServiceRegistration<INeutronFirewallPolicyCRUD> neutronFirewallPolicyInterfaceRegistration = context.registerService(INeutronFirewallPolicyCRUD.class, neutronFirewallPolicyInterface, null);
+        if(neutronFirewallPolicyInterfaceRegistration != null) {
+            registrations.add(neutronFirewallPolicyInterfaceRegistration);
+        }
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallRuleInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFirewallRuleInterface.java
new file mode 100644 (file)
index 0000000..f54a222
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFirewallRuleCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronFirewallRuleInterface extends AbstractNeutronInterface implements INeutronFirewallRuleCRUD {
+
+    NeutronFirewallRuleInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronFirewallRuleExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronFirewallRule getNeutronFirewallRule(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronFirewallRule> getAllNeutronFirewallRules() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronFirewallRule(NeutronFirewallRule input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronFirewallRule(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronFirewallRule(String uuid,
+            NeutronFirewallRule delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronFirewallRuleInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(INeutronObject neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFirewallRuleInterface neutronFirewallRuleInterface = new NeutronFirewallRuleInterface(providerContext);
+        ServiceRegistration<INeutronFirewallRuleCRUD> neutronFirewallRuleInterfaceRegistration = context.registerService(INeutronFirewallRuleCRUD.class, neutronFirewallRuleInterface, null);
+        if(neutronFirewallRuleInterfaceRegistration != null) {
+            registrations.add(neutronFirewallRuleInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterface.java
new file mode 100644 (file)
index 0000000..a706438
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.FloatingipBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronFloatingIPInterface extends AbstractNeutronInterface<Floatingip, NeutronFloatingIP> implements INeutronFloatingIPCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronFloatingIPInterface.class);
+
+    NeutronFloatingIPInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBFloatingIPCRUD interface methods
+
+    @Override
+    public boolean floatingIPExists(String uuid) {
+        Floatingip fip = readMd(createInstanceIdentifier(toMd(uuid)));
+        return (fip != null);
+    }
+
+    @Override
+    public NeutronFloatingIP getFloatingIP(String uuid) {
+        Floatingip fip = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (fip == null) {
+            return null;
+        }
+        return fromMd(fip);
+    }
+
+    @Override
+    public List<NeutronFloatingIP> getAllFloatingIPs() {
+        Set<NeutronFloatingIP> allIPs = new HashSet<>();
+        Floatingips fips = readMd(createInstanceIdentifier());
+        if (fips != null) {
+            for (Floatingip fip: fips.getFloatingip()) {
+                allIPs.add(fromMd(fip));
+            }
+        }
+        LOGGER.debug("Exiting getAllFloatingIPs, Found {} FloatingIPs", allIPs.size());
+        List<NeutronFloatingIP> ans = new ArrayList<>();
+        ans.addAll(allIPs);
+        return ans;
+    }
+
+    @Override
+    public boolean addFloatingIP(NeutronFloatingIP input) {
+        if (floatingIPExists(input.getID())) {
+            return false;
+        }
+        return addMd(input);
+    }
+
+    @Override
+    public boolean removeFloatingIP(String uuid) {
+        NeutronFloatingIP fip = getFloatingIP(uuid);
+        if (fip == null) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updateFloatingIP(String uuid, NeutronFloatingIP delta) {
+        NeutronFloatingIP target = getFloatingIP(uuid);
+        if (target == null) {
+            return false;
+        }
+        delta.setPortUUID(target.getPortUUID());
+        delta.setFixedIPAddress(target.getFixedIPAddress());
+        return updateMd(delta);
+    }
+
+    @Override
+    protected Floatingip toMd(String uuid) {
+        FloatingipBuilder floatingipBuilder = new FloatingipBuilder();
+        floatingipBuilder.setUuid(toUuid(uuid));
+        return floatingipBuilder.build();
+    }
+
+    @Override
+    protected Floatingip toMd(NeutronFloatingIP floatingIp) {
+        FloatingipBuilder floatingipBuilder = new FloatingipBuilder();
+        if (floatingIp.getFixedIPAddress() != null) {
+            floatingipBuilder.setFixedIpAddress(new IpAddress(floatingIp.getFixedIPAddress().toCharArray()));
+        }
+        if(floatingIp.getFloatingIPAddress() != null) {
+            floatingipBuilder.setFloatingIpAddress(new IpAddress(floatingIp.getFloatingIPAddress().toCharArray()));
+        }
+        if (floatingIp.getFloatingNetworkUUID() != null) {
+            floatingipBuilder.setFloatingNetworkId(toUuid(floatingIp.getFloatingNetworkUUID()));
+        }
+        if (floatingIp.getPortUUID() != null) {
+            floatingipBuilder.setPortId(toUuid(floatingIp.getPortUUID()));
+        }
+        if (floatingIp.getRouterUUID() != null) {
+            floatingipBuilder.setRouterId(toUuid(floatingIp.getRouterUUID()));
+        }
+        if (floatingIp.getStatus() != null) {
+            floatingipBuilder.setStatus(floatingIp.getStatus());
+        }
+        if (floatingIp.getTenantUUID() != null) {
+            floatingipBuilder.setTenantId(toUuid(floatingIp.getTenantUUID()));
+        }
+        if (floatingIp.getID() != null) {
+            floatingipBuilder.setUuid(toUuid(floatingIp.getID()));
+        }
+        else {
+            LOGGER.warn("Attempting to write neutron floating IP without UUID");
+        }
+        return floatingipBuilder.build();
+    }
+
+    protected NeutronFloatingIP fromMd(Floatingip fip) {
+        NeutronFloatingIP result = new NeutronFloatingIP();
+        result.setID(String.valueOf(fip.getUuid().getValue()));
+        if (fip.getFloatingNetworkId() != null) {
+            result.setFloatingNetworkUUID(String.valueOf(fip.getFloatingNetworkId().getValue()));
+        }
+        if (fip.getPortId() != null) {
+            result.setPortUUID(String.valueOf(fip.getPortId().getValue()));
+        }
+        if (fip.getFixedIpAddress() != null ) {
+            result.setFixedIPAddress(String.valueOf(fip.getFixedIpAddress().getValue()));
+        }
+        if (fip.getFloatingIpAddress() != null) {
+            result.setFloatingIPAddress(String.valueOf(fip.getFloatingIpAddress().getValue()));
+        }
+        if (fip.getTenantId() != null) {
+            result.setTenantUUID(String.valueOf(fip.getTenantId().getValue()));
+        }
+        if (fip.getRouterId() != null) {
+            result.setRouterUUID(String.valueOf(fip.getRouterId().getValue()));
+        }
+        result.setStatus(fip.getStatus());
+        return result;
+    }
+
+    @Override
+    protected InstanceIdentifier<Floatingip> createInstanceIdentifier(
+            Floatingip item) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Floatingips.class)
+                .child(Floatingip.class,item.getKey());
+    }
+
+    protected InstanceIdentifier<Floatingips> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Floatingips.class);
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        ServiceRegistration<INeutronFloatingIPCRUD> neutronFloatingIPInterfaceRegistration = context.registerService(INeutronFloatingIPCRUD.class, neutronFloatingIPInterface, null);
+        if (neutronFloatingIPInterfaceRegistration != null) {
+            registrations.add(neutronFloatingIPInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerHealthMonitorInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerHealthMonitorInterface.java
new file mode 100644 (file)
index 0000000..5dea349
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Healthmonitors;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerHealthMonitorInterface extends AbstractNeutronInterface<Healthmonitors, NeutronLoadBalancerHealthMonitor> implements INeutronLoadBalancerHealthMonitorCRUD {
+
+    NeutronLoadBalancerHealthMonitorInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerHealthMonitorExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(
+            String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerHealthMonitor(
+            NeutronLoadBalancerHealthMonitor input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerHealthMonitor(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerHealthMonitor(String uuid,
+            NeutronLoadBalancerHealthMonitor delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerHealthMonitorInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier<Healthmonitors> createInstanceIdentifier(
+            Healthmonitors item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Healthmonitors toMd(NeutronLoadBalancerHealthMonitor neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Healthmonitors toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerHealthMonitorInterface neutronLoadBalancerHealthMonitorInterface = new NeutronLoadBalancerHealthMonitorInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerHealthMonitorCRUD> neutronLoadBalancerHealthMonitorInterfaceRegistration = context.registerService(INeutronLoadBalancerHealthMonitorCRUD.class, neutronLoadBalancerHealthMonitorInterface, null);
+        if(neutronLoadBalancerHealthMonitorInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerHealthMonitorInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerInterface.java
new file mode 100644 (file)
index 0000000..a0b1f41
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Loadbalancers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.loadbalancers.Loadbalancer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.loadbalancers.LoadbalancerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO: Migrate this to consume the MD-SAL data store, so that it can read all the data from data store.
+ * No need to worry about the write/update related methods here. OVSDB net-virt will use these CRUD Interface
+ * only for reading. We will cleanup these interface/methods later.
+ */
+public class NeutronLoadBalancerInterface extends AbstractNeutronInterface<Loadbalancer, NeutronLoadBalancer> implements INeutronLoadBalancerCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronLoadBalancerInterface.class);
+    private ConcurrentMap<String, NeutronLoadBalancer> loadBalancerDB  = new ConcurrentHashMap<>();
+
+
+    NeutronLoadBalancerInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerExists(String uuid) {
+        return loadBalancerDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancer getNeutronLoadBalancer(String uuid) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            LOGGER.debug("No LoadBalancer Have Been Defined");
+            return null;
+        }
+        return loadBalancerDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancer> getAllNeutronLoadBalancers() {
+        Set<NeutronLoadBalancer> allLoadBalancers = new HashSet<>();
+        for (Entry<String, NeutronLoadBalancer> entry : loadBalancerDB.entrySet()) {
+            NeutronLoadBalancer loadBalancer = entry.getValue();
+            allLoadBalancers.add(loadBalancer);
+        }
+        LOGGER.debug("Exiting getLoadBalancers, Found {} OpenStackLoadBalancer", allLoadBalancers.size());
+        List<NeutronLoadBalancer> ans = new ArrayList<>();
+        ans.addAll(allLoadBalancers);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancer(NeutronLoadBalancer input) {
+        if (neutronLoadBalancerExists(input.getID())) {
+            return false;
+        }
+        loadBalancerDB.putIfAbsent(input.getID(), input);
+        //TODO: add code to find INeutronLoadBalancerAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancer(String uuid) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            return false;
+        }
+        loadBalancerDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancer target = loadBalancerDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerInUse(String loadBalancerUUID) {
+        return !neutronLoadBalancerExists(loadBalancerUUID);
+    }
+
+    @Override
+    protected Loadbalancer toMd(String uuid) {
+        LoadbalancerBuilder loadBalancersBuilder = new LoadbalancerBuilder();
+        loadBalancersBuilder.setUuid(toUuid(uuid));
+        return loadBalancersBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Loadbalancer> createInstanceIdentifier(
+            Loadbalancer loadBalancer) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Loadbalancers.class)
+                .child(Loadbalancer.class, loadBalancer.getKey());
+    }
+
+    @Override
+    protected Loadbalancer toMd(NeutronLoadBalancer loadBalancer) {
+        LoadbalancerBuilder loadBalancersBuilder = new LoadbalancerBuilder();
+        loadBalancersBuilder.setAdminStateUp(loadBalancer.getLoadBalancerAdminStateUp());
+        if (loadBalancer.getLoadBalancerDescription() != null) {
+            loadBalancersBuilder.setDescr(loadBalancer.getLoadBalancerDescription());
+        }
+        if (loadBalancer.getLoadBalancerName() != null) {
+            loadBalancersBuilder.setName(loadBalancer.getLoadBalancerName());
+        }
+        if (loadBalancer.getLoadBalancerStatus() != null) {
+            loadBalancersBuilder.setStatus(loadBalancer.getLoadBalancerStatus());
+        }
+        if (loadBalancer.getLoadBalancerTenantID() != null) {
+            loadBalancersBuilder.setTenantId(toUuid(loadBalancer.getLoadBalancerTenantID()));
+        }
+        if (loadBalancer.getLoadBalancerVipAddress() != null) {
+            loadBalancersBuilder.setVipAddress(new IpAddress(loadBalancer.getLoadBalancerVipAddress().toCharArray()));
+        }
+        if (loadBalancer.getLoadBalancerVipSubnetID() != null) {
+            loadBalancersBuilder.setVipSubnetId(toUuid(loadBalancer.getLoadBalancerVipSubnetID()));
+        }
+        if (loadBalancer.getID() != null) {
+            loadBalancersBuilder.setUuid(toUuid(loadBalancer.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron load balancer without UUID");
+        }
+        return loadBalancersBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerInterface neutronLoadBalancerInterface = new NeutronLoadBalancerInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerCRUD> neutronLoadBalancerInterfaceRegistration = context.registerService(INeutronLoadBalancerCRUD.class, neutronLoadBalancerInterface, null);
+        if(neutronLoadBalancerInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerListenerInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerListenerInterface.java
new file mode 100644 (file)
index 0000000..1d8d064
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerListener;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Listeners;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerListenerInterface extends AbstractNeutronInterface<Listeners, NeutronLoadBalancerListener> implements INeutronLoadBalancerListenerCRUD {
+
+    NeutronLoadBalancerListenerInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerListenerExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronLoadBalancerListener getNeutronLoadBalancerListener(
+            String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerListener(
+            NeutronLoadBalancerListener input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerListener(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerListener(String uuid,
+            NeutronLoadBalancerListener delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerListenerInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier<Listeners> createInstanceIdentifier(
+            Listeners item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Listeners toMd(NeutronLoadBalancerListener neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Listeners toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerListenerInterface neutronLoadBalancerListenerInterface = new NeutronLoadBalancerListenerInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerListenerCRUD> neutronLoadBalancerListenerInterfaceRegistration = context.registerService(INeutronLoadBalancerListenerCRUD.class, neutronLoadBalancerListenerInterface, null);
+        if(neutronLoadBalancerListenerInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerListenerInterfaceRegistration);
+        }
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolInterface.java
new file mode 100644 (file)
index 0000000..48d43ac
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_ID;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer_SessionPersistence;
+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.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.PoolBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.pool.attributes.SessionPersistenceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * TODO: Migrate this to consume the MD-SAL data store, so that it can read all the data from data store.
+ * No need to worry about the write/update related methods here. OVSDB net-virt will use these CRUD Interface
+ * only for reading. We will cleanup these interface/methods later.
+ */
+
+public class NeutronLoadBalancerPoolInterface extends AbstractNeutronInterface<Pool, NeutronLoadBalancerPool> implements INeutronLoadBalancerPoolCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronLoadBalancerPoolInterface.class);
+    private ConcurrentMap<String, NeutronLoadBalancerPool> loadBalancerPoolDB = new ConcurrentHashMap<>();
+
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+            = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+            .put(ProtocolHttp.class,"HTTP")
+            .put(ProtocolHttps.class,"HTTPS")
+            .put(ProtocolTcp.class,"TCP")
+            .build();
+
+    NeutronLoadBalancerPoolInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolExists(String uuid) {
+        return loadBalancerPoolDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            LOGGER.debug("No LoadBalancerPool has Been Defined");
+            return null;
+        }
+        return loadBalancerPoolDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools() {
+        Set<NeutronLoadBalancerPool> allLoadBalancerPools = new HashSet<>();
+        for (Entry<String, NeutronLoadBalancerPool> entry : loadBalancerPoolDB.entrySet()) {
+            NeutronLoadBalancerPool loadBalancerPool = entry.getValue();
+            allLoadBalancerPools.add(loadBalancerPool);
+        }
+        LOGGER.debug("Exiting getLoadBalancerPools, Found {} OpenStackLoadBalancerPool", allLoadBalancerPools.size());
+        List<NeutronLoadBalancerPool> ans = new ArrayList<>();
+        ans.addAll(allLoadBalancerPools);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input) {
+        if (neutronLoadBalancerPoolExists(input.getID())) {
+            return false;
+        }
+        loadBalancerPoolDB.putIfAbsent(input.getID(), input);
+        //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerPool(String uuid) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            return false;
+        }
+        loadBalancerPoolDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancerPool target = loadBalancerPoolDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolInUse(String loadBalancerPoolUUID) {
+        return !neutronLoadBalancerPoolExists(loadBalancerPoolUUID);
+    }
+
+    @Override
+    protected Pool toMd(String uuid) {
+        PoolBuilder poolsBuilder = new PoolBuilder();
+        poolsBuilder.setUuid(toUuid(uuid));
+        return poolsBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Pool> createInstanceIdentifier(Pool pools) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Pools.class)
+                .child(Pool.class, pools.getKey());
+    }
+
+    @Override
+    protected Pool toMd(NeutronLoadBalancerPool pool) {
+        PoolBuilder poolBuilder = new PoolBuilder();
+        poolBuilder.setAdminStateUp(pool.getLoadBalancerPoolAdminIsStateIsUp());
+        if (pool.getLoadBalancerPoolDescription() != null) {
+            poolBuilder.setDescr(pool.getLoadBalancerPoolDescription());
+        }
+        if (pool.getNeutronLoadBalancerPoolHealthMonitorID() != null) {
+            poolBuilder.setHealthmonitorId(toUuid(pool.getNeutronLoadBalancerPoolHealthMonitorID()));
+        }
+        if (pool.getLoadBalancerPoolLbAlgorithm() != null) {
+            poolBuilder.setLbAlgorithm(pool.getLoadBalancerPoolLbAlgorithm());
+        }
+        if (pool.getLoadBalancerPoolListeners() != null) {
+            List<Uuid> listListener = new ArrayList<>();
+            for (Neutron_ID neutron_id : pool.getLoadBalancerPoolListeners()) {
+                listListener.add(toUuid(neutron_id.getID()));
+            }
+            poolBuilder.setListeners(listListener);
+        }
+        // because members are another container, we don't want to copy
+        // it over, so just skip it here
+        if (pool.getLoadBalancerPoolName() != null) {
+            poolBuilder.setName(pool.getLoadBalancerPoolName());
+        }
+        if (pool.getLoadBalancerPoolProtocol() != null) {
+            ImmutableBiMap<String, Class<? extends ProtocolBase>> mapper =
+                PROTOCOL_MAP.inverse();
+            poolBuilder.setProtocol(mapper.get(pool.getLoadBalancerPoolProtocol()));
+        }
+        if (pool.getLoadBalancerPoolSessionPersistence() != null) {
+            NeutronLoadBalancer_SessionPersistence sessionPersistence = pool.getLoadBalancerPoolSessionPersistence();
+            SessionPersistenceBuilder sessionPersistenceBuilder = new SessionPersistenceBuilder();
+            sessionPersistenceBuilder.setCookieName(sessionPersistence.getCookieName());
+            sessionPersistenceBuilder.setType(sessionPersistence.getType());
+            poolBuilder.setSessionPersistence(sessionPersistenceBuilder.build());
+        }
+        if (pool.getLoadBalancerPoolTenantID() != null) {
+            poolBuilder.setTenantId(toUuid(pool.getLoadBalancerPoolTenantID()));
+        }
+        if (pool.getID() != null) {
+            poolBuilder.setUuid(toUuid(pool.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron load balancer pool without UUID");
+        }
+        return poolBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerPoolInterface neutronLoadBalancerPoolInterface = new NeutronLoadBalancerPoolInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerPoolCRUD> neutronLoadBalancerPoolInterfaceRegistration = context.registerService(INeutronLoadBalancerPoolCRUD.class, neutronLoadBalancerPoolInterface, null);
+        if(neutronLoadBalancerPoolInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerPoolInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolMemberInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolMemberInterface.java
new file mode 100644 (file)
index 0000000..ef8530c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolMemberCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.Members;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerPoolMemberInterface extends
+        AbstractNeutronInterface<Members, NeutronLoadBalancerPoolMember> implements INeutronLoadBalancerPoolMemberCRUD {
+
+    NeutronLoadBalancerPoolMemberInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolMemberExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(
+            String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerPoolMember(
+            NeutronLoadBalancerPoolMember input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerPoolMember(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerPoolMember(String uuid,
+            NeutronLoadBalancerPoolMember delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolMemberInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier<Members> createInstanceIdentifier(Members item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Members toMd(NeutronLoadBalancerPoolMember neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Members toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerPoolMemberInterface neutronLoadBalancerPoolMemberInterface = new NeutronLoadBalancerPoolMemberInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerPoolMemberCRUD> neutronLoadBalancerPoolMemberInterfaceRegistration = context.registerService(INeutronLoadBalancerPoolMemberCRUD.class, neutronLoadBalancerPoolMemberInterface, null);
+        if(neutronLoadBalancerPoolMemberInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerPoolMemberInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronNetworkInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronNetworkInterface.java
new file mode 100644 (file)
index 0000000..834256d
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork_Segment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3ExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.SegmentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronNetworkInterface extends AbstractNeutronInterface<Network,NeutronNetwork> implements INeutronNetworkCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronNetworkInterface.class);
+
+    private static final ImmutableBiMap<Class<? extends NetworkTypeBase>,String> NETWORK_MAP
+            = new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>,String>()
+            .put(NetworkTypeFlat.class,"flat")
+            .put(NetworkTypeGre.class,"gre")
+            .put(NetworkTypeVlan.class,"vlan")
+            .put(NetworkTypeVxlan.class,"vxlan")
+            .build();
+
+    NeutronNetworkInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBNetworkCRUD methods
+
+    @Override
+    public boolean networkExists(String uuid) {
+        Network network = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (network == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronNetwork getNetwork(String uuid) {
+        Network network = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (network == null) {
+            return null;
+        }
+        return fromMd(network);
+    }
+
+    @Override
+    public List<NeutronNetwork> getAllNetworks() {
+        Set<NeutronNetwork> allNetworks = new HashSet<>();
+        Networks networks = readMd(createInstanceIdentifier());
+        if (networks != null) {
+            for (Network network: networks.getNetwork()) {
+                allNetworks.add(fromMd(network));
+            }
+        }
+        LOGGER.debug("Exiting getAllNetworks, Found {} OpenStackNetworks", allNetworks.size());
+        List<NeutronNetwork> ans = new ArrayList<>();
+        ans.addAll(allNetworks);
+        return ans;
+    }
+
+    @Override
+    public boolean addNetwork(NeutronNetwork input) {
+        if (networkExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNetwork(String uuid) {
+        if (!networkExists(uuid)) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updateNetwork(String uuid, NeutronNetwork delta) {
+        if (!networkExists(uuid)) {
+            return false;
+        }
+/* note: because what we get is *not* a delta but (at this point) the updated
+ * object, this is much simpler - just replace the value and update the mdsal
+ * with it */
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean networkInUse(String netUUID) {
+        if (!networkExists(netUUID)) {
+            return true;
+        }
+        return false;
+    }
+
+    protected NeutronNetwork fromMd(Network network) {
+        NeutronNetwork result = new NeutronNetwork();
+        result.setAdminStateUp(network.isAdminStateUp());
+        result.setNetworkName(network.getName());
+        result.setShared(network.isShared());
+        result.setStatus(network.getStatus());
+// todo remove '-' chars as tenant id doesn't use them
+        result.setTenantID(network.getTenantId().getValue());
+        result.setID(network.getUuid().getValue());
+
+        NetworkL3Extension l3Extension = network.getAugmentation(NetworkL3Extension.class);
+        result.setRouterExternal(l3Extension.isExternal());
+
+        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        result.setProviderPhysicalNetwork(providerExtension.getPhysicalNetwork());
+        result.setProviderSegmentationID(providerExtension.getSegmentationId());
+        result.setProviderNetworkType(NETWORK_MAP.get(providerExtension.getNetworkType()));
+        List<NeutronNetwork_Segment> segments = new ArrayList<>();
+        if (providerExtension.getSegments() != null) {
+            for (Segments segment: providerExtension.getSegments()) {
+                NeutronNetwork_Segment neutronSegment = new NeutronNetwork_Segment();
+                neutronSegment.setProviderPhysicalNetwork(segment.getPhysicalNetwork());
+                neutronSegment.setProviderSegmentationID(segment.getSegmentationId());
+                neutronSegment.setProviderNetworkType(NETWORK_MAP.get(segment.getNetworkType()));
+                segments.add(neutronSegment);
+            }
+        }
+        result.setSegments(segments);
+        return result;
+    }
+
+    private void fillExtensions(NetworkBuilder networkBuilder,
+                                NeutronNetwork network) {
+        NetworkL3ExtensionBuilder l3ExtensionBuilder = new NetworkL3ExtensionBuilder();
+        if (network.getRouterExternal() != null) {
+            l3ExtensionBuilder.setExternal(network.getRouterExternal());
+        }
+
+        NetworkProviderExtensionBuilder providerExtensionBuilder = new NetworkProviderExtensionBuilder();
+        if (network.getProviderPhysicalNetwork() != null) {
+            providerExtensionBuilder.setPhysicalNetwork(network.getProviderPhysicalNetwork());
+        }
+        if (network.getProviderSegmentationID() != null) {
+            providerExtensionBuilder.setSegmentationId(network.getProviderSegmentationID());
+        }
+        if (network.getProviderNetworkType() != null) {
+            ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper =
+                NETWORK_MAP.inverse();
+            providerExtensionBuilder.setNetworkType(mapper.get(network.getProviderNetworkType()));
+        }
+        if (network.getSegments() != null) {
+            List<Segments> segments = new ArrayList<>();
+            long count = 0;
+            for( NeutronNetwork_Segment segment : network.getSegments()) {
+                count++;
+                SegmentsBuilder segmentsBuilder = new SegmentsBuilder();
+                if (segment.getProviderPhysicalNetwork() != null) {
+                    segmentsBuilder.setPhysicalNetwork(segment.getProviderPhysicalNetwork());
+                }
+                if (segment.getProviderSegmentationID() != null) {
+                    segmentsBuilder.setSegmentationId(segment.getProviderSegmentationID());
+                }
+                if (segment.getProviderNetworkType() != null) {
+                    ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper =
+                        NETWORK_MAP.inverse();
+                    segmentsBuilder.setNetworkType(mapper.get(segment.getProviderNetworkType()));
+                }
+                segmentsBuilder.setSegmentationIndex(count);
+                segments.add(segmentsBuilder.build());
+            }
+            providerExtensionBuilder.setSegments(segments);
+        }
+        if (network.getProviderSegmentationID() != null) {
+            providerExtensionBuilder.setSegmentationId(network.getProviderSegmentationID());
+        }
+
+        networkBuilder.addAugmentation(NetworkL3Extension.class,
+                                       l3ExtensionBuilder.build());
+        networkBuilder.addAugmentation(NetworkProviderExtension.class,
+                                       providerExtensionBuilder.build());
+    }
+
+    protected Network toMd(NeutronNetwork network) {
+        NetworkBuilder networkBuilder = new NetworkBuilder();
+        fillExtensions(networkBuilder, network);
+
+        networkBuilder.setAdminStateUp(network.getAdminStateUp());
+        if (network.getNetworkName() != null) {
+            networkBuilder.setName(network.getNetworkName());
+        }
+        if (network.getShared() != null) {
+            networkBuilder.setShared(network.getShared());
+        }
+        if (network.getStatus() != null) {
+            networkBuilder.setStatus(network.getStatus());
+        }
+        if (network.getTenantID() != null) {
+            networkBuilder.setTenantId(toUuid(network.getTenantID()));
+        }
+        if (network.getNetworkUUID() != null) {
+            networkBuilder.setUuid(toUuid(network.getNetworkUUID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron network without UUID");
+        }
+        return networkBuilder.build();
+    }
+
+    protected Network toMd(String uuid) {
+        NetworkBuilder networkBuilder = new NetworkBuilder();
+        networkBuilder.setUuid(toUuid(uuid));
+        return networkBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Network> createInstanceIdentifier(Network network) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Networks.class)
+                .child(Network.class,network.getKey());
+    }
+
+    protected InstanceIdentifier<Networks> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Networks.class);
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronNetworkInterface neutronNetworkInterface = new NeutronNetworkInterface(providerContext);
+        ServiceRegistration<INeutronNetworkCRUD> neutronNetworkInterfaceRegistration = context.registerService(INeutronNetworkCRUD.class, neutronNetworkInterface, null);
+        if(neutronNetworkInterfaceRegistration != null) {
+            registrations.add(neutronNetworkInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java
new file mode 100644 (file)
index 0000000..e2dbab6
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort_VIFDetail;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+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.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetailsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOptsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsBuilder;
+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.PortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.portsecurity.rev150712.PortSecurityExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.portsecurity.rev150712.PortSecurityExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronPortInterface extends AbstractNeutronInterface<Port, NeutronPort> implements INeutronPortCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronPortInterface.class);
+
+    NeutronPortInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBPortCRUD methods
+
+    @Override
+    public boolean portExists(String uuid) {
+        Port port = readMd(createInstanceIdentifier(toMd(uuid)));
+        return port != null;
+    }
+
+    @Override
+    public NeutronPort getPort(String uuid) {
+        Port port = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (port == null) {
+            return null;
+        }
+        return fromMd(port);
+    }
+
+    @Override
+    public List<NeutronPort> getAllPorts() {
+        Set<NeutronPort> allPorts = new HashSet<>();
+        Ports ports = readMd(createInstanceIdentifier());
+        if (ports != null) {
+            for (Port port : ports.getPort()) {
+                allPorts.add(fromMd(port));
+            }
+        }
+        LOGGER.debug("Exiting getAllPorts, Found {} OpenStackPorts", allPorts.size());
+        List<NeutronPort> ans = new ArrayList<>();
+        ans.addAll(allPorts);
+        return ans;
+    }
+
+    @Override
+    public boolean addPort(NeutronPort input) {
+        if (portExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removePort(String uuid) {
+        if (!portExists(uuid)) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updatePort(String uuid, NeutronPort delta) {
+        if (!portExists(uuid)) {
+            return false;
+        }
+        updateMd(delta);
+        return true;
+    }
+
+    // @deprecated, will be removed in Boron
+    @Override
+    public boolean macInUse(String macAddress) {
+        return false;
+    }
+
+    // @deprecated, will be removed in Boron
+    @Override
+    public NeutronPort getGatewayPort(String subnetUUID) {
+        return null;
+    }
+
+    @Override
+    protected InstanceIdentifier<Port> createInstanceIdentifier(Port port) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Ports.class)
+                .child(Port.class, port.getKey());
+    }
+
+    protected InstanceIdentifier<Ports> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Ports.class);
+    }
+
+    protected void addExtensions(Port port, NeutronPort result) {
+        PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
+        result.setBindinghostID(binding.getHostId());
+        if (binding.getVifDetails() != null) {
+            List<NeutronPort_VIFDetail> details = new ArrayList<>();
+            for (VifDetails vifDetail : binding.getVifDetails()) {
+                NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
+                detail.setPortFilter(vifDetail.isPortFilter());
+                detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
+                details.add(detail);
+            }
+            result.setVIFDetail(details);
+        }
+        result.setBindingvifType(binding.getVifType());
+        result.setBindingvnicType(binding.getVnicType());
+    }
+
+    private void portSecurityExtension(Port port, NeutronPort result) {
+        PortSecurityExtension portSecurity = port.getAugmentation(PortSecurityExtension.class);
+        if(portSecurity != null && portSecurity.isPortSecurityEnabled() != null) {
+            result.setPortSecurityEnabled(portSecurity.isPortSecurityEnabled());
+        }
+    }
+
+    protected NeutronPort fromMd(Port port) {
+        NeutronPort result = new NeutronPort();
+        result.setAdminStateUp(port.isAdminStateUp());
+        if (port.getAllowedAddressPairs() != null) {
+            List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<>();
+            for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
+                NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
+                pair.setIpAddress(mdPair.getIpAddress());
+                pair.setMacAddress(mdPair.getMacAddress());
+                pairs.add(pair);
+            }
+            result.setAllowedAddressPairs(pairs);
+        }
+        result.setDeviceID(port.getDeviceId());
+        result.setDeviceOwner(port.getDeviceOwner());
+        if (port.getExtraDhcpOpts() != null) {
+            List<NeutronPort_ExtraDHCPOption> options = new ArrayList<>();
+            for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
+                NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
+                arg.setName(opt.getOptName());
+                arg.setValue(opt.getOptValue());
+                options.add(arg);
+            }
+            result.setExtraDHCPOptions(options);
+        }
+        if (port.getFixedIps() != null) {
+            List<Neutron_IPs> ips = new ArrayList<>();
+            for (FixedIps mdIP : port.getFixedIps()) {
+                Neutron_IPs ip = new Neutron_IPs();
+                ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+                ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+                ips.add(ip);
+            }
+            result.setFixedIPs(ips);
+        }
+        result.setMacAddress(port.getMacAddress());
+        result.setName(port.getName());
+        result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
+        if (port.getSecurityGroups() != null) {
+            Set<NeutronSecurityGroup> allGroups = new HashSet<>();
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
+            INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
+            for (Uuid sgUuid : port.getSecurityGroups()) {
+                NeutronSecurityGroup secGroup = sgIf.getNeutronSecurityGroup(sgUuid.getValue());
+                if (secGroup != null) {
+                    allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+                }
+            }
+            List<NeutronSecurityGroup> groups = new ArrayList<>();
+            groups.addAll(allGroups);
+            result.setSecurityGroups(groups);
+        }
+        result.setStatus(port.getStatus());
+        if (port.getTenantId() != null) {
+            result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
+        }
+        result.setPortUUID(String.valueOf(port.getUuid().getValue()));
+        addExtensions(port, result);
+        portSecurityExtension(port, result);
+        return result;
+    }
+
+    @Override
+    protected Port toMd(NeutronPort neutronPort) {
+        PortBindingExtensionBuilder bindingBuilder = new PortBindingExtensionBuilder();
+        if (neutronPort.getBindinghostID() != null) {
+            bindingBuilder.setHostId(neutronPort.getBindinghostID());
+        }
+        if (neutronPort.getVIFDetail() != null) {
+            List<VifDetails> listVifDetail = new ArrayList<>();
+            for (NeutronPort_VIFDetail detail: neutronPort.getVIFDetail()) {
+                VifDetailsBuilder vifDetailsBuilder = new VifDetailsBuilder();
+                if (detail.getPortFilter() != null) {
+                    vifDetailsBuilder.setPortFilter(detail.getPortFilter());
+                }
+                if (detail.getOvsHybridPlug() != null) {
+                    vifDetailsBuilder.setOvsHybridPlug(detail.getOvsHybridPlug());
+                }
+                listVifDetail.add(vifDetailsBuilder.build());
+            }
+            bindingBuilder.setVifDetails(listVifDetail);
+        }
+        if (neutronPort.getBindingvifType() != null) {
+            bindingBuilder.setVifType(neutronPort.getBindingvifType());
+        }
+        if (neutronPort.getBindingvnicType() != null) {
+            bindingBuilder.setVnicType(neutronPort.getBindingvnicType());
+        }
+
+        PortSecurityExtensionBuilder portSecurityBuilder = new PortSecurityExtensionBuilder();
+        if (neutronPort.getPortSecurityEnabled() != null) {
+            portSecurityBuilder.setPortSecurityEnabled(neutronPort.getPortSecurityEnabled());
+        }
+        PortBuilder portBuilder = new PortBuilder();
+        portBuilder.addAugmentation(PortBindingExtension.class,
+                                    bindingBuilder.build());
+        portBuilder.addAugmentation(PortSecurityExtension.class, portSecurityBuilder.build());
+        portBuilder.setAdminStateUp(neutronPort.isAdminStateUp());
+        if(neutronPort.getAllowedAddressPairs() != null) {
+            List<AllowedAddressPairs> listAllowedAddressPairs = new ArrayList<>();
+            for (NeutronPort_AllowedAddressPairs allowedAddressPairs : neutronPort.getAllowedAddressPairs()) {
+                    AllowedAddressPairsBuilder allowedAddressPairsBuilder = new AllowedAddressPairsBuilder();
+                    allowedAddressPairsBuilder.setIpAddress(allowedAddressPairs.getIpAddress());
+                    allowedAddressPairsBuilder.setMacAddress(allowedAddressPairs.getMacAddress());
+                    listAllowedAddressPairs.add(allowedAddressPairsBuilder.build());
+            }
+            portBuilder.setAllowedAddressPairs(listAllowedAddressPairs);
+        }
+        if (neutronPort.getDeviceID() != null) {
+            portBuilder.setDeviceId(neutronPort.getDeviceID());
+        }
+        if (neutronPort.getDeviceOwner() != null) {
+        portBuilder.setDeviceOwner(neutronPort.getDeviceOwner());
+        }
+        if (neutronPort.getExtraDHCPOptions() != null) {
+            List<ExtraDhcpOpts> listExtraDHCPOptions = new ArrayList<>();
+            for (NeutronPort_ExtraDHCPOption extraDHCPOption : neutronPort.getExtraDHCPOptions()) {
+                ExtraDhcpOptsBuilder extraDHCPOptsBuilder = new ExtraDhcpOptsBuilder();
+                extraDHCPOptsBuilder.setOptName(extraDHCPOption.getName());
+                extraDHCPOptsBuilder.setOptValue(extraDHCPOption.getValue());
+                listExtraDHCPOptions.add(extraDHCPOptsBuilder.build());
+            }
+            portBuilder.setExtraDhcpOpts(listExtraDHCPOptions);
+        }
+        if (neutronPort.getFixedIPs() != null) {
+            List<FixedIps> listNeutronIPs = new ArrayList<>();
+            for (Neutron_IPs neutron_IPs : neutronPort.getFixedIPs()) {
+                FixedIpsBuilder fixedIpsBuilder = new FixedIpsBuilder();
+                fixedIpsBuilder.setIpAddress(new IpAddress(neutron_IPs.getIpAddress().toCharArray()));
+                fixedIpsBuilder.setSubnetId(toUuid(neutron_IPs.getSubnetUUID()));
+                listNeutronIPs.add(fixedIpsBuilder.build());
+            }
+            portBuilder.setFixedIps(listNeutronIPs);
+        }
+        if (neutronPort.getMacAddress() != null) {
+            portBuilder.setMacAddress(neutronPort.getMacAddress());
+        }
+        if (neutronPort.getName() != null) {
+        portBuilder.setName(neutronPort.getName());
+        }
+        if (neutronPort.getNetworkUUID() != null) {
+        portBuilder.setNetworkId(toUuid(neutronPort.getNetworkUUID()));
+        }
+        if (neutronPort.getSecurityGroups() != null) {
+            List<Uuid> listSecurityGroups = new ArrayList<>();
+            for (NeutronSecurityGroup neutronSecurityGroup : neutronPort.getSecurityGroups()) {
+                listSecurityGroups.add(toUuid(neutronSecurityGroup.getID()));
+            }
+            portBuilder.setSecurityGroups(listSecurityGroups);
+        }
+        if (neutronPort.getStatus() != null) {
+            portBuilder.setStatus(neutronPort.getStatus());
+        }
+        if (neutronPort.getTenantID() != null) {
+            portBuilder.setTenantId(toUuid(neutronPort.getTenantID()));
+        }
+        if (neutronPort.getPortUUID() != null) {
+            portBuilder.setUuid(toUuid(neutronPort.getPortUUID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron port without UUID");
+        }
+        return portBuilder.build();
+    }
+
+    @Override
+    protected Port toMd(String uuid) {
+        PortBuilder portBuilder = new PortBuilder();
+        portBuilder.setUuid(toUuid(uuid));
+        return portBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronPortInterface neutronPortInterface = new NeutronPortInterface(providerContext);
+        ServiceRegistration<INeutronPortCRUD> neutronPortInterfaceRegistration = context.registerService(INeutronPortCRUD.class, neutronPortInterface, null);
+        if(neutronPortInterfaceRegistration != null) {
+            registrations.add(neutronPortInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronRouterInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronRouterInterface.java
new file mode 100644 (file)
index 0000000..cf4ddd7
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronRouterCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_NetworkReference;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronRouterInterface extends  AbstractNeutronInterface<Router, NeutronRouter> implements INeutronRouterCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronRouterInterface.class);
+    // methods needed for creating caches
+
+
+    NeutronRouterInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+
+    // IfNBRouterCRUD Interface methods
+
+    @Override
+    public boolean routerExists(String uuid) {
+        Router router = readMd(createInstanceIdentifier(toMd(uuid)));
+        return router != null;
+    }
+
+    @Override
+    public NeutronRouter getRouter(String uuid) {
+        Router router = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (router == null) {
+            return null;
+        }
+        return fromMd(router);
+    }
+
+    @Override
+    public List<NeutronRouter> getAllRouters() {
+        Set<NeutronRouter> allRouters = new HashSet<>();
+        Routers routers = readMd(createInstanceIdentifier());
+        if (routers != null) {
+            for (Router router: routers.getRouter()) {
+                allRouters.add(fromMd(router));
+            }
+        }
+        LOGGER.debug("Exiting getAllRouters, Found {} Routers", allRouters.size());
+        List<NeutronRouter> ans = new ArrayList<>();
+        ans.addAll(allRouters);
+        return ans;
+    }
+
+    @Override
+    public boolean addRouter(NeutronRouter input) {
+        if (routerExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeRouter(String uuid) {
+        if (!routerExists(uuid)) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updateRouter(String uuid, NeutronRouter delta) {
+        if (!routerExists(uuid)) {
+            return false;
+        }
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean routerInUse(String routerUUID) {
+        if (!routerExists(routerUUID)) {
+            return true;
+        }
+        NeutronRouter target = getRouter(routerUUID);
+        return (target.getInterfaces().size() > 0);
+    }
+
+    @Override
+    protected Router toMd(NeutronRouter router) {
+
+        RouterBuilder routerBuilder = new RouterBuilder();
+
+        if (router.getRouterUUID() != null) {
+            routerBuilder.setUuid(toUuid(router.getRouterUUID()));
+        }
+        if (router.getName() != null) {
+            routerBuilder.setName(router.getName());
+        }
+        if (router.getTenantID() != null && !router.getTenantID().isEmpty()) {
+            routerBuilder.setTenantId(toUuid(router.getTenantID()));
+        }
+        if (router.getStatus() != null) {
+            routerBuilder.setStatus(router.getStatus());
+        }
+        if (router.getGatewayPortId() != null && !router.getGatewayPortId().isEmpty()) {
+            routerBuilder.setGatewayPortId(toUuid(router.getGatewayPortId()));
+        }
+        routerBuilder.setAdminStateUp(router.getAdminStateUp());
+        routerBuilder.setDistributed(router.getDistributed());
+        if (router.getRoutes() != null) {
+            List<Routes> routes = new ArrayList<>();
+            for (Routes route : router.getRoutes()) {
+                routes.add(route);
+            }
+            routerBuilder.setRoutes(routes);
+        }
+        if (router.getExternalGatewayInfo() != null) {
+            ExternalGatewayInfo externalGatewayInfo = null;
+            List<NeutronRouter_NetworkReference> neutronRouter_NetworkReferences = new ArrayList<>();
+            neutronRouter_NetworkReferences.add(router.getExternalGatewayInfo());
+            for (NeutronRouter_NetworkReference externalGatewayInfos : neutronRouter_NetworkReferences) {
+                ExternalGatewayInfoBuilder builder = new ExternalGatewayInfoBuilder();
+                builder.setEnableSnat(externalGatewayInfos.getEnableSNAT());
+                builder.setExternalNetworkId(toUuid(externalGatewayInfos.getNetworkID()));
+                if (externalGatewayInfos.getExternalFixedIPs() != null) {
+                    List<ExternalFixedIps> externalFixedIps = new ArrayList<>();
+                    for (Neutron_IPs eIP : externalGatewayInfos.getExternalFixedIPs()) {
+                        ExternalFixedIpsBuilder eFixedIpBuilder = new ExternalFixedIpsBuilder();
+                        eFixedIpBuilder.setIpAddress(new IpAddress(eIP.getIpAddress().toCharArray()));
+                        eFixedIpBuilder.setSubnetId(toUuid(eIP.getSubnetUUID()));
+                        externalFixedIps.add(eFixedIpBuilder.build());
+                    }
+                    builder.setExternalFixedIps(externalFixedIps);
+                }
+                externalGatewayInfo = builder.build();
+            }
+            routerBuilder.setExternalGatewayInfo(externalGatewayInfo);
+        }
+        if (router.getInterfaces() != null) {
+            Map<String, NeutronRouter_Interface> mapInterfaces = new HashMap<>();
+            List<Interfaces> interfaces = new ArrayList<>();
+            for (Entry<String, NeutronRouter_Interface> entry : mapInterfaces.entrySet()) {
+                interfaces.add((Interfaces) entry.getValue());
+            }
+            routerBuilder.setInterfaces(interfaces);
+        }
+        if (router.getID() != null) {
+            routerBuilder.setUuid(toUuid(router.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron router without UUID");
+        }
+        return routerBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Router> createInstanceIdentifier(Router router) {
+        return InstanceIdentifier.create(Neutron.class)
+                 .child(Routers.class)
+                 .child(Router.class, router.getKey());
+    }
+
+    protected InstanceIdentifier<Routers> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class).child(Routers.class);
+    }
+
+    @Override
+    protected Router toMd(String uuid) {
+        RouterBuilder routerBuilder = new RouterBuilder();
+        routerBuilder.setUuid(toUuid(uuid));
+        return routerBuilder.build();
+    }
+
+    public NeutronRouter fromMd(Router router) {
+        NeutronRouter result = new NeutronRouter();
+        result.setID(String.valueOf(router.getUuid().getValue()));
+        result.setName(router.getName());
+        result.setTenantID(String.valueOf(router.getTenantId().getValue()));
+        result.setAdminStateUp(router.isAdminStateUp());
+        result.setStatus(router.getStatus());
+        result.setDistributed(router.isDistributed());
+        if (router.getGatewayPortId() != null) {
+            result.setGatewayPortId(String.valueOf(router.getGatewayPortId().getValue()));
+        }
+        if (router.getRoutes() != null) {
+            List<Routes> routes = new ArrayList<>();
+            for (Routes route : router.getRoutes()) {
+                routes.add(route);
+            }
+            result.setRoutes(routes);
+        }
+
+        if (router.getExternalGatewayInfo() != null) {
+            NeutronRouter_NetworkReference extGwInfo = new NeutronRouter_NetworkReference();
+            extGwInfo.setNetworkID(String.valueOf(router.getExternalGatewayInfo().getExternalNetworkId().getValue()));
+            extGwInfo.setEnableSNAT(router.getExternalGatewayInfo().isEnableSnat());
+            if (router.getExternalGatewayInfo().getExternalFixedIps() != null) {
+                List<Neutron_IPs> fixedIPs = new ArrayList<>();
+                for (ExternalFixedIps mdFixedIP : router.getExternalGatewayInfo().getExternalFixedIps()) {
+                     Neutron_IPs fixedIP = new Neutron_IPs();
+                     fixedIP.setSubnetUUID(String.valueOf(mdFixedIP.getSubnetId().getValue()));
+                     fixedIP.setIpAddress(String.valueOf(mdFixedIP.getIpAddress().getValue()));
+                     fixedIPs.add(fixedIP);
+                }
+                extGwInfo.setExternalFixedIPs(fixedIPs);
+            }
+            result.setExternalGatewayInfo(extGwInfo);
+        }
+
+        if (router.getInterfaces() != null) {
+            Map<String, NeutronRouter_Interface> interfaces = new HashMap<>();
+            for (Interfaces mdInterface : router.getInterfaces()) {
+                NeutronRouter_Interface pojoInterface = new NeutronRouter_Interface();
+                String id = String.valueOf(mdInterface.getUuid().getValue());
+                pojoInterface.setID(id);
+                pojoInterface.setTenantID(String.valueOf(mdInterface.getTenantId().getValue()));
+                pojoInterface.setSubnetUUID(String.valueOf(mdInterface.getSubnetId().getValue()));
+                pojoInterface.setPortUUID(String.valueOf(mdInterface.getPortId().getValue()));
+                interfaces.put(id, pojoInterface);
+            }
+            result.setInterfaces(interfaces);
+        }
+        return result;
+    }
+    
+    public static void registerNewInterface(BundleContext context,
+            ProviderContext providerContext,
+            List<ServiceRegistration<?>> registrations) {
+       NeutronRouterInterface neutronRouterInterface = new NeutronRouterInterface(providerContext);
+       ServiceRegistration<INeutronRouterCRUD> neutronRouterInterfaceRegistration = context.registerService(INeutronRouterCRUD.class, neutronRouterInterface, null);
+       if(neutronRouterInterfaceRegistration != null) {
+               registrations.add(neutronRouterInterfaceRegistration);
+       }
+       }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSecurityGroupInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSecurityGroupInterface.java
new file mode 100644 (file)
index 0000000..3a39ec2
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+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.secgroups.rev150712.security.groups.attributes.SecurityGroups;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NeutronSecurityGroupInterface extends AbstractNeutronInterface<SecurityGroup,NeutronSecurityGroup> implements INeutronSecurityGroupCRUD {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSecurityGroupInterface.class);
+
+    NeutronSecurityGroupInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronSecurityGroupExists(String uuid) {
+        SecurityGroup group = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (group == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronSecurityGroup getNeutronSecurityGroup(String uuid) {
+        SecurityGroup group = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (group == null) {
+            return null;
+        }
+        return fromMd(group);
+    }
+
+    @Override
+    public List<NeutronSecurityGroup> getAllNeutronSecurityGroups() {
+        Set<NeutronSecurityGroup> allSecurityGroups = new HashSet<>();
+        SecurityGroups groups = readMd(createInstanceIdentifier());
+        if (groups != null) {
+            for (SecurityGroup group: groups.getSecurityGroup()) {
+                allSecurityGroups.add(fromMd(group));
+            }
+        }
+        LOGGER.debug("Exiting getSecurityGroups, Found {} OpenStackSecurityGroup", allSecurityGroups.size());
+        List<NeutronSecurityGroup> ans = new ArrayList<>();
+        ans.addAll(allSecurityGroups);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronSecurityGroup(NeutronSecurityGroup input) {
+        if (neutronSecurityGroupExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronSecurityGroup(String uuid) {
+        if (!neutronSecurityGroupExists(uuid)) {
+            return false;
+        }
+        removeMd(toMd(uuid));
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta) {
+        if (!neutronSecurityGroupExists(uuid)) {
+            return false;
+        }
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean neutronSecurityGroupInUse(String securityGroupUUID) {
+        return !neutronSecurityGroupExists(securityGroupUUID);
+    }
+
+    protected NeutronSecurityGroup fromMd(SecurityGroup group) {
+        NeutronSecurityGroup answer = new NeutronSecurityGroup();
+        if (group.getName() != null) {
+            answer.setSecurityGroupName(group.getName());
+        }
+        if (group.getDescription() != null) {
+            answer.setSecurityGroupDescription(group.getDescription());
+        }
+        if (group.getTenantId() != null) {
+            answer.setSecurityGroupTenantID(group.getTenantId().getValue().replace("-",""));
+        }
+
+        // Bug 4550
+        // https://bugs.opendaylight.org/show_bug.cgi?id=4550
+        // Now SecurityGroup::securityGroupRule isn't updated.
+        // always rebuid it from security group rules
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronSecurityRuleCRUD(this);
+        INeutronSecurityRuleCRUD srCrud = interfaces.getSecurityRuleInterface();
+
+        List<NeutronSecurityRule> rules = new ArrayList<NeutronSecurityRule>();
+        String sgId = group.getUuid().getValue();
+        for (NeutronSecurityRule rule: srCrud.getAllNeutronSecurityRules()) {
+            if (rule.getSecurityRuleGroupID().equals(sgId)) {
+                rules.add(rule);
+            }
+        }
+        answer.setSecurityRules(rules);
+
+        if (group.getUuid() != null) {
+            answer.setID(group.getUuid().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    protected SecurityGroup toMd(NeutronSecurityGroup securityGroup) {
+        SecurityGroupBuilder securityGroupBuilder = new SecurityGroupBuilder();
+        if (securityGroup.getSecurityGroupName() != null) {
+            securityGroupBuilder.setName(securityGroup.getSecurityGroupName());
+        }
+        if (securityGroup.getSecurityGroupDescription() != null) {
+            securityGroupBuilder.setDescription(securityGroup.getSecurityGroupDescription());
+        }
+        if (securityGroup.getSecurityGroupTenantID() != null) {
+            securityGroupBuilder.setTenantId(toUuid(securityGroup.getSecurityGroupTenantID()));
+        }
+
+        // don't update security group rule, always empty list
+        // Bug 4550
+        // https://bugs.opendaylight.org/show_bug.cgi?id=4550
+        securityGroupBuilder.setSecurityRules(new ArrayList<Uuid>());
+
+        if (securityGroup.getID() != null) {
+            securityGroupBuilder.setUuid(toUuid(securityGroup.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron securityGroup without UUID");
+        }
+
+        return securityGroupBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<SecurityGroup> createInstanceIdentifier(SecurityGroup securityGroup) {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityGroups.class).child(SecurityGroup.class,
+                                               securityGroup.getKey());
+    }
+
+    protected InstanceIdentifier<SecurityGroups> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityGroups.class);
+    }
+
+    @Override
+    protected SecurityGroup toMd(String uuid) {
+        SecurityGroupBuilder securityGroupBuilder = new SecurityGroupBuilder();
+        securityGroupBuilder.setUuid(toUuid(uuid));
+        return securityGroupBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronSecurityGroupInterface neutronSecurityGroupInterface = new NeutronSecurityGroupInterface(providerContext);
+        ServiceRegistration<INeutronSecurityGroupCRUD> neutronSecurityGroupInterfaceRegistration = context.registerService(INeutronSecurityGroupCRUD.class, neutronSecurityGroupInterface, null);
+        if(neutronSecurityGroupInterfaceRegistration != null) {
+            registrations.add(neutronSecurityGroupInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSecurityRuleInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSecurityRuleInterface.java
new file mode 100644 (file)
index 0000000..5847059
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2014, 2015 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
+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.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
+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.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+
+public class NeutronSecurityRuleInterface extends AbstractNeutronInterface<SecurityRule, NeutronSecurityRule> implements INeutronSecurityRuleCRUD {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSecurityRuleInterface.class);
+
+    private static final ImmutableBiMap<Class<? extends DirectionBase>, String> DIRECTION_MAP = ImmutableBiMap.of(
+            DirectionEgress.class, NeutronSecurityRule.DIRECTION_EGRESS,
+            DirectionIngress.class, NeutronSecurityRule.DIRECTION_INGRESS);
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>, String> PROTOCOL_MAP = ImmutableBiMap.of(
+            ProtocolIcmp.class, NeutronSecurityRule.PROTOCOL_ICMP,
+            ProtocolTcp.class, NeutronSecurityRule.PROTOCOL_TCP,
+            ProtocolUdp.class, NeutronSecurityRule.PROTOCOL_UDP,
+            ProtocolIcmpV6.class, NeutronSecurityRule.PROTOCOL_ICMPV6);
+    private static final ImmutableBiMap<Class<? extends EthertypeBase>,String> ETHERTYPE_MAP = ImmutableBiMap.of(
+            EthertypeV4.class, NeutronSecurityRule.ETHERTYPE_IPV4,
+            EthertypeV6.class, NeutronSecurityRule.ETHERTYPE_IPV6);
+
+    NeutronSecurityRuleInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    private void updateSecGroupRuleInSecurityGroup(NeutronSecurityRule input) {
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronSecurityGroupCRUD(this);
+        INeutronSecurityGroupCRUD sgCrud = interfaces.getSecurityGroupInterface();
+        NeutronSecurityGroup sg = sgCrud.getNeutronSecurityGroup(input.getSecurityRuleGroupID());
+        if(sg != null && sg.getSecurityRules() != null) {
+            for(NeutronSecurityRule sgr :sg.getSecurityRules()) {
+                if(sgr != null && sgr.getID() != null && sgr.getID().equals(input.getID())) {
+                    int index = sg.getSecurityRules().indexOf(sgr);
+                    sg.getSecurityRules().set(index, input);
+                }
+            }
+        }
+        if (sg != null) {
+            sg.getSecurityRules().add(input);
+        }
+    }
+
+    private void removeSecGroupRuleFromSecurityGroup(NeutronSecurityRule input) {
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronSecurityGroupCRUD(this);
+        INeutronSecurityGroupCRUD sgCrud = interfaces.getSecurityGroupInterface();
+        NeutronSecurityGroup sg = sgCrud.getNeutronSecurityGroup(input.getSecurityRuleGroupID());
+        if(sg != null && sg.getSecurityRules() != null) {
+            List<NeutronSecurityRule> toRemove = new ArrayList<>();
+            for(NeutronSecurityRule sgr :sg.getSecurityRules()) {
+                if(sgr.getID() != null && sgr.getID().equals(input.getID())) {
+                    toRemove.add(sgr);
+                }
+            }
+            sg.getSecurityRules().removeAll(toRemove);
+        }
+    }
+
+    @Override
+    public boolean neutronSecurityRuleExists(String uuid) {
+        SecurityRule rule = readMd(createInstanceIdentifier(toMd(uuid)));
+        return rule != null;
+    }
+
+    @Override
+    public NeutronSecurityRule getNeutronSecurityRule(String uuid) {
+        SecurityRule rule = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (rule == null) {
+            return null;
+        }
+        return fromMd(rule);
+    }
+
+    @Override
+    public List<NeutronSecurityRule> getAllNeutronSecurityRules() {
+        Set<NeutronSecurityRule> allSecurityRules = new HashSet<>();
+        SecurityRules rules = readMd(createInstanceIdentifier());
+        if (rules != null) {
+            for (SecurityRule rule: rules.getSecurityRule()) {
+                allSecurityRules.add(fromMd(rule));
+            }
+        }
+        LOGGER.debug("Exiting getSecurityRule, Found {} OpenStackSecurityRule", allSecurityRules.size());
+        return new ArrayList<>(allSecurityRules);
+    }
+
+    @Override
+    public boolean addNeutronSecurityRule(NeutronSecurityRule input) {
+        if (neutronSecurityRuleExists(input.getID())) {
+            return false;
+        }
+        updateSecGroupRuleInSecurityGroup(input);
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronSecurityRule(String uuid) {
+        if (!neutronSecurityRuleExists(uuid)) {
+            return false;
+        }
+        removeSecGroupRuleFromSecurityGroup(getNeutronSecurityRule(uuid));
+        removeMd(toMd(uuid));
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta) {
+        if (!neutronSecurityRuleExists(uuid)) {
+            return false;
+        }
+        updateSecGroupRuleInSecurityGroup(delta);
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean neutronSecurityRuleInUse(String securityRuleUUID) {
+        return !neutronSecurityRuleExists(securityRuleUUID);
+    }
+
+    protected NeutronSecurityRule fromMd(SecurityRule rule) {
+        NeutronSecurityRule answer = new NeutronSecurityRule();
+        if (rule.getTenantId() != null) {
+            answer.setSecurityRuleTenantID(rule.getTenantId().getValue().replace("-",""));
+        }
+        if (rule.getDirection() != null) {
+            answer.setSecurityRuleDirection(DIRECTION_MAP.get(rule.getDirection()));
+        }
+        if (rule.getSecurityGroupId() != null) {
+            answer.setSecurityRuleGroupID(rule.getSecurityGroupId().getValue());
+        }
+        if (rule.getRemoteGroupId() != null) {
+            answer.setSecurityRemoteGroupID(rule.getRemoteGroupId().getValue());
+        }
+        if (rule.getRemoteIpPrefix() != null) {
+            answer.setSecurityRuleRemoteIpPrefix(rule.getRemoteIpPrefix().getIpv4Prefix() != null?
+                    rule.getRemoteIpPrefix().getIpv4Prefix().getValue():rule.getRemoteIpPrefix().getIpv6Prefix().getValue());
+        }
+        if (rule.getProtocol() != null) {
+            answer.setSecurityRuleProtocol(PROTOCOL_MAP.get(rule.getProtocol()));
+        }
+        if (rule.getEthertype() != null) {
+            answer.setSecurityRuleEthertype(ETHERTYPE_MAP.get(rule.getEthertype()));
+        }
+        if (rule.getPortRangeMin() != null) {
+            answer.setSecurityRulePortMin(rule.getPortRangeMin());
+        }
+        if (rule.getPortRangeMax() != null) {
+            answer.setSecurityRulePortMax(rule.getPortRangeMax());
+        }
+        if (rule.getId() != null) {
+            answer.setID(rule.getId().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    protected SecurityRule toMd(NeutronSecurityRule securityRule) {
+        SecurityRuleBuilder securityRuleBuilder = new SecurityRuleBuilder();
+
+        if (securityRule.getSecurityRuleTenantID() != null) {
+            securityRuleBuilder.setTenantId(toUuid(securityRule.getSecurityRuleTenantID()));
+        }
+        if (securityRule.getSecurityRuleDirection() != null) {
+            ImmutableBiMap<String, Class<? extends DirectionBase>> mapper =
+                    DIRECTION_MAP.inverse();
+            securityRuleBuilder.setDirection(mapper.get(securityRule.getSecurityRuleDirection()));
+        }
+        if (securityRule.getSecurityRuleGroupID() != null) {
+            securityRuleBuilder.setSecurityGroupId(toUuid(securityRule.getSecurityRuleGroupID()));
+        }
+        if (securityRule.getSecurityRemoteGroupID() != null) {
+            securityRuleBuilder.setRemoteGroupId(toUuid(securityRule.getSecurityRemoteGroupID()));
+        }
+        if (securityRule.getSecurityRuleRemoteIpPrefix() != null) {
+            securityRuleBuilder.setRemoteIpPrefix(new IpPrefix(securityRule.getSecurityRuleRemoteIpPrefix().toCharArray()));
+        }
+        if (securityRule.getSecurityRuleProtocol() != null) {
+            ImmutableBiMap<String, Class<? extends ProtocolBase>> mapper =
+                    PROTOCOL_MAP.inverse();
+            securityRuleBuilder.setProtocol(mapper.get(securityRule.getSecurityRuleProtocol()));
+        }
+        if (securityRule.getSecurityRuleEthertype() != null) {
+            ImmutableBiMap<String, Class<? extends EthertypeBase>> mapper =
+                    ETHERTYPE_MAP.inverse();
+            securityRuleBuilder.setEthertype(mapper.get(securityRule.getSecurityRuleEthertype()));
+        }
+        if (securityRule.getSecurityRulePortMin() != null) {
+            securityRuleBuilder.setPortRangeMin(securityRule.getSecurityRulePortMin());
+        }
+        if (securityRule.getSecurityRulePortMax() != null) {
+            securityRuleBuilder.setPortRangeMax(securityRule.getSecurityRulePortMax());
+        }
+        if (securityRule.getID() != null) {
+            securityRuleBuilder.setId(toUuid(securityRule.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron securityRule without UUID");
+        }
+        return securityRuleBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<SecurityRule> createInstanceIdentifier(SecurityRule securityRule) {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityRules.class).child(SecurityRule.class,
+                                              securityRule.getKey());
+    }
+
+    protected InstanceIdentifier<SecurityRules> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityRules.class);
+    }
+
+    @Override
+    protected SecurityRule toMd(String uuid) {
+        SecurityRuleBuilder securityRuleBuilder = new SecurityRuleBuilder();
+        securityRuleBuilder.setId(toUuid(uuid));
+        return securityRuleBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronSecurityRuleInterface neutronSecurityRuleInterface = new NeutronSecurityRuleInterface(providerContext);
+        ServiceRegistration<INeutronSecurityRuleCRUD> neutronSecurityRuleInterfaceRegistration = context.registerService(INeutronSecurityRuleCRUD.class, neutronSecurityRuleInterface, null);
+        if(neutronSecurityRuleInterfaceRegistration != null) {
+            registrations.add(neutronSecurityRuleInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSubnetInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronSubnetInterface.java
new file mode 100644 (file)
index 0000000..c435869
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnetIPAllocationPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Base;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Off;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Slaac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateless;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPoolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSubnetInterface extends AbstractNeutronInterface<Subnet, NeutronSubnet> implements INeutronSubnetCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSubnetInterface.class);
+
+    private static final ImmutableBiMap<Class<? extends IpVersionBase>,Integer> IPV_MAP
+            = new ImmutableBiMap.Builder<Class<? extends IpVersionBase>,Integer>()
+            .put(IpVersionV4.class, 4)
+            .put(IpVersionV6.class, 6)
+            .build();
+
+    private static final ImmutableBiMap<Class<? extends Dhcpv6Base>,String> DHCPV6_MAP
+            = new ImmutableBiMap.Builder<Class<? extends Dhcpv6Base>,String>()
+            .put(Dhcpv6Off.class,"off")
+            .put(Dhcpv6Stateful.class,"dhcpv6-stateful")
+            .put(Dhcpv6Slaac.class,"slaac")
+            .put(Dhcpv6Stateless.class,"dhcpv6-stateless")
+            .build();
+
+    NeutronSubnetInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBSubnetCRUD methods
+
+    @Override
+    public boolean subnetExists(String uuid) {
+        Subnet subnet = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (subnet == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronSubnet getSubnet(String uuid) {
+        Subnet subnet = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (subnet == null) {
+            return null;
+        }
+        return fromMd(subnet);
+    }
+
+    @Override
+    public List<NeutronSubnet> getAllSubnets() {
+        Set<NeutronSubnet> allSubnets = new HashSet<>();
+        Subnets subnets = readMd(createInstanceIdentifier());
+        if (subnets != null) {
+            for (Subnet subnet: subnets.getSubnet()) {
+                allSubnets.add(fromMd(subnet));
+            }
+        }
+        LOGGER.debug("Exiting getAllSubnets, Found {} OpenStackSubnets", allSubnets.size());
+        List<NeutronSubnet> ans = new ArrayList<>();
+        ans.addAll(allSubnets);
+        return ans;
+    }
+
+    @Override
+    public boolean addSubnet(NeutronSubnet input) {
+        String id = input.getID();
+        if (subnetExists(id)) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeSubnet(String uuid) {
+        NeutronSubnet target = getSubnet(uuid);
+        if (target == null) {
+            return false;
+        }
+        removeMd(toMd(uuid));
+        return true;
+    }
+
+    @Override
+    public boolean updateSubnet(String uuid, NeutronSubnet delta) {
+        if (!subnetExists(uuid)) {
+            return false;
+        }
+/* note: because what we get is *not* a delta but (at this point) the updated
+ * object, this is much simpler - just replace the value and update the mdsal
+ * with it */
+        updateMd(delta);
+        return true;
+    }
+
+// note: this is being set to false in preparation for deprecation and removal
+    @Override
+    public boolean subnetInUse(String subnetUUID) {
+        return false;
+    }
+
+    protected NeutronSubnet fromMd(Subnet subnet) {
+        NeutronSubnet result = new NeutronSubnet();
+        result.setName(subnet.getName());
+        result.setTenantID(String.valueOf(subnet.getTenantId().getValue()).replace("-",""));
+        result.setNetworkUUID(subnet.getNetworkId().getValue());
+        result.setIpVersion(IPV_MAP.get(subnet.getIpVersion()));
+        result.setCidr(subnet.getCidr());
+        result.setIpV6RaMode(DHCPV6_MAP.get(subnet.getIpv6RaMode()));
+        result.setIpV6AddressMode(DHCPV6_MAP.get(subnet.getIpv6AddressMode()));
+        result.setEnableDHCP(subnet.isEnableDhcp());
+        if (subnet.getAllocationPools() != null) {
+            List<NeutronSubnetIPAllocationPool> allocationPools = new ArrayList<>();
+            for (AllocationPools allocationPool : subnet.getAllocationPools()) {
+                NeutronSubnetIPAllocationPool pool = new NeutronSubnetIPAllocationPool();
+                pool.setPoolStart(allocationPool.getStart());
+                pool.setPoolEnd(allocationPool.getEnd());
+                allocationPools.add(pool);
+            }
+            result.setAllocationPools(allocationPools);
+        }
+        if (subnet.getDnsNameservers() != null) {
+            List<String> dnsNameServers = new ArrayList<>();
+            for (IpAddress dnsNameServer : subnet.getDnsNameservers()) {
+                dnsNameServers.add(String.valueOf(dnsNameServer.getValue()));
+            }
+            result.setDnsNameservers(dnsNameServers);
+        }
+        result.setID(subnet.getUuid().getValue());
+// read through the ports and put the ones in this subnet into the internal
+// myPorts object.
+// @deprecated and will be removed in Boron
+        Set<NeutronPort> allPorts = new HashSet<>();
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronPortCRUD(this);
+        INeutronPortCRUD portIf = interfaces.getPortInterface();
+        for (NeutronPort port : portIf.getAllPorts()) {
+            if (port.getDeviceOwner().equalsIgnoreCase("network:router_interface")) {
+                result.setGatewayIP(String.valueOf(subnet.getGatewayIp().getValue()));
+            }
+            if (port.getFixedIPs() != null) {
+                for (Neutron_IPs ip : port.getFixedIPs()) {
+                    if (ip.getSubnetUUID().equals(result.getID())) {
+                        allPorts.add(port);
+                    }
+                }
+            }
+        }
+        List<NeutronPort> ports = new ArrayList<>();
+        ports.addAll(allPorts);
+        result.setPorts(ports);
+        return result;
+    }
+
+    protected Subnet toMd(NeutronSubnet subnet) {
+        SubnetBuilder subnetBuilder = new SubnetBuilder();
+        if (subnet.getName() != null) {
+            subnetBuilder.setName(subnet.getName());
+        }
+        if (subnet.getTenantID() != null) {
+            subnetBuilder.setTenantId(toUuid(subnet.getTenantID()));
+        }
+        if (subnet.getNetworkUUID() != null) {
+            subnetBuilder.setNetworkId(toUuid(subnet.getNetworkUUID()));
+        }
+        if (subnet.getIpVersion() != null) {
+            ImmutableBiMap<Integer, Class<? extends IpVersionBase>> mapper =
+                    IPV_MAP.inverse();
+            subnetBuilder.setIpVersion(mapper.get(subnet
+                    .getIpVersion()));
+        }
+        if (subnet.getCidr() != null) {
+            subnetBuilder.setCidr(subnet.getCidr());
+        }
+        if (subnet.getGatewayIP() != null) {
+            IpAddress ipAddress = new IpAddress(subnet.getGatewayIP()
+                    .toCharArray());
+            subnetBuilder.setGatewayIp(ipAddress);
+        }
+        if (subnet.getIpV6RaMode() != null) {
+            ImmutableBiMap<String, Class<? extends Dhcpv6Base>> mapper =
+                    DHCPV6_MAP.inverse();
+            subnetBuilder.setIpv6RaMode(mapper.get(subnet.getIpV6RaMode()));
+        }
+        if (subnet.getIpV6AddressMode() != null) {
+            ImmutableBiMap<String, Class<? extends Dhcpv6Base>> mapper =
+                    DHCPV6_MAP.inverse();
+            subnetBuilder.setIpv6AddressMode(mapper.get(subnet.getIpV6AddressMode()));
+        }
+        subnetBuilder.setEnableDhcp(subnet.getEnableDHCP());
+        if (subnet.getAllocationPools() != null) {
+            List<AllocationPools> allocationPools = new ArrayList<>();
+            for (NeutronSubnetIPAllocationPool allocationPool : subnet
+                    .getAllocationPools()) {
+                AllocationPoolsBuilder builder = new AllocationPoolsBuilder();
+                builder.setStart(allocationPool.getPoolStart());
+                builder.setEnd(allocationPool.getPoolEnd());
+                AllocationPools temp = builder.build();
+                allocationPools.add(temp);
+            }
+            subnetBuilder.setAllocationPools(allocationPools);
+        }
+        if (subnet.getDnsNameservers() != null) {
+            List<IpAddress> dnsNameServers = new ArrayList<>();
+            for (String dnsNameServer : subnet.getDnsNameservers()) {
+                IpAddress ipAddress = new IpAddress(dnsNameServer.toCharArray());
+                dnsNameServers.add(ipAddress);
+            }
+            subnetBuilder.setDnsNameservers(dnsNameServers);
+        }
+        if (subnet.getID() != null) {
+            subnetBuilder.setUuid(toUuid(subnet.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron subnet without UUID");
+        }
+        return subnetBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Subnet> createInstanceIdentifier(Subnet subnet) {
+        return InstanceIdentifier.create(Neutron.class).child(Subnets.class)
+                .child(Subnet.class, subnet.getKey());
+    }
+
+    protected InstanceIdentifier<Subnets> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Subnets.class);
+    }
+
+    @Override
+    protected Subnet toMd(String uuid) {
+        SubnetBuilder subnetBuilder = new SubnetBuilder();
+        subnetBuilder.setUuid(toUuid(uuid));
+        return subnetBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronSubnetInterface neutronSubnetInterface = new NeutronSubnetInterface(providerContext);
+        ServiceRegistration<INeutronSubnetCRUD> neutronSubnetInterfaceRegistration = context.registerService(INeutronSubnetCRUD.class, neutronSubnetInterface, null);
+        if(neutronSubnetInterfaceRegistration != null) {
+            registrations.add(neutronSubnetInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallAware.java
new file mode 100644 (file)
index 0000000..66b004a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewall;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement
+ *
+ */
+
+public interface INeutronFirewallAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified firewall can be created
+     *
+     * @param firewall
+     *            instance of proposed new Firewall object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronFirewall(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method for taking action after a firewall has been created
+     *
+     * @param firewall
+     *            instance of new Firewall object
+     */
+    void neutronFirewallCreated(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewall can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the firewall object using patch semantics
+     * @param original
+     *            instance of the Firewall object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronFirewall(NeutronFirewall delta, NeutronFirewall original);
+
+    /**
+     * Services provide this interface method for taking action after a firewall has been updated
+     *
+     * @param firewall
+     *            instance of modified Firewall object
+     */
+    void neutronFirewallUpdated(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewall can be deleted
+     *
+     * @param firewall
+     *            instance of the Firewall object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronFirewall(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method for taking action after a firewall has been deleted
+     *
+     * @param firewall
+     *            instance of deleted Firewall object
+     */
+    void neutronFirewallDeleted(NeutronFirewall firewall);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallPolicyAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallPolicyAware.java
new file mode 100644 (file)
index 0000000..acf609a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallPolicy;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Policys needs to implement
+ *
+ */
+
+public interface INeutronFirewallPolicyAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallPolicy can be created
+     *
+     * @param firewallPolicy
+     *            instance of proposed new Firewall Policy object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method for taking action after a firewallPolicy has been created
+     *
+     * @param firewallPolicy
+     *            instance of new Firewall Policy object
+     */
+    void neutronFirewallPolicyCreated(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallPolicy can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the firewallPolicy object using patch semantics
+     * @param original
+     *            instance of the Firewall Policy object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronFirewallPolicy(NeutronFirewallPolicy delta, NeutronFirewallPolicy original);
+
+    /**
+     * Services provide this interface method for taking action after a firewallPolicy has been updated
+     *
+     * @param firewallPolicy
+     *            instance of modified Firewall Policy object
+     */
+    void neutronFirewallPolicyUpdated(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallPolicy can be deleted
+     *
+     * @param firewallPolicy
+     *            instance of the Firewall Policy object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method for taking action after a firewallPolicy has been deleted
+     *
+     * @param firewallPolicy
+     *            instance of deleted Firewall Policy object
+     */
+    void neutronFirewallPolicyDeleted(NeutronFirewallPolicy firewallPolicy);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallRuleAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFirewallRuleAware.java
new file mode 100644 (file)
index 0000000..412c044
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallRule;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement
+ *
+ */
+
+public interface INeutronFirewallRuleAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallRule can be created
+     *
+     * @param firewallRule
+     *            instance of proposed new Firewall Rule object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronFirewallRule(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method for taking action after a firewallRule has been created
+     *
+     * @param firewallRule
+     *            instance of new Firewall Rule object
+     */
+    void neutronFirewallRuleCreated(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallRule can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the firewallRule object using patch semantics
+     * @param original
+     *            instance of the Firewall Rule object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronFirewallRule(NeutronFirewallRule delta, NeutronFirewallRule original);
+
+    /**
+     * Services provide this interface method for taking action after a firewallRule has been updated
+     *
+     * @param firewallRule
+     *            instance of modified Firewall Rule object
+     */
+    void neutronFirewallRuleUpdated(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallRule can be deleted
+     *
+     * @param firewallRule
+     *            instance of the Firewall Rule object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronFirewallRule(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method for taking action after a firewallRule has been deleted
+     *
+     * @param firewallRule
+     *            instance of deleted Firewall Rule object
+     */
+    void neutronFirewallRuleDeleted(NeutronFirewallRule firewallRule);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFloatingIPAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronFloatingIPAware.java
new file mode 100644 (file)
index 0000000..90f1232
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron FloatingIPs needs to implement
+ *
+ */
+
+public interface INeutronFloatingIPAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be created
+     *
+     * @param floatingIP
+     *            instance of proposed new Neutron FloatingIP object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateFloatingIP(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been created
+     *
+     * @param floatingIP
+     *            instance of new Neutron FloatingIP object
+     */
+    void neutronFloatingIPCreated(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the floatingIP object using patch semantics
+     * @param original
+     *            instance of the Neutron FloatingIP object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateFloatingIP(NeutronFloatingIP delta, NeutronFloatingIP original);
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been updated
+     *
+     * @param floatingIP
+     *            instance of modified Neutron FloatingIP object
+     */
+    void neutronFloatingIPUpdated(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be deleted
+     *
+     * @param floatingIP
+     *            instance of the Neutron FloatingIP object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteFloatingIP(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been deleted
+     *
+     * @param floatingIP
+     *            instance of deleted Neutron FloatingIP object
+     */
+    void neutronFloatingIPDeleted(NeutronFloatingIP floatingIP);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerAware.java
new file mode 100644 (file)
index 0000000..a3beb72
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancer Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be created
+     *
+     * @param loadBalancer
+     *            instance of proposed new LoadBalancer object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been created
+     *
+     * @param loadBalancer
+     *            instance of new LoadBalancer object
+     */
+    void neutronLoadBalancerCreated(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified loadBalancer can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancer object using patch semantics
+     * @param original
+     *            instance of the LoadBalancer object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been updated
+     *
+     * @param loadBalancer
+     *            instance of modified LoadBalancer object
+     */
+    void neutronLoadBalancerUpdated(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be deleted
+     *
+     * @param loadBalancer
+     *            instance of the LoadBalancer object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been deleted
+     *
+     * @param loadBalancer
+     *            instance of deleted LoadBalancer object
+     */
+    void neutronLoadBalancerDeleted(NeutronLoadBalancer loadBalancer);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerHealthMonitorAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerHealthMonitorAware.java
new file mode 100644 (file)
index 0000000..27b47bd
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerHealthMonitor Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be created
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of proposed new LoadBalancerHealthMonitor object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been created
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of new LoadBalancerHealthMonitor object
+     */
+    void neutronLoadBalancerHealthMonitorCreated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerHealthMonitor object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerHealthMonitor object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor delta,
+            NeutronLoadBalancerHealthMonitor original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been updated
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of modified LoadBalancerHealthMonitor object
+     */
+    void neutronLoadBalancerHealthMonitorUpdated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be deleted
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of the LoadBalancerHealthMonitor object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been deleted
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of deleted LoadBalancerHealthMonitor object
+     */
+    void neutronLoadBalancerHealthMonitorDeleted(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerListenerAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerListenerAware.java
new file mode 100644 (file)
index 0000000..38dbee1
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerListener;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerListener Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerListenerAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be created
+     *
+     * @param loadBalancerListener
+     *            instance of proposed new LoadBalancerListener object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been created
+     *
+     * @param loadBalancerListener
+     *            instance of new LoadBalancerListener object
+     */
+    void neutronLoadBalancerListenerCreated(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerListener object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerListener object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerListener(NeutronLoadBalancerListener delta,
+            NeutronLoadBalancerListener original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been updated
+     *
+     * @param loadBalancerListener
+     *            instance of modified LoadBalancerListener object
+     */
+    void neutronLoadBalancerListenerUpdated(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be deleted
+     *
+     * @param loadBalancerListener
+     *            instance of the LoadBalancerListener object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been deleted
+     *
+     * @param loadBalancerListener
+     *            instance of deleted LoadBalancerListener object
+     */
+    void neutronLoadBalancerListenerDeleted(NeutronLoadBalancerListener loadBalancerListener);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolAware.java
new file mode 100644 (file)
index 0000000..b137398
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerPool Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerPoolAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be created
+     *
+     * @param loadBalancerPool
+     *            instance of proposed new LoadBalancerPool object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been created
+     *
+     * @param loadBalancerPool
+     *            instance of new LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified loadBalancerPool can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerPool object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerPool object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been updated
+     *
+     * @param loadBalancerPool
+     *            instance of modified LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be deleted
+     *
+     * @param loadBalancerPool
+     *            instance of the LoadBalancerPool object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been deleted
+     *
+     * @param loadBalancerPool
+     *            instance of deleted LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool loadBalancerPool);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolMemberAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolMemberAware.java
new file mode 100644 (file)
index 0000000..13f09f9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+
+public interface INeutronLoadBalancerPoolMemberAware {
+
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be created
+     *
+     * @param loadBalancerPoolMember
+     *            instance of proposed new LoadBalancerPool object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been created
+     *
+     * @param loadBalancerPoolMember
+     *            instance of new LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerPoolMember object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerPool object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta,
+            NeutronLoadBalancerPoolMember original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been updated
+     *
+     * @param loadBalancerPoolMember
+     *            instance of modified LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be deleted
+     *
+     * @param loadBalancerPoolMember
+     *            instance of the LoadBalancerPool object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been deleted
+     *
+     * @param loadBalancerPoolMember
+     *            instance of deleted LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronNetworkAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronNetworkAware.java
new file mode 100644 (file)
index 0000000..043ce74
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Networks needs to implement
+ *
+ */
+
+public interface INeutronNetworkAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified network can be created
+     *
+     * @param network
+     *            instance of proposed new Neutron Network object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNetwork(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method for taking action after a network has been created
+     *
+     * @param network
+     *            instance of new Neutron Network object
+     */
+    void neutronNetworkCreated(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method to indicate if the specified network can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the network object using patch semantics
+     * @param original
+     *            instance of the Neutron Network object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNetwork(NeutronNetwork delta, NeutronNetwork original);
+
+    /**
+     * Services provide this interface method for taking action after a network has been updated
+     *
+     * @param network
+     *            instance of modified Neutron Network object
+     */
+    void neutronNetworkUpdated(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method to indicate if the specified network can be deleted
+     *
+     * @param network
+     *            instance of the Neutron Network object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNetwork(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method for taking action after a network has been deleted
+     *
+     * @param network
+     *            instance of deleted Neutron Network object
+     */
+    void neutronNetworkDeleted(NeutronNetwork network);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronPortAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronPortAware.java
new file mode 100644 (file)
index 0000000..5621100
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Ports needs to implement
+ *
+ */
+
+public interface INeutronPortAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified port can be created
+     *
+     * @param port
+     *            instance of proposed new Neutron Port object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreatePort(NeutronPort port);
+
+    /**
+     * Services provide this interface method for taking action after a port has been created
+     *
+     * @param port
+     *            instance of new Neutron Port object
+     */
+    void neutronPortCreated(NeutronPort port);
+
+    /**
+     * Services provide this interface method to indicate if the specified port can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the port object using patch semantics
+     * @param original
+     *            instance of the Neutron Port object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdatePort(NeutronPort delta, NeutronPort original);
+
+    /**
+     * Services provide this interface method for taking action after a port has been updated
+     *
+     * @param port
+     *            instance of modified Neutron Port object
+     */
+    void neutronPortUpdated(NeutronPort port);
+
+    /**
+     * Services provide this interface method to indicate if the specified port can be deleted
+     *
+     * @param port
+     *            instance of the Neutron Port object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeletePort(NeutronPort port);
+
+    /**
+     * Services provide this interface method for taking action after a port has been deleted
+     *
+     * @param port
+     *            instance of deleted Port Network object
+     */
+    void neutronPortDeleted(NeutronPort port);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronRouterAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronRouterAware.java
new file mode 100644 (file)
index 0000000..c372d1a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Routers needs to implement
+ *
+ */
+
+public interface INeutronRouterAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be created
+     *
+     * @param router
+     *            instance of proposed new Neutron Router object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateRouter(NeutronRouter router);
+
+    /**
+     * Services provide this interface method for taking action after a router has been created
+     *
+     * @param router
+     *            instance of new Neutron Router object
+     */
+    void neutronRouterCreated(NeutronRouter router);
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the router object using patch semantics
+     * @param original
+     *            instance of the Neutron Router object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateRouter(NeutronRouter delta, NeutronRouter original);
+
+    /**
+     * Services provide this interface method for taking action after a router has been updated
+     *
+     * @param router
+     *            instance of modified Neutron Router object
+     */
+    void neutronRouterUpdated(NeutronRouter router);
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be deleted
+     *
+     * @param router
+     *            instance of the Neutron Router object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteRouter(NeutronRouter router);
+
+    /**
+     * Services provide this interface method for taking action after a router has been deleted
+     *
+     * @param router
+     *            instance of deleted Router Network object
+     */
+    void neutronRouterDeleted(NeutronRouter router);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified interface can be attached to the specified router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface to be attached to the router
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the attach operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+    /**
+     * Services provide this interface method for taking action
+     * after an interface has been added to a router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface being attached to the router
+     */
+    void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified interface can be detached from the specified router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface to be detached to the router
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the detach operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+    /**
+     * Services provide this interface method for taking action after an interface has been removed from a router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface being detached from the router
+     */
+    void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSecurityGroupAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSecurityGroupAware.java
new file mode 100644 (file)
index 0000000..85ff4e0
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Security Groups needs to implement
+ */
+
+public interface INeutronSecurityGroupAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified security group can be created
+     *
+     * @param securityGroup instance of proposed new Neutron Security Group object
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the create operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canCreateNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method for taking action after a security group has been created
+     *
+     * @param securityGroup instance of new Neutron Security Group object
+     */
+    void neutronSecurityGroupCreated(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method to indicate if the specified security group can be changed using the specified
+     * delta
+     *
+     * @param delta    updates to the security group object using patch semantics
+     * @param original instance of the Neutron Security Group object to be updated
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the update operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original);
+
+    /**
+     * Services provide this interface method for taking action after a security group has been updated
+     *
+     * @param securityGroup instance of modified Neutron Security Group object
+     */
+    void neutronSecurityGroupUpdated(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method to indicate if the specified security group can be deleted
+     *
+     * @param securityGroup instance of the Neutron Security Group object to be deleted
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the delete operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canDeleteNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method for taking action after a security group has been deleted
+     *
+     * @param securityGroup instance of deleted Neutron Security Group object
+     */
+    void neutronSecurityGroupDeleted(NeutronSecurityGroup securityGroup);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSecurityRuleAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSecurityRuleAware.java
new file mode 100644 (file)
index 0000000..08608a6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+
+/**
+ * This interface defines the methods required to be aware of Neutron Security Rules
+ */
+
+public interface INeutronSecurityRuleAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified security rule can be created
+     *
+     * @param securityRule instance of proposed new Neutron Security Rule object
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the create operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method for taking action after a security rule has been created
+     *
+     * @param securityRule instance of new Neutron Security Rule object
+     */
+    void neutronSecurityRuleCreated(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified security rule can be changed using the specified
+     * delta
+     *
+     * @param delta    updates to the security rule object using patch semantics
+     * @param original instance of the Neutron Security Rule object to be updated
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the update operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original);
+
+    /**
+     * Services provide this interface method for taking action after a security rule has been updated
+     *
+     * @param securityRule instance of modified Neutron Security Rule object
+     */
+    void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified security rule can be deleted
+     *
+     * @param securityRule instance of the Neutron Security Rule object to be deleted
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the delete operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method for taking action after a security rule has been deleted
+     *
+     * @param securityRule instance of deleted Neutron Security Rule object
+     */
+    void neutronSecurityRuleDeleted(NeutronSecurityRule securityRule);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSubnetAware.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/INeutronSubnetAware.java
new file mode 100644 (file)
index 0000000..9fddaf8
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Subnets needs to implement
+ *
+ */
+
+public interface INeutronSubnetAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified subnet can be created
+     *
+     * @param subnet
+     *            instance of proposed new Neutron Subnet object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateSubnet(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method for taking action after a subnet has been created
+     *
+     * @param subnet
+     *            instance of new Neutron Subnet object
+     */
+    void neutronSubnetCreated(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method to indicate if the specified subnet can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the subnet object using patch semantics
+     * @param original
+     *            instance of the Neutron Subnet object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateSubnet(NeutronSubnet delta, NeutronSubnet original);
+
+    /**
+     * Services provide this interface method for taking action after a subnet has been updated
+     *
+     * @param subnet
+     *            instance of modified Neutron Subnet object
+     */
+    void neutronSubnetUpdated(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method to indicate if the specified subnet can be deleted
+     *
+     * @param subnet
+     *            instance of the Subnet Router object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteSubnet(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method for taking action after a subnet has been deleted
+     *
+     * @param subnet
+     *            instance of deleted Router Subnet object
+     */
+    void neutronSubnetDeleted(NeutronSubnet subnet);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronFloatingIPChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronFloatingIPChangeListener.java
new file mode 100644 (file)
index 0000000..cc1a14d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+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;
+
+public class NeutronFloatingIPChangeListener implements ClusteredDataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingIPChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronFloatingIPChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Floatingip> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Floatingips.class)
+                .child(Floatingip.class);
+        LOG.debug("Register listener for Neutron FloatingIp model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronFloatingIPAware.class, this);
+        createFloatingIP(changes, subscribers);
+        updateFloatingIP(changes, subscribers);
+        deleteFloatingIP(changes, subscribers);
+    }
+
+    private void createFloatingIP(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newFloatingIP : changes.getCreatedData().entrySet()) {
+               if(newFloatingIP.getValue() instanceof Floatingip){
+                NeutronFloatingIP floatingip= fromMd((Floatingip)newFloatingIP.getValue());
+                for(Object entry: subscribers){
+                    INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+                    subscriber.neutronFloatingIPCreated(floatingip);
+                }
+               }
+        }
+    }
+
+    private void updateFloatingIP(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateFloatingIP : changes.getUpdatedData().entrySet()) {
+               if(updateFloatingIP.getValue() instanceof Floatingip){
+                NeutronFloatingIP floatingip = fromMd((Floatingip)updateFloatingIP.getValue());
+                for(Object entry: subscribers){
+                    INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+                    subscriber.neutronFloatingIPUpdated(floatingip);
+                }
+               }
+        }
+    }
+
+    private void deleteFloatingIP(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedFloatingIPPath : changes.getRemovedPaths()) {
+               if(deletedFloatingIPPath.getTargetType().equals(Floatingip.class)){
+                NeutronFloatingIP floatingip = fromMd((Floatingip)changes.getOriginalData().get(deletedFloatingIPPath));
+                for(Object entry: subscribers){
+                    INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+                    subscriber.neutronFloatingIPDeleted(floatingip);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronFloatingIPInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronFloatingIP fromMd(Floatingip fip) {
+        NeutronFloatingIP result = new NeutronFloatingIP();
+        result.setID(String.valueOf(fip.getUuid().getValue()));
+        if (fip.getFloatingNetworkId() != null) {
+            result.setFloatingNetworkUUID(String.valueOf(fip.getFloatingNetworkId().getValue()));
+        }
+        if (fip.getPortId() != null) {
+            result.setPortUUID(String.valueOf(fip.getPortId().getValue()));
+        }
+        if (fip.getFixedIpAddress() != null ) {
+            result.setFixedIPAddress(String.valueOf(fip.getFixedIpAddress().getValue()));
+        }
+        if (fip.getFloatingIpAddress() != null) {
+            result.setFloatingIPAddress(String.valueOf(fip.getFloatingIpAddress().getValue()));
+        }
+        if (fip.getTenantId() != null) {
+            result.setTenantUUID(String.valueOf(fip.getTenantId().getValue()));
+        }
+        if (fip.getRouterId() != null) {
+            result.setRouterUUID(String.valueOf(fip.getRouterId().getValue()));
+        }
+        result.setStatus(fip.getStatus());
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java
new file mode 100644 (file)
index 0000000..2a09f6b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronIAwareUtil {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronIAwareUtil.class);
+
+    private NeutronIAwareUtil() {
+    }
+
+    public static Object[] getInstances(Class<?> clazz,Object bundle) {
+        Object instances[] = null;
+        try {
+            BundleContext bCtx = FrameworkUtil.getBundle(bundle.getClass())
+                    .getBundleContext();
+
+            ServiceReference<?>[] services = null;
+                services = bCtx.getServiceReferences(clazz.getName(),
+                        null);
+            if (services != null) {
+                instances = new Object[services.length];
+                for (int i = 0; i < services.length; i++) {
+                    instances[i] = bCtx.getService(services[i]);
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.error("Instance reference is NULL", e);
+        }
+        return instances;
+    }
+
+    public static List<Neutron_IPs> convertMDSalIpToNeutronIp(List<FixedIps> fixedIps) {
+        List<Neutron_IPs> ips = null;
+        if (fixedIps != null) {
+            ips = new ArrayList<Neutron_IPs>();
+            for (FixedIps mdIP : fixedIps) {
+                Neutron_IPs ip = new Neutron_IPs();
+                ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+                ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+                ips.add(ip);
+            }
+        }
+        return ips;
+    }
+
+    public static NeutronRouter_Interface convertMDSalInterfaceToNeutronRouterInterface(
+            Port routerInterface) {
+        NeutronRouter_Interface neutronInterface = new NeutronRouter_Interface();
+        String id = String.valueOf(routerInterface.getUuid().getValue());
+        neutronInterface.setID(id);
+        if (routerInterface.getTenantId() != null) {
+            neutronInterface.setTenantID(routerInterface.getTenantId().getValue());
+        }
+        neutronInterface.setSubnetUUID(routerInterface.getFixedIps().get(0).getSubnetId().getValue());
+        neutronInterface.setPortUUID(routerInterface.getUuid().getValue());
+        return neutronInterface;
+    }
+
+
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolChangeListener.java
new file mode 100644 (file)
index 0000000..98df6b7
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_ID;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer_SessionPersistence;
+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.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.members.Member;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+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;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronLoadBalancerPoolChangeListener implements ClusteredDataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronLoadBalancerPoolChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+            = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+            .put(ProtocolHttp.class, "HTTP")
+            .put(ProtocolHttps.class, "HTTPS")
+            .put(ProtocolIcmp.class, "ICMP")
+            .put(ProtocolTcp.class,"TCP")
+            .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronLoadBalancerPoolChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Pool> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Pools.class)
+                .child(Pool.class);
+        LOG.debug("Register listener for Neutron Load Balancer Pool model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, AsyncDataBroker.DataChangeScope.ONE);
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronLoadBalancerPoolAware.class, this);
+        createPool(changes, subscribers);
+        updatePool(changes, subscribers);
+        deletePool(changes, subscribers);
+    }
+
+    private void createPool(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newPool : changes.getCreatedData().entrySet()) {
+               if(newPool.getValue() instanceof Pool){
+                NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool) newPool.getValue());
+                for (Object entry : subscribers) {
+                    INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+                    subscriber.neutronLoadBalancerPoolCreated(loadBalancerPool);
+                }
+               }
+        }
+    }
+    private void updatePool(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updatePool : changes.getUpdatedData().entrySet()) {
+               if(updatePool.getValue() instanceof Pool){
+                NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool)updatePool.getValue());
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+                    subscriber.neutronLoadBalancerPoolUpdated(loadBalancerPool);
+                }
+               }
+        }
+    }
+    private void deletePool(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedPoolPath : changes.getRemovedPaths()) {
+               if(deletedPoolPath.getTargetType().equals(Pool.class)){
+                NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool)changes.getOriginalData().get(deletedPoolPath));
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+                    subscriber.neutronLoadBalancerPoolDeleted(loadBalancerPool);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronLoadBalancerPool.java class of Neutron Northbound class.
+     * in the original location, this method is called extractFields.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronLoadBalancerPool fromMd(Pool pool) {
+        NeutronLoadBalancerPool result = new NeutronLoadBalancerPool();
+
+        result.setID(pool.getUuid().getValue());
+        if (pool.getTenantId() != null) {
+            result.setLoadBalancerPoolTenantID(pool.getTenantId().getValue());
+        }
+        if (pool.getName() != null) {
+            result.setLoadBalancerPoolName(pool.getName());
+        }
+        if (pool.getDescr() != null) {
+            result.setLoadBalancerPoolDescription(pool.getDescr());
+        }
+        if (pool.getProtocol() != null) {
+            result.setLoadBalancerPoolProtocol(PROTOCOL_MAP.get(pool.getProtocol()));
+        }
+        if (pool.getLbAlgorithm() != null) {
+            result.setLoadBalancerPoolLbAlgorithm(pool.getLbAlgorithm());
+        }
+
+        // TODO: setNeutronLoadBalancerPoolHealthMonitorID is a list? Fill in, when its needed.
+        if (pool.getHealthmonitorId() != null) {
+               result.setNeutronLoadBalancerPoolHealthMonitorID(pool.getHealthmonitorId().getValue());
+        }
+
+        if (pool.isAdminStateUp() != null) {
+            result.setLoadBalancerPoolAdminStateIsUp(pool.isAdminStateUp());
+        }
+
+        List<Neutron_ID> listeners = new ArrayList();
+        if (pool.getListeners() != null) {
+            for (Uuid listenerUuid : pool.getListeners()) {
+                listeners.add(new Neutron_ID(listenerUuid.getValue()));
+            }
+        }
+        result.setLoadBalancerPoolListeners(listeners);
+
+        if (pool.getSessionPersistence() != null) {
+            NeutronLoadBalancer_SessionPersistence sessionPersistence = new NeutronLoadBalancer_SessionPersistence();
+            sessionPersistence.setCookieName(pool.getSessionPersistence().getCookieName());
+            sessionPersistence.setType(pool.getSessionPersistence().getType());
+            result.setLoadBalancerSessionPersistence(sessionPersistence);
+        }
+
+        List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers = new ArrayList();
+        if (pool.getMembers() != null) {
+            for (Member member : pool.getMembers().getMember()) {
+                NeutronLoadBalancerPoolMember neutronMember = new NeutronLoadBalancerPoolMember();
+
+                neutronMember.setPoolID(pool.getUuid().getValue());
+                neutronMember.setPoolMemberID(member.getUuid().getValue());
+
+                // TODO: locate and populate remainder attributes, when its needed
+                // member.setPoolMemberAddress(xxx);
+                // member.setPoolMemberAdminStateIsUp(xxx);
+                // member.setPoolMemberProtoPort(xxx);
+                // member.setPoolMemberSubnetID(xxx);
+                // member.setPoolMemberTenantID(xxx);
+                // member.setPoolMemberWeight(xxx);
+
+                loadBalancerPoolMembers.add(neutronMember);
+            }
+        }
+        result.setLoadBalancerPoolMembers(loadBalancerPoolMembers);
+
+        return result;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolMemberChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolMemberChangeListener.java
new file mode 100644 (file)
index 0000000..8963989
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.PoolKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.Members;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.members.Member;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+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;
+
+public class NeutronLoadBalancerPoolMemberChangeListener implements ClusteredDataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronLoadBalancerPoolMemberChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronLoadBalancerPoolMemberChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Member> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Pools.class)
+                .child(Pool.class)
+                .child(Members.class)
+                .child(Member.class);
+        LOG.debug("Register listener for Neutron Load Balancer Pool Member model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this,
+                        AsyncDataBroker.DataChangeScope.ONE);
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronLoadBalancerPoolMemberAware.class, this);
+        createPoolMember(changes, subscribers);
+        updatePoolMember(changes, subscribers);
+        deletePoolMember(changes, subscribers);
+    }
+
+    private void createPoolMember(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newPoolMember : changes.getCreatedData().entrySet()) {
+               if(newPoolMember.getValue() instanceof Member){
+                NeutronLoadBalancerPoolMember neutronLBPoolMember = fromMd(newPoolMember.getKey(), (Member) newPoolMember.getValue());
+                for (Object entry : subscribers) {
+                    INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+                    subscriber.neutronLoadBalancerPoolMemberCreated(neutronLBPoolMember);
+                }
+               }
+        }
+    }
+    private void updatePoolMember(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updatePoolMember : changes.getUpdatedData().entrySet()) {
+               if(updatePoolMember.getValue() instanceof Member){
+                NeutronLoadBalancerPoolMember neutronLBPoolMember =
+                        fromMd(updatePoolMember.getKey(), (Member) updatePoolMember.getValue());
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+                    subscriber.neutronLoadBalancerPoolMemberUpdated(neutronLBPoolMember);
+                }
+               }
+        }
+    }
+    private void deletePoolMember(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedPoolMemberPath : changes.getRemovedPaths()) {
+               if(deletedPoolMemberPath.getTargetType().equals(Member.class)){
+                NeutronLoadBalancerPoolMember neutronLBPoolMember =
+                        fromMd(deletedPoolMemberPath, (Member) changes.getOriginalData().get(deletedPoolMemberPath));
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+                    subscriber.neutronLoadBalancerPoolMemberDeleted(neutronLBPoolMember);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronLoadBalancerPoolMember.java class of Neutron Northbound class.
+     * in the original location, this method is called extractFields.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronLoadBalancerPoolMember fromMd(InstanceIdentifier<?> iid, Member member) {
+        NeutronLoadBalancerPoolMember result = new NeutronLoadBalancerPoolMember();
+
+        final PoolKey poolsKey = iid.firstKeyOf(Pool.class, PoolKey.class);
+        if (poolsKey != null) {
+            result.setPoolID(poolsKey.getUuid().getValue());
+        }
+
+        result.setID(member.getUuid().getValue());
+        if (member.isAdminStateUp() != null) {
+            result.setPoolMemberAdminStateIsUp(member.isAdminStateUp());
+        }
+
+        final IpAddress memberIpAddress = member.getAddress();
+        if (memberIpAddress != null) {
+            if (memberIpAddress.getIpv4Address() != null) {
+                result.setPoolMemberAddress(memberIpAddress.getIpv4Address().getValue());
+            } else if (memberIpAddress.getIpv6Address() != null) {
+                result.setPoolMemberAddress(memberIpAddress.getIpv6Address().getValue());
+            }
+        }
+
+        if (member.getProtocolPort() != null) {
+            result.setPoolMemberProtoPort(member.getProtocolPort());
+        }
+        if (member.getSubnetId() != null) {
+            result.setPoolMemberSubnetID(member.getSubnetId().getValue());
+        }
+        if (member.getTenantId() != null) {
+            result.setPoolMemberTenantID(member.getTenantId().getValue());
+        }
+        if (member.getWeight() != null) {
+            result.setPoolMemberWeight(member.getWeight());
+        }
+
+        return result;
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronNetworkChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..d3897c4
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork_Segment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+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;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronNetworkChangeListener implements ClusteredDataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends NetworkTypeBase>,String> NETWORK_MAP
+    = new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>,String>()
+    .put(NetworkTypeFlat.class,"flat")
+    .put(NetworkTypeGre.class,"gre")
+    .put(NetworkTypeVlan.class,"vlan")
+    .put(NetworkTypeVxlan.class,"vxlan")
+    .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronNetworkChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Network> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Networks.class)
+                .child(Network.class);
+        LOG.debug("Register listener for Neutron Network model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronNetworkAware.class, this);
+        createNetwork(changes, subscribers);
+        updateNetwork(changes, subscribers);
+        deleteNetwork(changes, subscribers);
+    }
+
+    private void createNetwork(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newNetwork : changes.getCreatedData().entrySet()) {
+               if(newNetwork.getValue() instanceof Network){
+                NeutronNetwork network = fromMd((Network)newNetwork.getValue());
+                for(Object entry: subscribers){
+                    INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+                    subscriber.neutronNetworkCreated(network);
+                }
+               }
+        }
+    }
+
+    private void updateNetwork(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateNetwork : changes.getUpdatedData().entrySet()) {
+               if(updateNetwork.getValue() instanceof Network){
+                NeutronNetwork network = fromMd((Network)updateNetwork.getValue());
+                for(Object entry: subscribers){
+                    INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+                    subscriber.neutronNetworkUpdated(network);
+                }
+               }
+        }
+    }
+
+    private void deleteNetwork(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedNetworkPath : changes.getRemovedPaths()) {
+               if(deletedNetworkPath.getTargetType().equals(Network.class)){
+                NeutronNetwork network = fromMd((Network)changes.getOriginalData().get(deletedNetworkPath));
+                for(Object entry: subscribers){
+                    INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+                    subscriber.neutronNetworkDeleted(network);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronNetworkInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronNetwork fromMd(Network network) {
+        NeutronNetwork result = new NeutronNetwork();
+        result.setAdminStateUp(network.isAdminStateUp());
+        result.setNetworkName(network.getName());
+        result.setShared(network.isShared());
+        result.setStatus(network.getStatus());
+
+        // todo remove '-' chars as tenant id doesn't use them
+        if (network.getTenantId() != null) {
+            result.setTenantID(network.getTenantId().getValue());
+        }
+        result.setID(network.getUuid().getValue());
+
+        NetworkL3Extension l3Extension = network.getAugmentation(NetworkL3Extension.class);
+        result.setRouterExternal(l3Extension.isExternal());
+
+        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        result.setProviderPhysicalNetwork(providerExtension.getPhysicalNetwork());
+        result.setProviderSegmentationID(providerExtension.getSegmentationId());
+        result.setProviderNetworkType(NETWORK_MAP.get(providerExtension.getNetworkType()));
+        List<NeutronNetwork_Segment> segments = new ArrayList<>();
+        if (providerExtension.getSegments() != null) {
+            for (Segments segment: providerExtension.getSegments()) {
+                NeutronNetwork_Segment neutronSegment = new NeutronNetwork_Segment();
+                neutronSegment.setProviderPhysicalNetwork(segment.getPhysicalNetwork());
+                neutronSegment.setProviderSegmentationID(segment.getSegmentationId());
+                neutronSegment.setProviderNetworkType(NETWORK_MAP.get(segment.getNetworkType()));
+                segments.add(neutronSegment);
+            }
+        }
+        result.setSegments(segments);
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java
new file mode 100644 (file)
index 0000000..ea9b98f
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort_VIFDetail;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronPortAware;
+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.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+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.rev150712.Neutron;
+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;
+
+public class NeutronPortChangeListener implements ClusteredDataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronPortChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Port> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Ports.class)
+                .child(Port.class);
+        LOG.debug("Register listener for Neutron Port model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronPortAware.class, this);
+        createPort(changes, subscribers);
+        updatePort(changes, subscribers);
+        deletePort(changes, subscribers);
+    }
+
+    private void createPort(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newPort : changes.getCreatedData().entrySet()) {
+               if(newPort.getValue() instanceof Port){
+                NeutronPort port = fromMd((Port)newPort.getValue());
+                for(Object entry: subscribers){
+                    INeutronPortAware subscriber = (INeutronPortAware)entry;
+                    subscriber.neutronPortCreated(port);
+                }
+               }
+        }
+    }
+
+    private void updatePort(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        Map<String, NeutronPort> originalPortMap = getChangedPorts(changes.getOriginalData());
+        for (Entry<InstanceIdentifier<?>, DataObject> updatePort : changes.getUpdatedData().entrySet()) {
+            if (updatePort.getValue() instanceof Port) {
+                NeutronPort port = fromMd((Port)updatePort.getValue());
+                NeutronPort originalPort = originalPortMap.get(port.getID());
+                if (originalPort != null) {
+                    port.setOriginalPort(originalPort);
+                } else {
+                    LOG.warn("Original Port data is missing");
+                }
+                for (Object entry: subscribers) {
+                    INeutronPortAware subscriber = (INeutronPortAware)entry;
+                    subscriber.neutronPortUpdated(port);
+                }
+            }
+        }
+    }
+
+    private void deletePort(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedPortPath : changes.getRemovedPaths()) {
+            if(deletedPortPath.getTargetType().equals(Port.class)){
+                NeutronPort port = fromMd((Port)changes.getOriginalData().get(deletedPortPath));
+                for(Object entry: subscribers){
+                    INeutronPortAware subscriber = (INeutronPortAware)entry;
+                    subscriber.neutronPortDeleted(port);
+                }
+            }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronPortInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronPort fromMd(Port port) {
+
+        NeutronPort result = new NeutronPort();
+        result.setAdminStateUp(port.isAdminStateUp());
+        if (port.getAllowedAddressPairs() != null) {
+            List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<>();
+            for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
+                NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
+                pair.setIpAddress(mdPair.getIpAddress());
+                pair.setMacAddress(mdPair.getMacAddress());
+                pairs.add(pair);
+            }
+            result.setAllowedAddressPairs(pairs);
+        }
+        result.setDeviceID(port.getDeviceId());
+        result.setDeviceOwner(port.getDeviceOwner());
+        if (port.getExtraDhcpOpts() != null) {
+            List<NeutronPort_ExtraDHCPOption> options = new ArrayList<>();
+            for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
+                NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
+                arg.setName(opt.getOptName());
+                arg.setValue(opt.getOptValue());
+                options.add(arg);
+            }
+            result.setExtraDHCPOptions(options);
+        }
+        if (port.getFixedIps() != null) {
+            List<Neutron_IPs> ips = new ArrayList<>();
+            for (FixedIps mdIP : port.getFixedIps()) {
+                Neutron_IPs ip = new Neutron_IPs();
+                ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+                ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+                ips.add(ip);
+            }
+            result.setFixedIPs(ips);
+        }
+        result.setMacAddress(port.getMacAddress());
+        result.setName(port.getName());
+        result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
+        if (port.getSecurityGroups() != null) {
+            Set<NeutronSecurityGroup> allGroups = new HashSet<>();
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
+            INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
+            for (Uuid sgUuid : port.getSecurityGroups()) {
+                NeutronSecurityGroup secGroup = sgIf.getNeutronSecurityGroup(sgUuid.getValue());
+                if (secGroup != null) {
+                    allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+                }
+            }
+            List<NeutronSecurityGroup> groups = new ArrayList<>();
+            groups.addAll(allGroups);
+            result.setSecurityGroups(groups);
+        }
+        result.setStatus(port.getStatus());
+        if (port.getTenantId() != null) {
+            result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
+        }
+        result.setPortUUID(String.valueOf(port.getUuid().getValue()));
+        addExtensions(port, result);
+        return result;
+    }
+
+    protected void addExtensions(Port port, NeutronPort result) {
+        PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
+        result.setBindinghostID(binding.getHostId());
+        if (binding.getVifDetails() != null) {
+            List<NeutronPort_VIFDetail> details = new ArrayList<>();
+            for (VifDetails vifDetail : binding.getVifDetails()) {
+                NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
+                detail.setPortFilter(vifDetail.isPortFilter());
+                detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
+                details.add(detail);
+            }
+            result.setVIFDetail(details);
+        }
+        result.setBindingvifType(binding.getVifType());
+        result.setBindingvnicType(binding.getVnicType());
+    }
+
+    private  Map<String,NeutronPort> getChangedPorts(Map<InstanceIdentifier<?>, DataObject> changedData) {
+        LOG.trace("getChangedPorts:" + changedData);
+        Map<String,NeutronPort> portMap = new HashMap<>();
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> changed : changedData.entrySet()) {
+            if (changed.getValue() instanceof Port) {
+                NeutronPort port = fromMd((Port)changed.getValue());
+                portMap.put(port.getID(), port);
+            }
+        }
+        return portMap;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronRouterChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronRouterChangeListener.java
new file mode 100644 (file)
index 0000000..911a203
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_NetworkReference;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+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;
+
+public class NeutronRouterChangeListener implements ClusteredDataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronRouterChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Router> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Routers.class)
+                .child(Router.class);
+        LOG.debug("Register listener for Neutron Router model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronRouterAware.class, this);
+        createRouter(changes, subscribers);
+        updateRouter(changes, subscribers);
+        deleteRouter(changes, subscribers);
+    }
+
+    private void createRouter(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newRouter : changes.getCreatedData().entrySet()) {
+               if(newRouter.getValue() instanceof Router){
+                NeutronRouter router = fromMd((Router)newRouter.getValue());
+                for(Object entry: subscribers){
+                    INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+                    subscriber.neutronRouterCreated(router);
+                }
+               }
+        }
+
+    }
+
+    private void updateRouter(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateRouter : changes.getUpdatedData().entrySet()) {
+               if(updateRouter.getValue() instanceof Router){
+                NeutronRouter router = fromMd((Router)updateRouter.getValue());
+                for(Object entry: subscribers){
+                    INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+                    subscriber.neutronRouterUpdated(router);
+                }
+               }
+        }
+    }
+
+    private void deleteRouter(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedRouterPath : changes.getRemovedPaths()) {
+               if(deletedRouterPath.getTargetType().equals(Router.class)){
+                NeutronRouter router = fromMd((Router)changes.getOriginalData().get(deletedRouterPath));
+                for(Object entry: subscribers){
+                    INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+                    subscriber.neutronRouterDeleted(router);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronRouterInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronRouter fromMd(Router router) {
+        NeutronRouter result = new NeutronRouter();
+        result.setID(String.valueOf(router.getUuid().getValue()));
+        result.setName(router.getName());
+        if (router.getTenantId() != null) {
+            result.setTenantID(String.valueOf(router.getTenantId().getValue()));
+        }
+        result.setAdminStateUp(router.isAdminStateUp());
+        result.setStatus(router.getStatus());
+        result.setDistributed(router.isDistributed());
+        if (router.getGatewayPortId() != null) {
+            result.setGatewayPortId(String.valueOf(router.getGatewayPortId().getValue()));
+        }
+        if (router.getRoutes() != null) {
+            List<Routes> routes = new ArrayList<>();
+            for (Routes route : router.getRoutes()) {
+                routes.add(route);
+            }
+            result.setRoutes(routes);
+        }
+
+        if (router.getExternalGatewayInfo() != null) {
+            NeutronRouter_NetworkReference extGwInfo = new NeutronRouter_NetworkReference();
+            extGwInfo.setNetworkID(String.valueOf(router.getExternalGatewayInfo().getExternalNetworkId().getValue()));
+            extGwInfo.setEnableSNAT(router.getExternalGatewayInfo().isEnableSnat());
+            if (router.getExternalGatewayInfo().getExternalFixedIps() != null) {
+                List<Neutron_IPs> fixedIPs = new ArrayList<>();
+                for (ExternalFixedIps mdFixedIP : router.getExternalGatewayInfo().getExternalFixedIps()) {
+                     Neutron_IPs fixedIP = new Neutron_IPs();
+                     fixedIP.setSubnetUUID(String.valueOf(mdFixedIP.getSubnetId().getValue()));
+                     fixedIP.setIpAddress(String.valueOf(mdFixedIP.getIpAddress().getValue()));
+                     fixedIPs.add(fixedIP);
+                }
+                extGwInfo.setExternalFixedIPs(fixedIPs);
+            }
+            result.setExternalGatewayInfo(extGwInfo);
+        }
+
+        if (router.getInterfaces() != null) {
+            Map<String, NeutronRouter_Interface> interfaces = new HashMap<>();
+            for (Interfaces mdInterface : router.getInterfaces()) {
+                NeutronRouter_Interface pojoInterface = new NeutronRouter_Interface();
+                String id = String.valueOf(mdInterface.getUuid().getValue());
+                pojoInterface.setID(id);
+                if (mdInterface.getTenantId() != null) {
+                     pojoInterface.setTenantID(String.valueOf(mdInterface.getTenantId().getValue()));
+                }
+                pojoInterface.setSubnetUUID(String.valueOf(mdInterface.getSubnetId().getValue()));
+                pojoInterface.setPortUUID(String.valueOf(mdInterface.getPortId().getValue()));
+                interfaces.put(id, pojoInterface);
+            }
+            result.setInterfaces(interfaces);
+        }
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSecurityGroupDataChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSecurityGroupDataChangeListener.java
new file mode 100644 (file)
index 0000000..e21d0d9
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+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.secgroups.rev150712.security.groups.attributes.SecurityGroups;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
+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;
+
+public class NeutronSecurityGroupDataChangeListener implements ClusteredDataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory
+            .getLogger(NeutronSecurityGroupDataChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronSecurityGroupDataChangeListener(DataBroker db) {
+        this.db = db;
+        InstanceIdentifier<SecurityGroup> path = InstanceIdentifier
+                .create(Neutron.class).child(SecurityGroups.class)
+                .child(SecurityGroup.class);
+        LOG.debug("Register listener for Neutron Secutiry group model data changes");
+        registration = this.db.registerDataChangeListener(
+                LogicalDatastoreType.CONFIGURATION, path, this,
+                DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(
+                INeutronSecurityGroupAware.class, this);
+        createSecurityGroup(changes, subscribers);
+        updateSecurityGroup(changes, subscribers);
+        deleteSecurityGroup(changes, subscribers);
+    }
+
+    private void createSecurityGroup(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newSecutiryGroup : changes
+                .getCreatedData().entrySet()) {
+            if (newSecutiryGroup.getValue() instanceof SecurityGroup) {
+                NeutronSecurityGroup secutiryGroup = fromMd((SecurityGroup) newSecutiryGroup
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+                    subscriber.neutronSecurityGroupCreated(secutiryGroup);
+                }
+            }
+        }
+
+    }
+
+    private void updateSecurityGroup(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateSecurityGroup : changes
+                .getUpdatedData().entrySet()) {
+            if (updateSecurityGroup.getValue() instanceof SecurityGroup) {
+                NeutronSecurityGroup securityGroup = fromMd((SecurityGroup) updateSecurityGroup
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+                    subscriber.neutronSecurityGroupUpdated(securityGroup);
+                }
+            }
+        }
+    }
+
+    private void deleteSecurityGroup(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedSecurityGroup : changes
+                .getRemovedPaths()) {
+            if (deletedSecurityGroup.getTargetType()
+                    .equals(SecurityGroup.class)) {
+                NeutronSecurityGroup securityGroup = fromMd((SecurityGroup) changes
+                        .getOriginalData().get(deletedSecurityGroup));
+                for (Object entry : subscribers) {
+                    INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+                    subscriber.neutronSecurityGroupDeleted(securityGroup);
+                }
+            }
+        }
+    }
+
+    private NeutronSecurityGroup fromMd(SecurityGroup group) {
+        NeutronSecurityGroup answer = new NeutronSecurityGroup();
+        if (group.getName() != null) {
+            answer.setSecurityGroupName(group.getName());
+        }
+        if (group.getDescription() != null) {
+            answer.setSecurityGroupDescription(group.getDescription());
+        }
+        if (group.getTenantId() != null) {
+            answer.setSecurityGroupTenantID(group.getTenantId().getValue()
+                    .replace("-", ""));
+        }
+        if (group.getSecurityRules() != null) {
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+                    .fetchINeutronSecurityRuleCRUD(this);
+            INeutronSecurityRuleCRUD srCrud = interfaces
+                    .getSecurityRuleInterface();
+
+            List<NeutronSecurityRule> rules = new ArrayList<>();
+            for (Uuid uuid : group.getSecurityRules()) {
+                rules.add(srCrud.getNeutronSecurityRule(uuid.getValue()));
+            }
+            answer.setSecurityRules(rules);
+        }
+        if (group.getUuid() != null) {
+            answer.setID(group.getUuid().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSecurityRuleDataChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSecurityRuleDataChangeListener.java
new file mode 100644 (file)
index 0000000..439dfe2
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
+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.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
+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.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
+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;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSecurityRuleDataChangeListener implements ClusteredDataChangeListener, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleDataChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends DirectionBase>, String> DIRECTION_MAP = ImmutableBiMap.of(
+            DirectionEgress.class, NeutronSecurityRule.DIRECTION_EGRESS,
+            DirectionIngress.class, NeutronSecurityRule.DIRECTION_INGRESS);
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>, String> PROTOCOL_MAP = ImmutableBiMap.of(
+            ProtocolIcmp.class, NeutronSecurityRule.PROTOCOL_ICMP,
+            ProtocolTcp.class, NeutronSecurityRule.PROTOCOL_TCP,
+            ProtocolUdp.class, NeutronSecurityRule.PROTOCOL_UDP,
+            ProtocolIcmpV6.class, NeutronSecurityRule.PROTOCOL_ICMPV6);
+    private static final ImmutableBiMap<Class<? extends EthertypeBase>,String> ETHERTYPE_MAP = ImmutableBiMap.of(
+            EthertypeV4.class, NeutronSecurityRule.ETHERTYPE_IPV4,
+            EthertypeV6.class, NeutronSecurityRule.ETHERTYPE_IPV6);
+
+    private ListenerRegistration<DataChangeListener> registration;
+
+    public NeutronSecurityRuleDataChangeListener(DataBroker db) {
+        InstanceIdentifier<SecurityRule> path = InstanceIdentifier
+                .create(Neutron.class).child(SecurityRules.class)
+                .child(SecurityRule.class);
+        LOG.debug("Register listener for Neutron Secutiry rules model data changes");
+        registration = db.registerDataChangeListener(
+                LogicalDatastoreType.CONFIGURATION, path, this,
+                DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(
+                INeutronSecurityRuleAware.class, this);
+        createSecurityRule(changes, subscribers);
+        updateSecurityRule(changes, subscribers);
+        deleteSecurityRule(changes, subscribers);
+    }
+
+    private void createSecurityRule(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newSecutiryRule : changes
+                .getCreatedData().entrySet()) {
+            if (newSecutiryRule.getValue() instanceof SecurityRule) {
+                NeutronSecurityRule secutiryRule = fromMd((SecurityRule) newSecutiryRule
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+                    subscriber.neutronSecurityRuleCreated(secutiryRule);
+                }
+            }
+        }
+
+    }
+
+    private void updateSecurityRule(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateSecurityRule : changes
+                .getUpdatedData().entrySet()) {
+            if (updateSecurityRule.getValue() instanceof SecurityRule) {
+                NeutronSecurityRule securityRule = fromMd((SecurityRule) updateSecurityRule
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+                    subscriber.neutronSecurityRuleUpdated(securityRule);
+                }
+            }
+        }
+    }
+
+    private void deleteSecurityRule(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedSecurityRule : changes
+                .getRemovedPaths()) {
+            if (deletedSecurityRule.getTargetType().equals(SecurityRule.class)) {
+                NeutronSecurityRule securityRule = fromMd((SecurityRule) changes
+                        .getOriginalData().get(deletedSecurityRule));
+                for (Object entry : subscribers) {
+                    INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+                    subscriber.neutronSecurityRuleDeleted(securityRule);
+                }
+            }
+        }
+    }
+
+    private NeutronSecurityRule fromMd(SecurityRule rule) {
+        NeutronSecurityRule answer = new NeutronSecurityRule();
+        if (rule.getTenantId() != null) {
+            answer.setSecurityRuleTenantID(rule.getTenantId().getValue()
+                    .replace("-", ""));
+        }
+        if (rule.getDirection() != null) {
+            answer.setSecurityRuleDirection(DIRECTION_MAP.get(rule
+                    .getDirection()));
+        }
+        if (rule.getSecurityGroupId() != null) {
+            answer.setSecurityRuleGroupID(rule.getSecurityGroupId().getValue());
+        }
+        if (rule.getRemoteGroupId() != null) {
+            answer.setSecurityRemoteGroupID(rule.getRemoteGroupId().getValue());
+        }
+        if (rule.getRemoteIpPrefix() != null) {
+            answer.setSecurityRuleRemoteIpPrefix(rule.getRemoteIpPrefix().getIpv4Prefix()!= null?
+                    rule.getRemoteIpPrefix().getIpv4Prefix().getValue():rule.getRemoteIpPrefix().getIpv6Prefix().getValue());
+        }
+        if (rule.getProtocol() != null) {
+            answer.setSecurityRuleProtocol(PROTOCOL_MAP.get(rule.getProtocol()));
+        }
+        if (rule.getEthertype() != null) {
+            answer.setSecurityRuleEthertype(ETHERTYPE_MAP.get(rule
+                    .getEthertype()));
+        }
+        if (rule.getPortRangeMin() != null) {
+            answer.setSecurityRulePortMin(rule.getPortRangeMin());
+        }
+        if (rule.getPortRangeMax() != null) {
+            answer.setSecurityRulePortMax(rule.getPortRangeMax());
+        }
+        if (rule.getId() != null) {
+            answer.setID(rule.getId().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSubnetChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/translator/iaware/impl/NeutronSubnetChangeListener.java
new file mode 100644 (file)
index 0000000..d13c214
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnetIPAllocationPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronSubnetAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Base;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Off;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Slaac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateless;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+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;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSubnetChangeListener implements ClusteredDataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronSubnetChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends IpVersionBase>,Integer> IPV_MAP
+    = new ImmutableBiMap.Builder<Class<? extends IpVersionBase>,Integer>()
+    .put(IpVersionV4.class, 4)
+    .put(IpVersionV6.class, 6)
+    .build();
+
+    private static final ImmutableBiMap<Class<? extends Dhcpv6Base>,String> DHCPV6_MAP
+    = new ImmutableBiMap.Builder<Class<? extends Dhcpv6Base>,String>()
+    .put(Dhcpv6Off.class,"off")
+    .put(Dhcpv6Stateful.class,"dhcpv6-stateful")
+    .put(Dhcpv6Slaac.class,"slaac")
+    .put(Dhcpv6Stateless.class,"dhcpv6-stateless")
+    .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronSubnetChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Subnet> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Subnets.class)
+                .child(Subnet.class);
+        LOG.debug("Register listener for Neutron Subnet model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronSubnetAware.class, this);
+        createSubnet(changes, subscribers);
+        updateSubnet(changes, subscribers);
+        deleteSubnet(changes, subscribers);
+    }
+
+    private void createSubnet(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newSubnet : changes.getCreatedData().entrySet()) {
+               if(newSubnet.getValue() instanceof Subnet){
+                NeutronSubnet subnet = fromMd((Subnet)newSubnet.getValue());
+                for(Object entry: subscribers){
+                    INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+                    subscriber.neutronSubnetCreated(subnet);
+                }
+               }
+        }
+    }
+
+    private void updateSubnet(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateSubnet : changes.getUpdatedData().entrySet()) {
+               if(updateSubnet.getValue() instanceof Subnet){
+                NeutronSubnet subnet = fromMd((Subnet)updateSubnet.getValue());
+                for(Object entry: subscribers){
+                    INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+                    subscriber.neutronSubnetUpdated(subnet);
+                }
+               }
+        }
+    }
+
+    private void deleteSubnet(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedSubnetPath : changes.getRemovedPaths()) {
+               if(deletedSubnetPath.getTargetType().equals(Subnet.class)){
+                NeutronSubnet subnet = fromMd((Subnet)changes.getOriginalData().get(deletedSubnetPath));
+                for(Object entry: subscribers){
+                    INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+                    subscriber.neutronSubnetDeleted(subnet);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronSubnetInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronSubnet fromMd(Subnet subnet) {
+        NeutronSubnet result = new NeutronSubnet();
+        result.setName(subnet.getName());
+        if (subnet.getTenantId() != null) {
+            result.setTenantID(String.valueOf(subnet.getTenantId().getValue()).replace("-",""));
+        }
+        result.setNetworkUUID(subnet.getNetworkId().getValue());
+        result.setIpVersion(IPV_MAP.get(subnet.getIpVersion()));
+        result.setCidr(subnet.getCidr());
+        if (subnet.getGatewayIp() != null) {
+            result.setGatewayIP(String.valueOf(subnet.getGatewayIp().getValue()));
+        }
+        if (subnet.getIpv6RaMode() != null) {
+            result.setIpV6RaMode(DHCPV6_MAP.get(subnet.getIpv6RaMode()));
+        }
+        if (subnet.getIpv6AddressMode() != null) {
+            result.setIpV6AddressMode(DHCPV6_MAP.get(subnet.getIpv6AddressMode()));
+        }
+        result.setEnableDHCP(subnet.isEnableDhcp());
+        if (subnet.getAllocationPools() != null) {
+            List<NeutronSubnetIPAllocationPool> allocationPools = new ArrayList<>();
+            for (AllocationPools allocationPool : subnet.getAllocationPools()) {
+                NeutronSubnetIPAllocationPool pool = new NeutronSubnetIPAllocationPool();
+                pool.setPoolStart(allocationPool.getStart());
+                pool.setPoolEnd(allocationPool.getEnd());
+                allocationPools.add(pool);
+            }
+            result.setAllocationPools(allocationPools);
+        }
+        if (subnet.getDnsNameservers() != null) {
+            List<String> dnsNameServers = new ArrayList<>();
+            for (IpAddress dnsNameServer : subnet.getDnsNameservers()) {
+                dnsNameServers.add(String.valueOf(dnsNameServer.getValue()));
+            }
+            result.setDnsNameservers(dnsNameServers);
+        }
+        result.setID(subnet.getUuid().getValue());
+
+        // read through the ports and put the ones in this subnet into the internal
+        // myPorts object.
+       Set<NeutronPort> allPorts = new HashSet<>();
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronPortCRUD(this);
+        INeutronPortCRUD portIf = interfaces.getPortInterface();
+        for (NeutronPort port : portIf.getAllPorts()) {
+            if (port.getFixedIPs() != null) {
+                for (Neutron_IPs ip : port.getFixedIPs()) {
+                    if (ip.getSubnetUUID().equals(result.getID())) {
+                        allPorts.add(port);
+                    }
+                }
+            }
+        }
+        List<NeutronPort> ports = new ArrayList<>();
+        ports.addAll(allPorts);
+        result.setPorts(ports);
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModule.java b/openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModule.java
new file mode 100644 (file)
index 0000000..add390a
--- /dev/null
@@ -0,0 +1,35 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.impl.rev150513;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.netvirt.openstack.netvirt.NetvirtProvider;
+import org.osgi.framework.BundleContext;
+
+public class NetvirtImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.impl.rev150513.AbstractNetvirtImplModule {
+    private BundleContext bundleContext = null;
+
+    public NetvirtImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetvirtImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.impl.rev150513.NetvirtImplModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        NetvirtProvider provider = new NetvirtProvider(bundleContext, getClusteringEntityOwnershipServiceDependency());
+        provider.setConntrackEnabled(getConntrackEnabled());
+        BindingAwareBroker localBroker = getBrokerDependency();
+        localBroker.registerProvider(provider);
+        return provider;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModuleFactory.java b/openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModuleFactory.java
new file mode 100644 (file)
index 0000000..15bf334
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netvirt-impl yang module local name: netvirt-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Mon May 18 13:02:40 EDT 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.impl.rev150513;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.impl.rev150513.AbstractNetvirtImplModuleFactory {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtImplModuleFactory.class);
+
+    @Override
+    public Module createModule(String instanceName,
+                               DependencyResolver dependencyResolver,
+                               DynamicMBeanWithInstance old, BundleContext bundleContext)
+            throws Exception {
+        Module module =  super.createModule(instanceName, dependencyResolver, old, bundleContext);
+        setModuleBundleContext(bundleContext, module);
+        return module;
+    }
+
+    @Override
+    public Module createModule(String instanceName,
+                               DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        Module module = super.createModule(instanceName, dependencyResolver, bundleContext);
+        setModuleBundleContext(bundleContext, module);
+        return module;
+    }
+
+    private void setModuleBundleContext(BundleContext bundleContext,
+                                        Module module) {
+        if (module instanceof NetvirtImplModule) {
+            ((NetvirtImplModule)module).setBundleContext(bundleContext);
+        } else {
+            LOG.warn("Module is of type {} expected type {}",
+                    module.getClass(), NetvirtImplModule.class);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/yang/netvirt-impl.yang b/openstack/net-virt/src/main/yang/netvirt-impl.yang
new file mode 100644 (file)
index 0000000..2057257
--- /dev/null
@@ -0,0 +1,47 @@
+module netvirt-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:impl";
+    prefix "netvirt-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+    import opendaylight-entity-ownership-service {prefix eos; revision-date 2015-08-10;}
+
+    description
+        "Service definition for netvirt project";
+
+    revision "2015-05-13" {
+        description
+            "Initial revision";
+    }
+
+    identity netvirt-impl {
+        base config:module-type;
+        config:java-name-prefix netvirtImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netvirt-impl {
+            when "/config:modules/config:module/config:type = 'netvirt-impl'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+            container clustering-entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
+                }
+            }
+            leaf conntrack-enabled {
+                type boolean;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/AbstractEventTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/AbstractEventTest.java
new file mode 100644 (file)
index 0000000..46ddc95
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent.HandlerType;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+
+/**
+ * Unit test for {@link AbstractEvent}
+ */
+public class AbstractEventTest {
+
+    private AbstractEventChild1 abstractEvent1;
+    private AbstractEventChild2 abstractEvent2;
+    private AbstractEventChild2 abstractEvent3;
+
+    class AbstractEventChild1 extends AbstractEvent{
+        protected AbstractEventChild1(HandlerType handlerType, Action action) {
+            super(handlerType, action);
+        }
+
+    }
+
+    class AbstractEventChild2 extends AbstractEvent{
+        protected AbstractEventChild2(HandlerType handlerType, Action action) {
+            super(handlerType, action);
+        }
+    }
+
+
+    @Before
+    public void setUp(){
+         abstractEvent1 = new AbstractEventChild1(HandlerType.SOUTHBOUND, Action.DELETE);
+         abstractEvent2 = new AbstractEventChild2(HandlerType.NEUTRON_FLOATING_IP, Action.ADD);
+         abstractEvent3 = abstractEvent2;
+    }
+
+    @Test
+    public void testAbstractEvent(){
+        assertEquals("Error, getAction() did not return the correct value", Action.DELETE, abstractEvent1.getAction());
+
+        assertEquals("Error, getHandlerType() did not return the correct value", HandlerType.SOUTHBOUND, abstractEvent1.getHandlerType());
+
+        assertTrue("Error, equals() did not succeed", abstractEvent2.equals(abstractEvent3));
+
+        assertNotNull("Error, hashCode() did not return any value", abstractEvent1.hashCode());
+        assertEquals("Error, hashCode() is not consistent", abstractEvent2.hashCode(), abstractEvent3.hashCode());
+
+        int transactionId = abstractEvent1.getTransactionId();
+        assertEquals("Error, toString() did not return the correct value",
+                "AbstractEvent [transactionId=" + transactionId + " handlerType=SOUTHBOUND action=DELETE]", abstractEvent1.toString());
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/AbstractHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/AbstractHandlerTest.java
new file mode 100644 (file)
index 0000000..b3aea90
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.HttpURLConnection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+
+/**
+ * Unit test for {@link AbstractHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class AbstractHandlerTest {
+
+    @InjectMocks private AbstractHandler abstractHandler = mock(AbstractHandler.class, Mockito.CALLS_REAL_METHODS);
+    @Mock private EventDispatcher eventDispatcher;
+
+    @Test
+    public void testGetException() {
+        Status status = mock(Status.class);
+
+        when(status.getCode())
+                .thenReturn(StatusCode.BADREQUEST)
+                .thenReturn(StatusCode.CONFLICT)
+                .thenReturn(StatusCode.NOTACCEPTABLE)
+                .thenReturn(StatusCode.NOTFOUND)
+                .thenReturn(StatusCode.GONE);
+
+        assertEquals(
+                "Error, getException() did not return the correct neutron API service error",
+                HttpURLConnection.HTTP_BAD_REQUEST,
+                AbstractHandler.getException(status));
+        assertEquals(
+                "Error, getException() did not return the correct neutron API service error",
+                HttpURLConnection.HTTP_CONFLICT,
+                AbstractHandler.getException(status));
+        assertEquals(
+                "Error, getException() did not return the correct neutron API service error",
+                HttpURLConnection.HTTP_NOT_ACCEPTABLE,
+                AbstractHandler.getException(status));
+        assertEquals(
+                "Error, getException() did not return the correct neutron API service error",
+                HttpURLConnection.HTTP_NOT_FOUND,
+                AbstractHandler.getException(status));
+        assertEquals(
+                "Error, getException() did not return the correct neutron API service error",
+                HttpURLConnection.HTTP_INTERNAL_ERROR,
+                AbstractHandler.getException(status));
+    }
+
+    @Test
+    public void testEnqueueEvent() throws Exception {
+        abstractHandler.enqueueEvent(mock(AbstractEvent.class));
+        verify(eventDispatcher, times(1)).enqueueEvent(any(AbstractEvent.class));
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/FWaasHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/FWaasHandlerTest.java
new file mode 100644 (file)
index 0000000..7464ac9
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import java.net.HttpURLConnection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+
+
+/**
+ * Unit test for {@link FWaasHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class FWaasHandlerTest {
+
+    @InjectMocks FWaasHandler fwaasHandler;
+
+    @Before
+    public void setUp() {
+        fwaasHandler = mock(FWaasHandler.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @Test
+    public void testCanCreateNeutronFirewall(){
+        assertEquals("Error, canCreateNeutronFirewall() did not return the correct value ", HttpURLConnection.HTTP_CREATED, fwaasHandler.canCreateNeutronFirewall(any(NeutronFirewall.class)));
+    }
+
+    @Test
+    public void testNeutronFirewallCreated(){
+        verifyNoMoreInteractions(fwaasHandler);
+        fwaasHandler.canCreateNeutronFirewall(mock(NeutronFirewall.class));
+        verify(fwaasHandler, times(1)).canCreateNeutronFirewall(any(NeutronFirewall.class));
+    }
+
+    @Test
+    public void testCanUpdateNeutronFirewall(){
+        assertEquals("Error, canUpdateNeutronFirewall() did not return the correct value ", HttpURLConnection.HTTP_OK, fwaasHandler.canUpdateNeutronFirewall(any(NeutronFirewall.class), any(NeutronFirewall.class)));
+    }
+
+    @Test
+    public void testCanDeleteNeutronFirewall(){
+        assertEquals("Error, canDeleteNeutronFirewall() did not return the correct value ", HttpURLConnection.HTTP_OK, fwaasHandler.canDeleteNeutronFirewall(any(NeutronFirewall.class)));
+    }
+
+    @Test
+    public void testNeutronFirewallDeleted(){
+        verifyNoMoreInteractions(fwaasHandler);
+        fwaasHandler.neutronFirewallDeleted(mock(NeutronFirewall.class));
+        verify(fwaasHandler, times(1)).canDeleteNeutronFirewall(any(NeutronFirewall.class));
+    }
+
+    @Test
+    public void testCanCreateNeutronFirewallRule(){
+        assertEquals("Error, canCreateNeutronFirewallRule() did not return the correct value ", HttpURLConnection.HTTP_CREATED, fwaasHandler.canCreateNeutronFirewallRule(any(NeutronFirewallRule.class)));
+    }
+
+    @Test
+    public void testNeutronFirewallRuleCreated(){
+        verifyNoMoreInteractions(fwaasHandler);
+        fwaasHandler.neutronFirewallRuleCreated(mock(NeutronFirewallRule.class));
+        verify(fwaasHandler, times(1)).canCreateNeutronFirewallRule(any(NeutronFirewallRule.class));
+    }
+
+    @Test
+    public void testCanUpdateNeutronFirewallRule(){
+        assertEquals("Error, canUpdateNeutronFirewallRule() did not return the correct value ", HttpURLConnection.HTTP_OK, fwaasHandler.canUpdateNeutronFirewallRule(any(NeutronFirewallRule.class), any(NeutronFirewallRule.class)));
+    }
+
+    @Test
+    public void testCanDeleteNeutronFirewallRule(){
+        assertEquals("Error, canDeleteNeutronFirewallRule() did not return the correct value ", HttpURLConnection.HTTP_OK, fwaasHandler.canDeleteNeutronFirewallRule(any(NeutronFirewallRule.class)));
+    }
+
+    @Test
+    public void testNeutronFirewallRuleDeleted(){
+        verifyNoMoreInteractions(fwaasHandler);
+        fwaasHandler.neutronFirewallRuleDeleted(mock(NeutronFirewallRule.class));
+        verify(fwaasHandler, times(1)).canDeleteNeutronFirewallRule(any(NeutronFirewallRule.class));
+    }
+
+    @Test
+    public void testCanCreateNeutronFirewallPolicy(){
+        assertEquals("Error, canCreateNeutronFirewallPolicy() did not return the correct value ", HttpURLConnection.HTTP_CREATED, fwaasHandler.canCreateNeutronFirewallPolicy(any(NeutronFirewallPolicy.class)));
+    }
+
+    @Test
+    public void testNeutronFirewallPolicyCreated(){
+        verifyNoMoreInteractions(fwaasHandler);
+        fwaasHandler.neutronFirewallPolicyCreated(mock(NeutronFirewallPolicy.class));
+        verify(fwaasHandler, times(1)).canCreateNeutronFirewallPolicy(any(NeutronFirewallPolicy.class));
+    }
+
+    @Test
+    public void testCanUpdateNeutronFirewallPolicy(){
+        assertEquals("Error, canUpdateNeutronFirewallPolicy() did not return the correct value ", HttpURLConnection.HTTP_OK, fwaasHandler.canUpdateNeutronFirewallPolicy(any(NeutronFirewallPolicy.class), any(NeutronFirewallPolicy.class)));
+    }
+
+    @Test
+    public void testCanDeleteNeutronFirewallPolicy(){
+        assertEquals("Error, canDeleteNeutronFirewallPolicy() did not return the correct value ", HttpURLConnection.HTTP_OK, fwaasHandler.canDeleteNeutronFirewallPolicy(any(NeutronFirewallPolicy.class)));
+    }
+
+    @Test
+    public void testNeutronFirewallPolicyDeleted(){
+        verifyNoMoreInteractions(fwaasHandler);
+        fwaasHandler.neutronFirewallPolicyDeleted(mock(NeutronFirewallPolicy.class));
+        verify(fwaasHandler, times(1)).canDeleteNeutronFirewallPolicy(any(NeutronFirewallPolicy.class));
+    }
+
+    @Test
+    public void testProcessEvent(){
+        // TODO
+        // no yet implemented
+//        NorthboundEvent ev = mock(NorthboundEvent.class);
+//        when(ev.getAction()).thenReturn(Action.ADD);
+//        fwaasHandler.processEvent(ev);
+    }
+
+    @Test
+    public void testSetDependencies() {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        fwaasHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", fwaasHandler.eventDispatcher, eventDispatcher);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/FloatingIPHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/FloatingIPHandlerTest.java
new file mode 100644 (file)
index 0000000..df43570
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link FloatingIPHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class FloatingIPHandlerTest {
+
+    @InjectMocks FloatingIPHandler floatingHandler;
+    @Mock NeutronL3Adapter neutronL3Adapter;
+
+    @Test
+    public void testCanCreateFloatingIP(){
+        assertEquals("Error, did not return the correct HTTP status code", HttpURLConnection.HTTP_OK, floatingHandler.canCreateFloatingIP(mock(NeutronFloatingIP.class)));
+    }
+
+    @Test
+    public void testCanUpdateFloatingIP(){
+        assertEquals("Error, did not return the correct HTTP status code", HttpURLConnection.HTTP_OK, floatingHandler.canUpdateFloatingIP(mock(NeutronFloatingIP.class), mock(NeutronFloatingIP.class)));
+    }
+
+    @Test
+    public void testCanDeleteFloatingIP(){
+        assertEquals("Error, did not return the correct HTTP status code", HttpURLConnection.HTTP_OK, floatingHandler.canDeleteFloatingIP(mock(NeutronFloatingIP.class)));
+    }
+
+    @Test
+    public void testProcessEvent(){
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+
+        when(ev.getNeutronFloatingIP()).thenReturn(mock(NeutronFloatingIP.class));
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        floatingHandler.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronFloatingIPEvent(ev.getNeutronFloatingIP(), ev.getAction());
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        floatingHandler.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronFloatingIPEvent(ev.getNeutronFloatingIP(), ev.getAction());
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        floatingHandler.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronFloatingIPEvent(ev.getNeutronFloatingIP(), ev.getAction());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+        NeutronL3Adapter neutronL3Adapter = mock(NeutronL3Adapter.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+        ServiceHelper.overrideGlobalInstance(NeutronL3Adapter.class, neutronL3Adapter);
+
+        floatingHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", eventDispatcher, floatingHandler.eventDispatcher);
+        assertEquals("Error, did not return the correct object", neutronL3Adapter, getNeutronL3Adapter());
+    }
+
+    private NeutronL3Adapter getNeutronL3Adapter() throws Exception {
+        Field field = FloatingIPHandler.class.getDeclaredField("neutronL3Adapter");
+        field.setAccessible(true);
+        return (NeutronL3Adapter) field.get(floatingHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSHandlerTest.java
new file mode 100644 (file)
index 0000000..933dd37
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link LBaaSHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class LBaaSHandlerTest {
+
+    @InjectMocks private LBaaSHandler lbaasHandler;
+    private LBaaSHandler lbaasHandlerSpy;
+
+    @Mock private INeutronLoadBalancerCRUD neutronLBCache;
+    @Mock private INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
+    @Mock private LoadBalancerProvider loadBalancerProvider;
+    @Mock private NodeCacheManager nodeCacheManager;
+    @Mock private NeutronLoadBalancer neutronLB;
+    @Mock private INeutronSubnetCRUD neutronSubnetCache;
+    @Mock private INeutronNetworkCRUD neutronNetworkCache;
+    @Mock private INeutronPortCRUD neutronPortCache;
+
+    @Before
+    public void setUp(){
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        Map.Entry<String,String> providerInfo = mock(Entry.class);
+        NeutronLoadBalancerPoolMember neutronLBPoolMember = mock(NeutronLoadBalancerPoolMember.class);
+        NeutronLoadBalancerPool neutronLBPool = mock(NeutronLoadBalancerPool.class);
+        List<NeutronLoadBalancerPoolMember> members = new ArrayList();
+        List<NeutronLoadBalancerPool> list_neutronLBPool = new ArrayList();
+        List<NeutronLoadBalancer> list_neutronLB = new ArrayList();
+        List<Node> list_node = new ArrayList();
+
+        lbaasHandlerSpy = Mockito.spy(lbaasHandler);
+
+        neutronLB = mock(NeutronLoadBalancer.class);
+        when(neutronLB.getLoadBalancerName()).thenReturn("load_balancer_name");
+        when(neutronLB.getLoadBalancerVipAddress()).thenReturn("vip_address");
+        when(neutronLB.getLoadBalancerVipSubnetID()).thenReturn("subnetID");
+
+        when(ev.getLoadBalancer()).thenReturn(neutronLB);
+
+        when(providerInfo.getKey()).thenReturn("key");
+        when(providerInfo.getValue()).thenReturn("value");
+
+        lbaasHandler.setDependencies(neutronPortCache);
+        final NeutronPort neutronPort = new NeutronPort();
+        final Neutron_IPs neutronIP1 = new Neutron_IPs();
+        neutronIP1.setSubnetUUID("pool_member_subnetID");
+        neutronIP1.setIpAddress("pool_member_address");
+        final Neutron_IPs neutronIP2 = new Neutron_IPs();
+        neutronIP2.setSubnetUUID("subnetID");
+        neutronIP2.setIpAddress("vip_address");
+        final Neutron_IPs neutronIP3 = new Neutron_IPs();
+        neutronIP3.setSubnetUUID("subnetID");
+        neutronIP3.setIpAddress("pool_member_address");
+        final List<Neutron_IPs> neutronIPs = new ArrayList<>();
+        neutronIPs.add(neutronIP1);
+        neutronIPs.add(neutronIP2);
+        neutronIPs.add(neutronIP3);
+        neutronPort.setFixedIPs(neutronIPs);
+        neutronPort.setMacAddress("mac_address");
+        when(neutronPortCache.getAllPorts()).thenReturn(Collections.singletonList(neutronPort));
+
+        lbaasHandler.setDependencies(neutronSubnetCache);
+        final NeutronSubnet neutronSubnet1 = new NeutronSubnet();
+        neutronSubnet1.setID("pool_member_subnetID");
+        neutronSubnet1.setNetworkUUID("pool_member_networkUUID");
+        final NeutronSubnet neutronSubnet2 = new NeutronSubnet();
+        neutronSubnet2.setID("subnetID");
+        neutronSubnet2.setNetworkUUID("pool_member_networkUUID");
+        List<NeutronSubnet> neutronSubnets = new ArrayList<>();
+        neutronSubnets.add(neutronSubnet1);
+        neutronSubnets.add(neutronSubnet2);
+        when(neutronSubnetCache.getAllSubnets()).thenReturn(neutronSubnets);
+
+        lbaasHandler.setDependencies(neutronNetworkCache);
+        final NeutronNetwork neutronNetwork = new NeutronNetwork();
+        neutronNetwork.setNetworkUUID("pool_member_networkUUID");
+        neutronNetwork.setProviderNetworkType("key");
+        neutronNetwork.setProviderSegmentationID("value");
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(Collections.singletonList(neutronNetwork));
+
+        when(neutronLBPoolMember.getPoolMemberAdminStateIsUp()).thenReturn(true);
+        when(neutronLBPoolMember.getPoolMemberSubnetID()).thenReturn("subnetID");
+        when(neutronLBPoolMember.getID()).thenReturn("pool_memberID");
+        when(neutronLBPoolMember.getPoolMemberAddress()).thenReturn("pool_member_address");
+        when(neutronLBPoolMember.getPoolMemberProtoPort()).thenReturn(1);
+        members.add(neutronLBPoolMember);
+
+        when(neutronLBPool.getLoadBalancerPoolMembers()).thenReturn(members);
+        when(neutronLBPool.getLoadBalancerPoolProtocol()).thenReturn(LoadBalancerConfiguration.PROTOCOL_TCP);
+        list_neutronLBPool.add(neutronLBPool);
+        when(neutronLBPoolCache.getAllNeutronLoadBalancerPools()).thenReturn(list_neutronLBPool);
+
+        list_neutronLB.add(neutronLB);
+        when(neutronLBCache.getAllNeutronLoadBalancers()).thenReturn(list_neutronLB );
+
+        list_node.add(mock(Node.class));
+        when(nodeCacheManager.getBridgeNodes()).thenReturn(list_node);
+    }
+
+    @Test
+    public void testCanCreateNeutronLoadBalancer(){
+        assertEquals("Error, canCreateNeutronLoadBalancer() did not return the correct value ", HttpURLConnection.HTTP_OK, lbaasHandler.canCreateNeutronLoadBalancer(null));
+    }
+
+    @Test
+    public void testCanUpdateNeutronLoadBalancer(){
+        assertEquals("Error, canUpdateNeutronLoadBalancer() did not return the correct value ", HttpURLConnection.HTTP_OK, lbaasHandler.canUpdateNeutronLoadBalancer(null, null));
+    }
+
+    @Test
+    public void testCanDeleteNeutronLoadBalancer(){
+        assertEquals("Error, canDeleteNeutronLoadBalancer() did not return the correct value ", HttpURLConnection.HTTP_OK, lbaasHandler.canDeleteNeutronLoadBalancer(null));
+    }
+
+    /**
+     * Test method {@link LBaaSHandler#processEvent(AbstractEvent)}
+     */
+    @Test
+    public void testProcessEvent(){
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        when(ev.getLoadBalancer()).thenReturn(neutronLB);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        lbaasHandlerSpy.processEvent(ev);
+        verify(lbaasHandlerSpy, times(1)).extractLBConfiguration(any(NeutronLoadBalancer.class));
+        verify(loadBalancerProvider, times(1)).programLoadBalancerRules(any(Node.class), any(LoadBalancerConfiguration.class), same(Action.ADD));
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        lbaasHandlerSpy.processEvent(ev);
+        verify(lbaasHandlerSpy, times(2)).extractLBConfiguration(any(NeutronLoadBalancer.class)); // 1 + 1 above
+        verify(loadBalancerProvider, times(1)).programLoadBalancerRules(any(Node.class), any(LoadBalancerConfiguration.class), same(Action.DELETE));
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        lbaasHandlerSpy.processEvent(ev);
+        verify(lbaasHandlerSpy, times(4)).extractLBConfiguration(any(NeutronLoadBalancer.class)); // 2 + 2 above
+        verify(loadBalancerProvider, times(2)).programLoadBalancerRules(any(Node.class), any(LoadBalancerConfiguration.class), same(Action.DELETE)); // 1 + 1 above
+        verify(loadBalancerProvider, times(2)).programLoadBalancerRules(any(Node.class), any(LoadBalancerConfiguration.class), same(Action.ADD)); // 1 + 1 above
+    }
+
+    /**
+     * Test method {@link LBaaSHandler#extractLBConfiguration(NeutronLoadBalancer)}
+     */
+    @Test
+    public void testExtractLBConfiguration(){
+        LoadBalancerConfiguration lbConfig = lbaasHandler.extractLBConfiguration(neutronLB);
+
+        verify(neutronLBPoolCache, times(1)).getAllNeutronLoadBalancerPools();
+
+        // make sure the load balancer configuration was correctly populated
+        assertEquals("Error, did not return the correct value",  "key", lbConfig.getProviderNetworkType());
+        assertEquals("Error, did not return the correct value",  "value", lbConfig.getProviderSegmentationId());
+        assertEquals("Error, did not return the correct value",  "mac_address", lbConfig.getVmac());
+
+        // make sure the load balancer pool member was correctly populated
+        LoadBalancerConfiguration.LoadBalancerPoolMember member = lbConfig.getMembers().get("pool_memberID");
+        assertEquals("Error, did not return the correct value",  "pool_member_address", member.getIP());
+        assertEquals("Error, did not return the correct value",  "mac_address", member.getMAC());
+        assertEquals("Error, did not return the correct value",  LoadBalancerConfiguration.PROTOCOL_TCP, member.getProtocol());
+        assertTrue("Error, did not return the correct value",  1 ==  member.getPort());
+    }
+
+    /**
+     * Test method {@link LBaaSHandler#notifyNode(Node, Action)}
+     */
+    @Test
+    public void testNotifyNode() {
+        lbaasHandlerSpy.notifyNode(mock(Node.class), Action.ADD);
+
+        verify(lbaasHandlerSpy, times(1)).extractLBConfiguration(any(NeutronLoadBalancer.class));
+        verify(neutronLBCache, times(1)).getAllNeutronLoadBalancers();
+        verify(neutronLBPoolCache, times(1)).getAllNeutronLoadBalancerPools();
+        verify(loadBalancerProvider, times(1)).programLoadBalancerRules(any(Node.class), any(LoadBalancerConfiguration.class), any(Action.class));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+        LoadBalancerProvider loadBalancerProvider = mock(LoadBalancerProvider.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+        ServiceHelper.overrideGlobalInstance(LoadBalancerProvider.class, loadBalancerProvider);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+
+        lbaasHandler.setDependencies(mock(ServiceReference.class));
+
+        Assert.assertEquals("Error, did not return the correct object", lbaasHandler.eventDispatcher, eventDispatcher);
+        assertEquals("Error, did not return the correct object", getField("loadBalancerProvider"), loadBalancerProvider);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
+        lbaasHandler.setDependencies(iNeutronNetworkCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
+
+        INeutronPortCRUD iNeutronPortCRUD = mock(INeutronPortCRUD.class);
+        lbaasHandler.setDependencies(iNeutronPortCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), iNeutronPortCRUD);
+
+        INeutronSubnetCRUD iNeutronSubnetCRUD = mock(INeutronSubnetCRUD.class);
+        lbaasHandler.setDependencies(iNeutronSubnetCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronSubnetCache"), iNeutronSubnetCRUD);
+
+        INeutronLoadBalancerCRUD iNeutronLoadBalancerCRUD = mock(INeutronLoadBalancerCRUD.class);
+        lbaasHandler.setDependencies(iNeutronLoadBalancerCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronLBCache"), iNeutronLoadBalancerCRUD);
+
+        INeutronLoadBalancerPoolCRUD iNeutronLoadBalancerPoolCRUD = mock(INeutronLoadBalancerPoolCRUD.class);
+        lbaasHandler.setDependencies(iNeutronLoadBalancerPoolCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronLBPoolCache"), iNeutronLoadBalancerPoolCRUD);
+
+        LoadBalancerProvider loadBalancerProvider = mock(LoadBalancerProvider.class);
+        lbaasHandler.setDependencies(loadBalancerProvider);
+        assertEquals("Error, did not return the correct object", getField("loadBalancerProvider"), loadBalancerProvider);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = LBaaSHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(lbaasHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolHandlerTest.java
new file mode 100644 (file)
index 0000000..02bec42
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration.LoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link LBaaSPoolMemberHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class LBaaSPoolHandlerTest {
+
+    @InjectMocks LBaaSPoolHandler lBaaSPoolHandler;
+
+    @Mock private INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
+    @Mock private INeutronLoadBalancerCRUD neutronLBCache;
+    @Mock private LoadBalancerProvider loadBalancerProvider;
+    @Mock private NodeCacheManager nodeCacheManager;
+
+    @Mock private NeutronLoadBalancerPool neutronLBPool;
+    @Mock private INeutronSubnetCRUD neutronSubnetCache;
+    @Mock private INeutronNetworkCRUD neutronNetworkCache;
+    @Mock private INeutronPortCRUD neutronPortCache;
+
+    @Before
+    public void setUp() {
+        when(neutronLBPool.getLoadBalancerPoolProtocol()).thenReturn(LoadBalancerConfiguration.PROTOCOL_HTTP);
+
+        lBaaSPoolHandler.setDependencies(neutronPortCache);
+        final NeutronPort neutronPort = new NeutronPort();
+        final Neutron_IPs neutronIP1 = new Neutron_IPs();
+        neutronIP1.setSubnetUUID("pool_member_subnetID");
+        neutronIP1.setIpAddress("pool_member_address");
+        final Neutron_IPs neutronIP2 = new Neutron_IPs();
+        neutronIP2.setSubnetUUID("subnetID");
+        neutronIP2.setIpAddress("vip_address");
+        final Neutron_IPs neutronIP3 = new Neutron_IPs();
+        neutronIP3.setSubnetUUID("subnetID");
+        neutronIP3.setIpAddress("pool_member_address");
+        final List<Neutron_IPs> neutronIPs = new ArrayList<>();
+        neutronIPs.add(neutronIP1);
+        neutronIPs.add(neutronIP2);
+        neutronIPs.add(neutronIP3);
+        neutronPort.setFixedIPs(neutronIPs);
+        neutronPort.setMacAddress("mac_address");
+        when(neutronPortCache.getAllPorts()).thenReturn(Collections.singletonList(neutronPort));
+
+        lBaaSPoolHandler.setDependencies(neutronSubnetCache);
+        final NeutronSubnet neutronSubnet1 = new NeutronSubnet();
+        neutronSubnet1.setID("pool_member_subnetID");
+        neutronSubnet1.setNetworkUUID("pool_member_networkUUID");
+        final NeutronSubnet neutronSubnet2 = new NeutronSubnet();
+        neutronSubnet2.setID("subnetID");
+        neutronSubnet2.setNetworkUUID("pool_member_networkUUID");
+        List<NeutronSubnet> neutronSubnets = new ArrayList<>();
+        neutronSubnets.add(neutronSubnet1);
+        neutronSubnets.add(neutronSubnet2);
+        when(neutronSubnetCache.getAllSubnets()).thenReturn(neutronSubnets);
+
+        lBaaSPoolHandler.setDependencies(neutronNetworkCache);
+        final NeutronNetwork neutronNetwork = new NeutronNetwork();
+        neutronNetwork.setNetworkUUID("pool_member_networkUUID");
+        neutronNetwork.setProviderNetworkType("key");
+        neutronNetwork.setProviderSegmentationID("value");
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(Collections.singletonList(neutronNetwork));
+
+        List<NeutronLoadBalancerPoolMember> members = new ArrayList<>();
+        NeutronLoadBalancerPoolMember neutronLBPoolMember = mock(NeutronLoadBalancerPoolMember.class);
+        when(neutronLBPoolMember.getPoolMemberAdminStateIsUp()).thenReturn(true);
+        when(neutronLBPoolMember.getPoolMemberSubnetID()).thenReturn("subnetID");
+        when(neutronLBPoolMember.getID()).thenReturn("pool_memberID");
+        when(neutronLBPoolMember.getPoolMemberAddress()).thenReturn("pool_member_address");
+        when(neutronLBPoolMember.getPoolMemberProtoPort()).thenReturn(1);
+        members.add(neutronLBPoolMember);
+        when(neutronLBPool.getLoadBalancerPoolMembers()).thenReturn(members);
+
+        List<NeutronLoadBalancer> list_neutronLB = new ArrayList<>();
+        NeutronLoadBalancer neutronLB = mock(NeutronLoadBalancer.class);
+        when(neutronLB.getLoadBalancerName()).thenReturn("load_balancer_name");
+        when(neutronLB.getLoadBalancerVipAddress()).thenReturn("vip_address");
+        when(neutronLB.getLoadBalancerVipSubnetID()).thenReturn("subnetID");
+        list_neutronLB.add(neutronLB);
+        when(neutronLBCache.getAllNeutronLoadBalancers()).thenReturn(list_neutronLB);
+    }
+
+    /**
+     * Test method {@link LBaaSPoolHandler#canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool)}
+     */
+    @Test
+    public void testCanCreateNeutronLoadBalancerPoolMember() {
+        when(neutronLBPool.getLoadBalancerPoolProtocol())
+                                    .thenReturn(LoadBalancerConfiguration.PROTOCOL_HTTP) // to test HTTP_OK
+                                    .thenReturn(null) // to test HTTP_BAD_REQUEST
+                                    .thenReturn("dummy_proto"); // to test HTTP_NOT_ACCEPTABLE
+
+        assertEquals("Error, canCreateNeutronLoadBalancerPool() didn't return the correct HTTP flag", HttpURLConnection.HTTP_OK, lBaaSPoolHandler.canCreateNeutronLoadBalancerPool(neutronLBPool));
+        assertEquals("Error, canCreateNeutronLoadBalancerPool() didn't return the correct HTTP flag", HttpURLConnection.HTTP_BAD_REQUEST, lBaaSPoolHandler.canCreateNeutronLoadBalancerPool(neutronLBPool));
+        assertEquals("Error, canCreateNeutronLoadBalancerPool() didn't return the correct HTTP flag", HttpURLConnection.HTTP_NOT_ACCEPTABLE, lBaaSPoolHandler.canCreateNeutronLoadBalancerPool(neutronLBPool));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolHandler#canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool, NeutronLoadBalancerPool)}
+     */
+    public void testCanUpdateNeutronLoadBalancerPool() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_NOT_IMPLEMENTED, lBaaSPoolHandler.canUpdateNeutronLoadBalancerPool(any(NeutronLoadBalancerPool.class), any(NeutronLoadBalancerPool.class)));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolHandler#canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool)}
+     */
+    @Test
+    public void testCanDeleteNeutronLoadBalancerPool() {
+        when(neutronLBPool.getLoadBalancerPoolProtocol())
+                                        .thenReturn(LoadBalancerConfiguration.PROTOCOL_HTTP) // to test HTTP_OK
+                                        .thenReturn(null) // to test HTTP_BAD_REQUEST
+                                        .thenReturn("dummy_proto"); // to test HTTP_NOT_ACCEPTABLE
+
+        assertEquals("Error, canDeleteNeutronLoadBalancerPool() didn't return the correct HTTP flag", HttpURLConnection.HTTP_OK, lBaaSPoolHandler.canDeleteNeutronLoadBalancerPool(neutronLBPool));
+        assertEquals("Error, canDeleteNeutronLoadBalancerPool() didn't return the correct HTTP flag", HttpURLConnection.HTTP_BAD_REQUEST, lBaaSPoolHandler.canDeleteNeutronLoadBalancerPool(neutronLBPool));
+        assertEquals("Error, canDeleteNeutronLoadBalancerPool() didn't return the correct HTTP flag", HttpURLConnection.HTTP_NOT_ACCEPTABLE, lBaaSPoolHandler.canDeleteNeutronLoadBalancerPool(neutronLBPool));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolHandler#processEvent(AbstractEvent)}
+     */
+    @Test
+    public void testProcessEvent() {
+        LBaaSPoolHandler lbaasPoolHandlerSpy = Mockito.spy(lBaaSPoolHandler);
+
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        when(ev.getLoadBalancerPool()).thenReturn(neutronLBPool);
+
+        List<Node> list_node = new ArrayList<>();
+        list_node .add(mock(Node.class));
+        when(nodeCacheManager.getBridgeNodes()).thenReturn(list_node);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        lbaasPoolHandlerSpy.processEvent(ev);
+        verify(lbaasPoolHandlerSpy, times(1)).extractLBConfiguration(any(NeutronLoadBalancerPool.class));
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        lbaasPoolHandlerSpy.processEvent(ev);
+        verify(lbaasPoolHandlerSpy, times(2)).extractLBConfiguration(any(NeutronLoadBalancerPool.class)); // 1 + 1 above
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        lbaasPoolHandlerSpy.processEvent(ev);
+        verify(lbaasPoolHandlerSpy, times(2)).extractLBConfiguration(any(NeutronLoadBalancerPool.class)); // same as before as nothing as been done
+    }
+
+    /**
+     * Test method {@link LBaaSPoolHandler#extractLBConfiguration(NeutronLoadBalancerPool)}
+     */
+    @Test
+    public void testExtractLBConfiguration() {
+        List<LoadBalancerConfiguration> list_lbConfig = lBaaSPoolHandler.extractLBConfiguration(neutronLBPool);
+        assertFalse(list_lbConfig.isEmpty());
+        LoadBalancerConfiguration lbConfig = list_lbConfig.get(0);
+
+        verify(neutronLBCache, times(1)).getAllNeutronLoadBalancers();
+
+        // make sure the load balancer configuration was correctly populated
+        assertEquals("Error, did not return the correct value",  "key", lbConfig.getProviderNetworkType());
+        assertEquals("Error, did not return the correct value",  "value", lbConfig.getProviderSegmentationId());
+        assertEquals("Error, did not return the correct value",  "mac_address", lbConfig.getVmac());
+
+        // make sure the load balancer pool member was correctly populated
+        LoadBalancerPoolMember member = lbConfig.getMembers().get("pool_memberID");
+        assertEquals("Error, did not return the correct value",  "pool_member_address", member.getIP());
+        assertEquals("Error, did not return the correct value",  "mac_address", member.getMAC());
+        assertEquals("Error, did not return the correct value",  LoadBalancerConfiguration.PROTOCOL_HTTP, member.getProtocol());
+        assertTrue("Error, did not return the correct value",  1 ==  member.getPort());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+        LoadBalancerProvider loadBalancerProvider = mock(LoadBalancerProvider.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+        ServiceHelper.overrideGlobalInstance(LoadBalancerProvider.class, loadBalancerProvider);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+
+        lBaaSPoolHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", lBaaSPoolHandler.eventDispatcher, eventDispatcher);
+        assertEquals("Error, did not return the correct object", getField("loadBalancerProvider"), loadBalancerProvider);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
+        lBaaSPoolHandler.setDependencies(iNeutronNetworkCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
+
+        INeutronPortCRUD iNeutronPortCRUD = mock(INeutronPortCRUD.class);
+        lBaaSPoolHandler.setDependencies(iNeutronPortCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), iNeutronPortCRUD);
+
+        INeutronSubnetCRUD iNeutronSubnetCRUD = mock(INeutronSubnetCRUD.class);
+        lBaaSPoolHandler.setDependencies(iNeutronSubnetCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronSubnetCache"), iNeutronSubnetCRUD);
+
+        INeutronLoadBalancerCRUD iNeutronLoadBalancerCRUD = mock(INeutronLoadBalancerCRUD.class);
+        lBaaSPoolHandler.setDependencies(iNeutronLoadBalancerCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronLBCache"), iNeutronLoadBalancerCRUD);
+
+        LoadBalancerProvider loadBalancerProvider = mock(LoadBalancerProvider.class);
+        lBaaSPoolHandler.setDependencies(loadBalancerProvider);
+        assertEquals("Error, did not return the correct object", getField("loadBalancerProvider"), loadBalancerProvider);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = LBaaSPoolHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(lBaaSPoolHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolMemberHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/LBaaSPoolMemberHandlerTest.java
new file mode 100644 (file)
index 0000000..69841fc
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration;
+import org.opendaylight.netvirt.openstack.netvirt.api.LoadBalancerConfiguration.LoadBalancerPoolMember;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link LBaaSPoolMemberHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class LBaaSPoolMemberHandlerTest {
+
+    @InjectMocks LBaaSPoolMemberHandler lBaaSPoolMemberHandler;
+
+    @Mock private INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
+    @Mock private INeutronLoadBalancerCRUD neutronLBCache;
+    @Mock private LoadBalancerProvider loadBalancerProvider;
+    @Mock private NodeCacheManager nodeCacheManager;
+    @Mock private INeutronPortCRUD neutronPortCache;
+    @Mock private INeutronNetworkCRUD neutronNetworkCache;
+    @Mock private INeutronSubnetCRUD neutronSubnetCache;
+
+    private NeutronLoadBalancerPoolMember neutronLBMember;
+
+    @Before
+    public void setUp() {
+        neutronLBMember = new NeutronLoadBalancerPoolMember();
+        neutronLBMember.setID("pool_memberID");
+        neutronLBMember.setPoolMemberAddress("pool_member_address");
+        neutronLBMember.setPoolMemberSubnetID("pool_member_subnetID");
+        neutronLBMember.setPoolMemberProtoPort(1);
+        neutronLBMember.setPoolID("poolID");
+
+        lBaaSPoolMemberHandler.setDependencies(neutronPortCache);
+        final NeutronPort neutronPort = new NeutronPort();
+        final Neutron_IPs neutronIP1 = new Neutron_IPs();
+        neutronIP1.setSubnetUUID("pool_member_subnetID");
+        neutronIP1.setIpAddress("pool_member_address");
+        final Neutron_IPs neutronIP2 = new Neutron_IPs();
+        neutronIP2.setSubnetUUID("pool_member_subnetID");
+        neutronIP2.setIpAddress("vip_address");
+        final List<Neutron_IPs> neutronIPs = new ArrayList<>();
+        neutronIPs.add(neutronIP1);
+        neutronIPs.add(neutronIP2);
+        neutronPort.setFixedIPs(neutronIPs);
+        neutronPort.setMacAddress("mac_address");
+        when(neutronPortCache.getAllPorts()).thenReturn(Collections.singletonList(neutronPort));
+
+        lBaaSPoolMemberHandler.setDependencies(neutronSubnetCache);
+        final NeutronSubnet neutronSubnet = new NeutronSubnet();
+        neutronSubnet.setID("pool_member_subnetID");
+        neutronSubnet.setNetworkUUID("pool_member_networkUUID");
+        when(neutronSubnetCache.getAllSubnets()).thenReturn(Collections.singletonList(neutronSubnet));
+
+        lBaaSPoolMemberHandler.setDependencies(neutronNetworkCache);
+        final NeutronNetwork neutronNetwork = new NeutronNetwork();
+        neutronNetwork.setNetworkUUID("pool_member_networkUUID");
+        neutronNetwork.setProviderNetworkType("key");
+        neutronNetwork.setProviderSegmentationID("value");
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(Collections.singletonList(neutronNetwork));
+
+        List<NeutronLoadBalancerPoolMember> members = new ArrayList<>();
+        NeutronLoadBalancerPoolMember neutronLBPoolMember = new NeutronLoadBalancerPoolMember();
+        neutronLBPoolMember.setPoolMemberAdminStateIsUp(true);
+        neutronLBPoolMember.setPoolMemberSubnetID("pool_member_subnetID");
+        neutronLBPoolMember.setID("pool_memberID1");
+        neutronLBPoolMember.setPoolMemberProtoPort(1);
+        members.add(neutronLBPoolMember);
+
+        NeutronLoadBalancerPool neutronLBPool = new NeutronLoadBalancerPool();
+        neutronLBPool.setLoadBalancerPoolProtocol(LoadBalancerConfiguration.PROTOCOL_TCP);
+        neutronLBPool.setLoadBalancerPoolMembers(members);
+        when(neutronLBPoolCache.getNeutronLoadBalancerPool(anyString())).thenReturn(neutronLBPool);
+
+        NeutronLoadBalancer neutronLB = new NeutronLoadBalancer();
+        neutronLB.setLoadBalancerName("load_balancer_name");
+        neutronLB.setLoadBalancerVipAddress("vip_address");
+        neutronLB.setLoadBalancerVipSubnetID("pool_member_subnetID");
+        when(neutronLBCache.getAllNeutronLoadBalancers()).thenReturn(Collections.singletonList(neutronLB));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolMemberHandler#canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember)}
+     */
+    @Test
+    public void testCanCreateNeutronLoadBalancerPoolMember() {
+        // HTTP_BAD_REQUEST
+        neutronLBMember.setPoolID(null);
+        assertEquals("Error, canCreateNeutronLoadBalancerPoolMember() didn't return the correct HTTP flag", HttpURLConnection.HTTP_BAD_REQUEST, lBaaSPoolMemberHandler.canCreateNeutronLoadBalancerPoolMember(neutronLBMember));
+
+        // HTTP_OK
+        neutronLBMember.setPoolID("poolID");
+        assertEquals("Error, canCreateNeutronLoadBalancerPoolMember() didn't return the correct HTTP flag", HttpURLConnection.HTTP_OK, lBaaSPoolMemberHandler.canCreateNeutronLoadBalancerPoolMember(neutronLBMember));
+
+        // HTTP_NOT_ACCEPTABLE
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(Collections.<NeutronNetwork>emptyList());
+        assertEquals("Error, canCreateNeutronLoadBalancerPoolMember() didn't return the correct HTTP flag", HttpURLConnection.HTTP_NOT_ACCEPTABLE, lBaaSPoolMemberHandler.canCreateNeutronLoadBalancerPoolMember(neutronLBMember));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolMemberHandler#canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember, NeutronLoadBalancerPoolMember)}
+     */
+    @Test
+    public void testCanUpdateNeutronLoadBalancerPoolMember() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_NOT_IMPLEMENTED, lBaaSPoolMemberHandler.canUpdateNeutronLoadBalancerPoolMember(null, null));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolMemberHandler#canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember)}
+     */
+    @Test
+    public void testCanDeleteNeutronLoadBalancerPoolMember() {
+        // HTTP_BAD_REQUEST
+        neutronLBMember.setPoolID(null);
+        assertEquals("Error, canDeleteNeutronLoadBalancerPoolMember() didn't return the correct HTTP flag", HttpURLConnection.HTTP_BAD_REQUEST, lBaaSPoolMemberHandler.canDeleteNeutronLoadBalancerPoolMember(neutronLBMember));
+
+        // HTTP_OK
+        neutronLBMember.setPoolID("poolID");
+        assertEquals("Error, canDeleteNeutronLoadBalancerPoolMember() didn't return the correct HTTP flag", HttpURLConnection.HTTP_OK, lBaaSPoolMemberHandler.canDeleteNeutronLoadBalancerPoolMember(neutronLBMember));
+
+        // HTTP_NOT_ACCEPTABLE
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(Collections.<NeutronNetwork>emptyList());
+        assertEquals("Error, canDeleteNeutronLoadBalancerPoolMember() didn't return the correct HTTP flag", HttpURLConnection.HTTP_NOT_ACCEPTABLE, lBaaSPoolMemberHandler.canDeleteNeutronLoadBalancerPoolMember(neutronLBMember));
+    }
+
+    /**
+     * Test method {@link LBaaSPoolMemberHandler#processEvent(AbstractEvent)}
+     */
+    @Test
+    public void testProcessEvent(){
+        LBaaSPoolMemberHandler lbaasPoolMemberHandlerSpy = Mockito.spy(lBaaSPoolMemberHandler);
+
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        when(ev.getLoadBalancerPoolMember()).thenReturn(neutronLBMember);
+
+        List<Node> list_node = new ArrayList<>();
+        list_node .add(mock(Node.class));
+        when(nodeCacheManager.getBridgeNodes()).thenReturn(list_node);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        lbaasPoolMemberHandlerSpy.processEvent(ev);
+        verify(lbaasPoolMemberHandlerSpy, times(1)).extractLBConfiguration(any(NeutronLoadBalancerPoolMember.class));
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        lbaasPoolMemberHandlerSpy.processEvent(ev);
+        verify(lbaasPoolMemberHandlerSpy, times(2)).extractLBConfiguration(any(NeutronLoadBalancerPoolMember.class)); // 1 + 1 above
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        lbaasPoolMemberHandlerSpy.processEvent(ev);
+        verify(lbaasPoolMemberHandlerSpy, times(2)).extractLBConfiguration(any(NeutronLoadBalancerPoolMember.class)); // same as before as nothing as been done
+    }
+
+    /**
+     * Test method {@link LBaaSPoolMemberHandler#extractLBConfiguration(NeutronLoadBalancerPoolMember)}
+     */
+    @Test
+    public void testExtractLBConfiguration() {
+        LoadBalancerConfiguration lbConfig = lBaaSPoolMemberHandler.extractLBConfiguration(neutronLBMember);
+
+        // make sure the load balancer configuration was correctly populated
+        assertEquals("Error, did not return the correct value",  "key", lbConfig.getProviderNetworkType());
+        assertEquals("Error, did not return the correct value",  "value", lbConfig.getProviderSegmentationId());
+        assertEquals("Error, did not return the correct value",  "mac_address", lbConfig.getVmac());
+
+        // make sure the load balancer pool member was correctly populated
+        LoadBalancerPoolMember member = lbConfig.getMembers().get("pool_memberID");
+        assertEquals("Error, did not return the correct value",  "pool_member_address", member.getIP());
+        assertEquals("Error, did not return the correct value",  "mac_address", member.getMAC());
+        assertEquals("Error, did not return the correct value",  LoadBalancerConfiguration.PROTOCOL_TCP, member.getProtocol());
+        assertTrue("Error, did not return the correct value",  1 ==  member.getPort());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+        LoadBalancerProvider loadBalancerProvider = mock(LoadBalancerProvider.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+        ServiceHelper.overrideGlobalInstance(LoadBalancerProvider.class, loadBalancerProvider);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+
+        lBaaSPoolMemberHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", lBaaSPoolMemberHandler.eventDispatcher, eventDispatcher);
+        assertEquals("Error, did not return the correct object", getField("loadBalancerProvider"), loadBalancerProvider);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
+        lBaaSPoolMemberHandler.setDependencies(iNeutronNetworkCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
+
+        INeutronPortCRUD iNeutronPortCRUD = mock(INeutronPortCRUD.class);
+        lBaaSPoolMemberHandler.setDependencies(iNeutronPortCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), iNeutronPortCRUD);
+
+        INeutronSubnetCRUD iNeutronSubnetCRUD = mock(INeutronSubnetCRUD.class);
+        lBaaSPoolMemberHandler.setDependencies(iNeutronSubnetCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronSubnetCache"), iNeutronSubnetCRUD);
+
+        INeutronLoadBalancerCRUD iNeutronLoadBalancerCRUD = mock(INeutronLoadBalancerCRUD.class);
+        lBaaSPoolMemberHandler.setDependencies(iNeutronLoadBalancerCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronLBCache"), iNeutronLoadBalancerCRUD);
+
+        INeutronLoadBalancerPoolCRUD iNeutronLoadBalancerPoolCRUD = mock(INeutronLoadBalancerPoolCRUD.class);
+        lBaaSPoolMemberHandler.setDependencies(iNeutronLoadBalancerPoolCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronLBPoolCache"), iNeutronLoadBalancerPoolCRUD);
+
+        LoadBalancerProvider loadBalancerProvider = mock(LoadBalancerProvider.class);
+        lBaaSPoolMemberHandler.setDependencies(loadBalancerProvider);
+        assertEquals("Error, did not return the correct object", getField("loadBalancerProvider"), loadBalancerProvider);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = LBaaSPoolMemberHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(lBaaSPoolMemberHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NetworkHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NetworkHandlerTest.java
new file mode 100644 (file)
index 0000000..bf4c1f1
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+        .OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link NetworkHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class NetworkHandlerTest {
+
+    @InjectMocks private NetworkHandler networkHandler;
+
+    @Mock private NeutronNetwork sharedNeutronNetwork;
+    @Mock private NeutronNetwork nonSharedNeutronNetwork;
+
+    @Mock private NeutronL3Adapter neutronL3Adapter;
+    @Mock private TenantNetworkManager tenantNetworkManager;
+    @Mock private INeutronNetworkCRUD neutronNetworkCache;
+    @Mock private BridgeConfigurationManager bridgeConfigurationManager;
+    @Mock private NodeCacheManager nodeCacheManager;
+    @Mock private Southbound southbound;
+
+    @Before
+    public void setup() {
+        when(sharedNeutronNetwork.isShared()).thenReturn(true);
+        when(nonSharedNeutronNetwork.isShared()).thenReturn(false);
+    }
+
+    /**
+     * Test method {@link NetworkHandler#canCreateNetwork(NeutronNetwork)}
+     */
+    @Test
+    public void testCanCreateNetwork() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, networkHandler.canCreateNetwork(sharedNeutronNetwork));
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, networkHandler.canCreateNetwork(nonSharedNeutronNetwork));
+    }
+
+    /**
+     * Test method {@link NetworkHandler#canUpdateNetwork(NeutronNetwork, NeutronNetwork)}
+     */
+    @Test
+    public void testCanUpdateNetwork() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, networkHandler.canUpdateNetwork(sharedNeutronNetwork, sharedNeutronNetwork));
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, networkHandler.canUpdateNetwork(nonSharedNeutronNetwork, nonSharedNeutronNetwork));
+    }
+
+    /**
+     * Test method {@link NetworkHandler#canDeleteNetwork(NeutronNetwork)}
+     */
+    @Test
+    public void testCanDeleteNetwork() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, networkHandler.canDeleteNetwork(nonSharedNeutronNetwork));
+    }
+
+    /**
+     * Test method {@link NetworkHandler#processEvent(AbstractEvent)}
+     */
+    @Test
+    public void testProcessEvent() {
+        NetworkHandler networkHandlerSpy = Mockito.spy(networkHandler);
+
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        when(ev.getNeutronNetwork()).thenReturn(nonSharedNeutronNetwork);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        networkHandlerSpy.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronNetworkEvent(any(NeutronNetwork.class), same(Action.ADD));
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        networkHandlerSpy.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronNetworkEvent(any(NeutronNetwork.class), same(Action.UPDATE));
+
+        String portName = "portName";
+
+        List<NeutronNetwork> networks = new ArrayList<>();
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(networks);
+
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(mock(Node.class));
+        when(nodeCacheManager.getNodes()).thenReturn(nodes);
+
+        List<String> phyIfName = new ArrayList<>();
+        phyIfName.add(portName);
+        when(bridgeConfigurationManager.getAllPhysicalInterfaceNames(any(Node.class))).thenReturn(phyIfName );
+
+        List<OvsdbTerminationPointAugmentation> ports = new ArrayList<>();
+        OvsdbTerminationPointAugmentation port = mock(OvsdbTerminationPointAugmentation.class);
+        when(port.getName()).thenReturn(portName);
+        ports.add(port);
+        when(southbound.getTerminationPointsOfBridge(any(Node.class))).thenReturn(ports);
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        when(southbound.isTunnel(any(OvsdbTerminationPointAugmentation.class))).thenReturn(true);
+        networkHandlerSpy.processEvent(ev); // test delete with southbound.isTunnel(true)
+        when(southbound.isTunnel(any(OvsdbTerminationPointAugmentation.class))).thenReturn(false);
+        networkHandlerSpy.processEvent(ev); // test delete with southbound.isTunnel(false)
+        // the functions are called once per call to processEvent()
+        verify(neutronL3Adapter, times(2)).handleNeutronNetworkEvent(any(NeutronNetwork.class), same(Action.DELETE));
+        verify(tenantNetworkManager, times(2)).networkDeleted(anyString());
+        // depending on the southbound.isTunnel()
+        verify(southbound, times(2)).deleteTerminationPoint(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        BridgeConfigurationManager bridgeConfigurationManager = mock(BridgeConfigurationManager.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        NeutronL3Adapter neutronL3Adapter = mock(NeutronL3Adapter.class);
+        Southbound southbound = mock(Southbound.class);
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+
+        ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
+        ServiceHelper.overrideGlobalInstance(BridgeConfigurationManager.class, bridgeConfigurationManager);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+        ServiceHelper.overrideGlobalInstance(NeutronL3Adapter.class, neutronL3Adapter);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        networkHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
+        assertEquals("Error, did not return the correct object", getField("bridgeConfigurationManager"), bridgeConfigurationManager);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+        assertEquals("Error, did not return the correct object", getField("neutronL3Adapter"), neutronL3Adapter);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+        assertEquals("Error, did not return the correct object", networkHandler.eventDispatcher, eventDispatcher);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
+        networkHandler.setDependencies(iNeutronNetworkCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
+}
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = NetworkHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(networkHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NeutronCacheUtilsTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NeutronCacheUtilsTest.java
new file mode 100644 (file)
index 0000000..edca4dd
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+
+/**
+ * Unit test for {@link NeutronCacheUtils}
+ */
+public class NeutronCacheUtilsTest {
+
+    /**
+     * Test method {@link NeutronCacheUtils#getMacAddress(INeutronPortCRUD, String, String)}
+     */
+    @Test
+    public void testGetMacAddress(){
+        INeutronPortCRUD neutronPortsCache = mock(INeutronPortCRUD.class);
+        NeutronPort port = mock(NeutronPort.class);
+        Neutron_IPs ip = mock(Neutron_IPs.class);
+        when(ip.getIpAddress()).thenReturn("ip_address");
+        when(ip.getSubnetUUID()).thenReturn("subnetUUID");
+        List<Neutron_IPs> list_fixedIP = new ArrayList<>();
+        list_fixedIP.add(ip);
+        when(port.getFixedIPs()).thenReturn(list_fixedIP);
+        when(port.getMacAddress()).thenReturn("mac_address");
+        List<NeutronPort> list_port = new ArrayList<>();
+        list_port.add(port);
+
+        when(neutronPortsCache.getAllPorts()).thenReturn(list_port);
+
+        assertEquals("Error, getMacAddress() did not return the correct value", "mac_address", NeutronCacheUtils.getMacAddress(neutronPortsCache, "subnetUUID", "ip_address"));
+    }
+
+    /**
+     * Test method {@link NeutronCacheUtils#getProviderInformation(INeutronNetworkCRUD, INeutronSubnetCRUD, String)}
+     */
+    @Test
+    public void testGetProviderInformation() {
+        INeutronSubnetCRUD neutronSubnetCache = mock(INeutronSubnetCRUD.class);
+        NeutronSubnet subnet = mock(NeutronSubnet.class);
+        when(subnet.getID()).thenReturn("subnetUUID");
+        when(subnet.getNetworkUUID()).thenReturn("networkUUID");
+        List<NeutronSubnet> list_subnet = new ArrayList<>();
+        list_subnet.add(subnet);
+
+        when(neutronSubnetCache.getAllSubnets()).thenReturn(list_subnet );
+
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        NeutronNetwork network = mock(NeutronNetwork.class);
+        when(network.getID()).thenReturn("networkUUID");
+        when(network.getProviderNetworkType()).thenReturn("network_type_1");
+        when(network.getProviderSegmentationID()).thenReturn("network_segID");
+        List<NeutronNetwork> list_network = new ArrayList<>();
+        list_network.add(network);
+
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(list_network);
+
+        Map.Entry<String,String> entry = new AbstractMap.SimpleEntry<>(
+                network.getProviderNetworkType(), network.getProviderSegmentationID());
+
+        assertEquals("Error, getProviderInformation() did not return the correct values", entry, NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, "subnetUUID"));
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NodeCacheManagerEventTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NodeCacheManagerEventTest.java
new file mode 100644 (file)
index 0000000..2b7fd4e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * Unit test for {@link NodeCacheManagerEvent}
+ */
+
+@RunWith(MockitoJUnitRunner.class)
+public class NodeCacheManagerEventTest {
+
+    @InjectMocks private NodeCacheManagerEvent nodeCacheManagerEvent;
+
+    @Test
+    public void testToString() {
+        Node node = mock(Node.class);
+        nodeCacheManagerEvent = new NodeCacheManagerEvent(node, Action.ADD);
+        assertEquals("Error, toString() did not return the correct string", "NodeCacheManagerEvent [action=ADD, node=" + node + "]", nodeCacheManagerEvent.toString());
+    }
+
+    @Test
+    public void testHashCode() {
+        assertNotNull("Error, hashCode shouldn't be null", nodeCacheManagerEvent.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        assertTrue("Error, the two object should be equal", nodeCacheManagerEvent.equals(nodeCacheManagerEvent));
+        assertFalse("Error, the two object should not be equal", nodeCacheManagerEvent.equals(new String("dummy")));
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NodeConfigurationTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/NodeConfigurationTest.java
new file mode 100644 (file)
index 0000000..cc1774e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+
+/**
+ * Unit test for {@link NodeConfiguration}
+ */
+public class NodeConfigurationTest {
+
+    @Test
+    public void testNodeConfiguration() {
+        NodeConfiguration nodeConf = new NodeConfiguration();
+
+        assertEquals("Error, did not populate the internal vlan queue correctly", Constants.MAX_VLAN - 1, nodeConf.getInternalVlans().size());
+        assertNotNull("Error, tenant vlan map has not been initialized", nodeConf.getTenantVlanMap());
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/PortHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/PortHandlerTest.java
new file mode 100644 (file)
index 0000000..dab134b
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+        .OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test fort {@link PortHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class PortHandlerTest {
+
+    @InjectMocks private PortHandler portHandler;
+
+    @Mock private NeutronL3Adapter neutronL3Adapter;
+    @Mock private DistributedArpService distributedArpService;
+    @Mock private NodeCacheManager nodeCacheManager;
+    @Mock private Southbound southbound;
+
+    @Test
+    public void testCanCreatePort() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portHandler.canCreatePort(mock(NeutronPort.class)));
+    }
+
+    @Test
+    public void testCanUpdatePort() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portHandler.canUpdatePort(mock(NeutronPort.class), mock(NeutronPort.class)));
+    }
+
+    @Test
+    public void testCanDeletePort() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portHandler.canDeletePort(mock(NeutronPort.class)));
+    }
+
+    @Test
+    public void testProcessEvent() {
+        PortHandler portHandlerSpy = Mockito.spy(portHandler);
+
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getTenantID()).thenReturn("tenantID");
+        when(neutronPort.getNetworkUUID()).thenReturn("networkUUID");
+        when(neutronPort.getID()).thenReturn("ID");
+        when(neutronPort.getPortUUID()).thenReturn("portUUID");
+
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        when(ev.getPort()).thenReturn(neutronPort);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        portHandlerSpy.processEvent(ev);
+        verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.ADD);
+        verify(neutronL3Adapter, times(1)).handleNeutronPortEvent(neutronPort, Action.ADD);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        portHandlerSpy.processEvent(ev);
+        verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.UPDATE);
+        verify(neutronL3Adapter, times(1)).handleNeutronPortEvent(neutronPort, Action.UPDATE);
+
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(mock(Node.class));
+        when(nodeCacheManager.getNodes()).thenReturn(nodes);
+
+        List<OvsdbTerminationPointAugmentation> ports = new ArrayList<>();
+        OvsdbTerminationPointAugmentation port = mock(OvsdbTerminationPointAugmentation.class);
+        ports.add(port);
+        when(southbound.getTerminationPointsOfBridge(any(Node.class))).thenReturn(ports);
+
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn("portUUID");
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        portHandlerSpy.processEvent(ev);
+        verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.DELETE);
+        verify(neutronL3Adapter, times(1)).handleNeutronPortEvent(neutronPort, Action.DELETE);
+        verify(southbound, times(1)).deleteTerminationPoint(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        DistributedArpService distributedArpService = mock(DistributedArpService.class);
+        NeutronL3Adapter neutronL3Adapter = mock(NeutronL3Adapter.class);
+        Southbound southbound = mock(Southbound.class);
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+        ServiceHelper.overrideGlobalInstance(DistributedArpService.class, distributedArpService);
+        ServiceHelper.overrideGlobalInstance(NeutronL3Adapter.class, neutronL3Adapter);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        portHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+        assertEquals("Error, did not return the correct object", getField("distributedArpService"), distributedArpService);
+        assertEquals("Error, did not return the correct object", getField("neutronL3Adapter"), neutronL3Adapter);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+        assertEquals("Error, did not return the correct object", portHandler.eventDispatcher, eventDispatcher);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = PortHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(portHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandlerTest.java
new file mode 100644 (file)
index 0000000..46899b9
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test {@link PortSecurityHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class PortSecurityHandlerTest {
+
+    @InjectMocks private PortSecurityHandler portSecurityHandler;
+    private PortSecurityHandler posrtSecurityHandlerSpy;
+    @Mock
+    EventDispatcher eventDispatcher;
+
+    @Before
+    public void setUp() {
+        posrtSecurityHandlerSpy = Mockito.spy(portSecurityHandler);
+    }
+
+    @Test
+    public void testCanCreateNeutronSecurityGroup() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_CREATED, portSecurityHandler.canCreateNeutronSecurityGroup(mock(NeutronSecurityGroup.class)));
+
+        posrtSecurityHandlerSpy.neutronSecurityGroupCreated(any(NeutronSecurityGroup.class));
+        verify(posrtSecurityHandlerSpy, times(1)).canCreateNeutronSecurityGroup(any(NeutronSecurityGroup.class));
+    }
+
+    @Test
+    public void testCanUpdateNeutronSecurityGroup() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portSecurityHandler.canUpdateNeutronSecurityGroup(mock(NeutronSecurityGroup.class), mock(NeutronSecurityGroup.class)));
+    }
+
+    @Test
+    public void testCanDeleteNeutronSecurityGroup() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portSecurityHandler.canDeleteNeutronSecurityGroup(mock(NeutronSecurityGroup.class)));
+
+        posrtSecurityHandlerSpy.neutronSecurityGroupDeleted(any(NeutronSecurityGroup.class));
+        verify(posrtSecurityHandlerSpy, times(1)).canDeleteNeutronSecurityGroup(any(NeutronSecurityGroup.class));
+    }
+
+    @Test
+    public void testCanCreateNeutronSecurityRule() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_CREATED, portSecurityHandler.canCreateNeutronSecurityRule(mock(NeutronSecurityRule.class)));
+
+        posrtSecurityHandlerSpy.neutronSecurityRuleCreated(any(NeutronSecurityRule.class));
+        verify(posrtSecurityHandlerSpy, times(1)).enqueueEvent(any(AbstractEvent.class));
+    }
+
+    @Test
+    public void testCanUpdateNeutronSecurityRule() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portSecurityHandler.canUpdateNeutronSecurityRule(mock(NeutronSecurityRule.class), mock(NeutronSecurityRule.class)));
+    }
+
+    @Test
+    public void testCanDeleteNeutronSecurityRule() {
+        assertEquals("Error, did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, portSecurityHandler.canDeleteNeutronSecurityRule(mock(NeutronSecurityRule.class)));
+
+        posrtSecurityHandlerSpy.neutronSecurityRuleDeleted(any(NeutronSecurityRule.class));
+        verify(posrtSecurityHandlerSpy, times(1)).enqueueEvent(any(AbstractEvent.class));
+   }
+
+    @Test
+    public void testProcessEvent() {
+        // TODO see PortSecurityHandler#processEvent()
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        portSecurityHandler.setDependencies(mock(ServiceReference.class));
+
+        Assert.assertEquals("Error, did not return the correct object", portSecurityHandler.eventDispatcher, eventDispatcher);
+    }
+
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = PortSecurityHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(portSecurityHandler);
+    }
+
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/RouterHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/RouterHandlerTest.java
new file mode 100644 (file)
index 0000000..bc23359
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test fort {@link RouterHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class RouterHandlerTest {
+
+    @InjectMocks RouterHandler routerHandler;
+
+    @Mock NeutronL3Adapter neutronL3Adapter;
+
+    @Test
+    public void testCanCreateRouter() {
+        assertEquals("Error, canCreateRouter() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, routerHandler.canCreateRouter(mock(NeutronRouter.class)));
+    }
+
+    @Test
+    public void testCanUpdateRouter() {
+        assertEquals("Error, canUpdateRouter() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, routerHandler.canUpdateRouter(mock(NeutronRouter.class), mock(NeutronRouter.class)));
+    }
+
+    @Test
+    public void testCanDeleteRouter() {
+        assertEquals("Error, canDeleteRouter() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, routerHandler.canDeleteRouter(mock(NeutronRouter.class)));
+    }
+
+    @Test
+    public void testCanAttachAndDettachInterface() {
+        NeutronRouter router = mock(NeutronRouter.class);
+        when(router.getName()).thenReturn("router_name");
+
+        NeutronRouter_Interface routerInterface = mock(NeutronRouter_Interface.class);
+        when(routerInterface.getPortUUID()).thenReturn("portUUID");
+        when(routerInterface.getSubnetUUID()).thenReturn("subnetUUID");
+
+        assertEquals("Error, canAttachInterface() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, routerHandler.canAttachInterface(router, routerInterface));
+        assertEquals("Error, canDetachInterface() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, routerHandler.canDetachInterface(router, routerInterface));
+    }
+
+    @Test
+    public void testProcessEvent() {
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        when(ev.getRouter()).thenReturn(mock(NeutronRouter.class));
+        when(ev.getRouterInterface())
+                                .thenReturn(null)
+                                .thenReturn(mock(NeutronRouter_Interface.class));
+
+        routerHandler.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronRouterEvent(ev.getRouter(), Action.UPDATE);
+        routerHandler.processEvent(ev);
+        verify(neutronL3Adapter, times(1)).handleNeutronRouterInterfaceEvent(ev.getRouter(), ev.getRouterInterface(), Action.UPDATE);
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        NeutronL3Adapter neutronL3Adapter = mock(NeutronL3Adapter.class);
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+        ServiceHelper.overrideGlobalInstance(NeutronL3Adapter.class, neutronL3Adapter);
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        routerHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("neutronL3Adapter"), neutronL3Adapter);
+        assertEquals("Error, did not return the correct object", routerHandler.eventDispatcher, eventDispatcher);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = RouterHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(routerHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandlerTest.java
new file mode 100644 (file)
index 0000000..8ae3775
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test fort {@link SouthboundHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SouthboundHandlerTest {
+
+    @InjectMocks private SouthboundHandler southboundHandler;
+    private SouthboundHandler southboundHandlerSpy;
+
+    @Mock private ConfigurationService configurationService;
+    @Mock private BridgeConfigurationManager bridgeConfigurationManager;
+    @Mock private TenantNetworkManager tenantNetworkManager;
+    @Mock private NetworkingProviderManager networkingProviderManager;
+    @Mock private DistributedArpService distributedArpService;
+    @Mock private NeutronL3Adapter neutronL3Adapter;
+    @Mock private NodeCacheManager nodeCacheManager;
+    @Mock private OvsdbInventoryService ovsdbInventoryService;
+    @Mock private Southbound southbound;
+
+    @Before
+    public void setUp() {
+        southboundHandler.eventDispatcher = mock(EventDispatcher.class);
+        southboundHandlerSpy = Mockito.spy(southboundHandler);
+    }
+
+    @Test
+    public void testTriggerUpdates() {
+        Node node = mock(Node.class);
+        when(node.getAugmentation(OvsdbNodeAugmentation.class)).thenReturn(mock(OvsdbNodeAugmentation.class));
+
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(mock(Node.class));
+        when(southbound.readOvsdbTopologyNodes()).thenReturn(nodes);
+
+        southboundHandlerSpy.triggerUpdates();
+        verify(southboundHandlerSpy, times(1)).ovsdbUpdate(any(Node.class), any(DataObject.class), any(OvsdbInventoryListener.OvsdbType.class), any(Action.class));
+
+    }
+
+    @Test
+    public void testNotifyNode() {
+        when(southbound.getBridge(any(Node.class))).thenReturn(mock(OvsdbBridgeAugmentation.class));
+
+        NetworkingProvider networkingProvider = mock(NetworkingProvider.class);
+        when(networkingProviderManager.getProvider(any(Node.class))).thenReturn(networkingProvider);
+
+        southboundHandlerSpy.notifyNode(mock(Node.class), Action.ADD);
+
+        verify(networkingProvider, times(1)).initializeOFFlowRules(any(Node.class));
+    }
+
+    @Test
+    public void testProcessEvent() {
+        SouthboundEvent ev = mock(SouthboundEvent.class);
+        Node node = mock(Node.class);
+
+        // NODE
+        when(ev.getNode()).thenReturn(node);
+        when(ev.getAugmentationData()).thenReturn(mock(OvsdbNodeAugmentation.class));
+        when(ev.getType()).thenReturn(SouthboundEvent.Type.NODE);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        southboundHandler.processEvent(ev);
+        verify(nodeCacheManager, times(1)).nodeAdded(any(Node.class));
+        verify(bridgeConfigurationManager, times(1)).prepareNode(any(Node.class));
+        Mockito.reset(nodeCacheManager);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        southboundHandler.processEvent(ev);
+        verify(nodeCacheManager, times(1)).nodeAdded(any(Node.class));
+        Mockito.reset(nodeCacheManager);
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        southboundHandler.processEvent(ev);
+        verify(nodeCacheManager, times(1)).nodeRemoved(any(Node.class));
+        Mockito.reset(nodeCacheManager);
+
+        Mockito.reset(ev);
+
+        // BRIDGE
+        when(ev.getNode()).thenReturn(node);
+        when(ev.getAugmentationData()).thenReturn(mock(OvsdbBridgeAugmentation.class));
+        when(ev.getType()).thenReturn(SouthboundEvent.Type.BRIDGE);
+
+        when(southbound.getDatapathId(any(OvsdbBridgeAugmentation.class))).thenReturn("45");
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        southboundHandler.processEvent(ev);
+        verify(nodeCacheManager, times(1)).nodeAdded(any(Node.class));
+        Mockito.reset(nodeCacheManager);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        southboundHandler.processEvent(ev);
+        verify(nodeCacheManager, times(1)).nodeAdded(any(Node.class));
+        Mockito.reset(nodeCacheManager);
+
+        Mockito.reset(nodeCacheManager);
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        southboundHandler.processEvent(ev);
+        verify(nodeCacheManager, times(1)).nodeRemoved(any(Node.class));
+        verify(southbound, times(1)).deleteBridge(any(Node.class));
+        Mockito.reset(nodeCacheManager);
+        Mockito.reset(southbound);
+
+        Mockito.reset(ev);
+
+        // PORT
+        OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = mock(OvsdbTerminationPointAugmentation.class);
+        when(ovsdbTerminationPointAugmentation.getName()).thenReturn("network");
+//        Mockito.<Class<?>>when(ovsdbTerminationPointAugmentation.getInterfaceType()).thenReturn(InterfaceTypeBase.class);
+//        when(ovsdbTerminationPointAugmentation.getInterfaceType()).thenReturn(n);
+        when(ev.getNode()).thenReturn(node);
+        when(ev.getAugmentationData()).thenReturn(ovsdbTerminationPointAugmentation);
+        when(ev.getType()).thenReturn(SouthboundEvent.Type.PORT);
+
+        NetworkingProvider networkingProvider = mock(NetworkingProvider.class);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getRouterExternal()).thenReturn(false);
+        when(tenantNetworkManager.getTenantNetwork(any(OvsdbTerminationPointAugmentation.class))).thenReturn(neutronNetwork);
+        when(networkingProviderManager.getProvider(any(Node.class))).thenReturn(networkingProvider);
+        when(bridgeConfigurationManager.createLocalNetwork(any(Node.class), any(NeutronNetwork.class))).thenReturn(true);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        southboundHandler.processEvent(ev);
+        verify(distributedArpService, times(1)).processInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(neutronL3Adapter, times(1)).handleInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(networkingProvider, times(1)).handleInterfaceUpdate(any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+        Mockito.reset(distributedArpService);
+        Mockito.reset(neutronL3Adapter);
+        Mockito.reset(networkingProvider);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        southboundHandler.processEvent(ev);
+        verify(distributedArpService, times(1)).processInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(neutronL3Adapter, times(1)).handleInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(networkingProvider, times(1)).handleInterfaceUpdate(any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+        Mockito.reset(neutronL3Adapter);
+        Mockito.reset(distributedArpService);
+        Mockito.reset(networkingProvider);
+
+//        List<String> phyIfName = new ArrayList<String>();
+//        phyIfName.add("network");
+//        when(bridgeConfigurationManager.getAllPhysicalInterfaceNames(any(Node.class))).thenReturn(phyIfName);
+//
+//        when(ev.getAction()).thenReturn(Action.DELETE); //isInterfaceOfIntereset true
+//        southboundHandler.processEvent(ev);
+//        verify(neutronL3Adapter, times(1)).handleInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+//        verify(networkingProvider, times(1)).handleInterfaceDelete(anyString(), any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), anyBoolean());
+//
+//        Mockito.reset(networkingProvider);
+//
+//        when(southbound.getBridge(any(Node.class))).thenReturn(mock(OvsdbBridgeAugmentation.class));
+//        List<TerminationPoint> terminationPoints = new ArrayList<TerminationPoint>();
+//        TerminationPoint terminationPoint =  mock(TerminationPoint.class);
+//        OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation2 = mock(OvsdbTerminationPointAugmentation.class);
+//        when(terminationPoint.getAugmentation(any(Class.class))).thenReturn(ovsdbTerminationPointAugmentation);
+//        Uuid uuid = mock(Uuid.class);
+//        when(ovsdbTerminationPointAugmentation.getInterfaceUuid()).thenReturn(uuid);
+//        when(ovsdbTerminationPointAugmentation2.getInterfaceUuid()).thenReturn(uuid);
+//        terminationPoints.add(terminationPoint);
+//        when(node.getTerminationPoint()).thenReturn(terminationPoints);
+//
+//        when(ev.getAction()).thenReturn(Action.DELETE); //isInterfaceOfIntereset false - network != null
+//        southboundHandler.processEvent(ev);
+//        verify(networkingProvider, times(1)).handleInterfaceDelete(anyString(), any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), anyBoolean());
+
+        // OPENVSWITCH
+        when(ev.getNode()).thenReturn(node);
+        when(ev.getAugmentationData()).thenReturn(ovsdbTerminationPointAugmentation);
+        when(ev.getType()).thenReturn(SouthboundEvent.Type.OPENVSWITCH);
+
+        when(ovsdbTerminationPointAugmentation.getName()).thenReturn("network");
+        List<TerminationPoint> terminationPoints = new ArrayList<>();
+        terminationPoints.add(mock(TerminationPoint.class));
+        when(southbound.extractTerminationPoints(any(Node.class))).thenReturn(terminationPoints);
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        southboundHandler.processEvent(ev);
+        verify(distributedArpService, times(1)).processInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(neutronL3Adapter, times(1)).handleInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(networkingProvider, times(1)).handleInterfaceUpdate(any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+        Mockito.reset(distributedArpService);
+        Mockito.reset(neutronL3Adapter);
+        Mockito.reset(networkingProvider);
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        NetworkingProviderManager networkingProviderManager = mock(NetworkingProviderManager.class);
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        BridgeConfigurationManager bridgeConfigurationManager = mock(BridgeConfigurationManager.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        NeutronL3Adapter neutronL3Adapter = mock(NeutronL3Adapter.class);
+        DistributedArpService distributedArpService = mock(DistributedArpService.class);
+        Southbound southbound = mock(Southbound.class);
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+        OvsdbInventoryService ovsdbInventoryService = mock(OvsdbInventoryService.class);
+
+        ServiceHelper.overrideGlobalInstance(ConfigurationService.class, configurationService);
+        ServiceHelper.overrideGlobalInstance(NetworkingProviderManager.class, networkingProviderManager);
+        ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
+        ServiceHelper.overrideGlobalInstance(BridgeConfigurationManager.class, bridgeConfigurationManager);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+        ServiceHelper.overrideGlobalInstance(DistributedArpService.class, distributedArpService);
+        ServiceHelper.overrideGlobalInstance(NeutronL3Adapter.class, neutronL3Adapter);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+        ServiceHelper.overrideGlobalInstance(OvsdbInventoryService.class, ovsdbInventoryService);
+
+        southboundHandler.setDependencies(mock(ServiceReference.class));
+        assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
+        assertEquals("Error, did not return the correct object", getField("networkingProviderManager"), networkingProviderManager);
+        assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
+        assertEquals("Error, did not return the correct object", getField("bridgeConfigurationManager"), bridgeConfigurationManager);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+        assertEquals("Error, did not return the correct object", getField("distributedArpService"), distributedArpService);
+        assertEquals("Error, did not return the correct object", getField("neutronL3Adapter"), neutronL3Adapter);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+        assertEquals("Error, did not return the correct object", getField("ovsdbInventoryService"), ovsdbInventoryService);
+        assertEquals("Error, did not return the correct object", southboundHandler.eventDispatcher, eventDispatcher);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = SouthboundHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(southboundHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SubnetHandlerTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SubnetHandlerTest.java
new file mode 100644 (file)
index 0000000..b17e876
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test fort {@link SubnetHandler}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SubnetHandlerTest {
+
+    @InjectMocks private SubnetHandler subnetHandler;
+
+    @Mock NeutronL3Adapter neutronl3Adapter;
+
+    @Test
+    public void testCanCreateSubnet() {
+        assertEquals("Error, canCreateSubnet() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, subnetHandler.canCreateSubnet(mock(NeutronSubnet.class)));
+    }
+
+    @Test
+    public void testCanUpdateSubnet() {
+        assertEquals("Error, canUpdateSubnet() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, subnetHandler.canUpdateSubnet(mock(NeutronSubnet.class), mock(NeutronSubnet.class)));
+    }
+
+    @Test
+    public void testCanDeleteSubnet() {
+        assertEquals("Error, canDeleteSubnet() did not return the correct HTTP flag", HttpURLConnection.HTTP_OK, subnetHandler.canDeleteSubnet(mock(NeutronSubnet.class)));
+    }
+
+    @Test
+    public void testProcessEvent() {
+        NorthboundEvent ev = mock(NorthboundEvent.class);
+        when(ev.getSubnet()).thenReturn(mock(NeutronSubnet.class));
+
+        when(ev.getAction()).thenReturn(Action.ADD);
+        subnetHandler.processEvent(ev);
+        verify(neutronl3Adapter, times(1)).handleNeutronSubnetEvent(ev.getSubnet(), ev.getAction());
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        subnetHandler.processEvent(ev);
+        verify(neutronl3Adapter, times(1)).handleNeutronSubnetEvent(ev.getSubnet(), ev.getAction());
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        subnetHandler.processEvent(ev);
+        verify(neutronl3Adapter, times(1)).handleNeutronSubnetEvent(ev.getSubnet(), ev.getAction());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        NeutronL3Adapter neutronL3Adapter = mock(NeutronL3Adapter.class);
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+        ServiceHelper.overrideGlobalInstance(NeutronL3Adapter.class, neutronL3Adapter);
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        subnetHandler.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("neutronL3Adapter"), neutronL3Adapter);
+        assertEquals("Error, did not return the correct object", subnetHandler.eventDispatcher, eventDispatcher);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = SubnetHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(subnetHandler);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerConfigurationTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/api/LoadBalancerConfigurationTest.java
new file mode 100644 (file)
index 0000000..e011d04
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+* Copyright (c) 2014 Intel Corp. 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
+*
+* Authors : Marcus Koontz
+*/
+package org.opendaylight.netvirt.openstack.netvirt.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+
+public class LoadBalancerConfigurationTest {
+    private LoadBalancerConfiguration lbConfig;
+    private Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> lbMap = new HashMap<>();
+    private Object[][] valuesArray =
+            {{"mockUUID1", "mockUUID2", "mockUUID3"},
+            {"10.10.1.343", "10.10.1.391", "10.10.1.31"},
+            {"D5:6B:59:E8:F4:84", "D5:4B:60:E8:F5:84", "D5:4B:60:E8:F6:84"},
+            {"tcp", "tcp", "http"},
+            {125304, 125304, 1204}};
+
+    @Before
+    public void setUp() throws Exception {
+        lbConfig = new LoadBalancerConfiguration();
+        lbConfig.addMember(valuesArray[0][0].toString(), valuesArray[1][0].toString(),
+                valuesArray[2][0].toString(), valuesArray[3][0].toString(), (Integer)valuesArray[4][0]);
+        lbConfig.addMember(valuesArray[0][1].toString(), valuesArray[1][1].toString(),
+                valuesArray[2][1].toString(), valuesArray[3][1].toString(), (Integer)valuesArray[4][1]);
+        lbMap = lbConfig.getMembers();
+    }
+
+    @Test
+    public void testConstructorLbConfig() throws Exception{
+        lbConfig.setName("test-name");
+        lbConfig.setProviderNetworkType("vlan");
+        lbConfig.setProviderSegmentationId("segment-id-mock");
+        lbConfig.setVip("192.168.58.87");
+        lbConfig.setVmac("A2-E2-24-E3-44-8D");
+        LoadBalancerConfiguration lbConfigLocal = new LoadBalancerConfiguration(lbConfig);
+
+        assertEquals("getName() returned the wrong value", "test-name", lbConfigLocal.getName());
+        assertEquals("getProviderNetworkType() returned the wrong value", "vlan",
+                lbConfigLocal.getProviderNetworkType());
+        assertEquals("getProviderSegmentationId() returned the wrong value", "segment-id-mock",
+                lbConfigLocal.getProviderSegmentationId());
+        assertEquals("getVip() returned the wrong value", "192.168.58.87", lbConfigLocal.getVip());
+        assertEquals("getVmac() returned the wrong value", "A2-E2-24-E3-44-8D", lbConfigLocal.getVmac());
+
+        Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> lbMapLocal = lbConfigLocal.getMembers();
+        for (LoadBalancerConfiguration.LoadBalancerPoolMember lbMember: lbMapLocal.values()){
+            assertTrue("IP expected " + valuesArray[1][lbMember.getIndex()] + " found: " +
+                    lbMember.getIP(), valuesArray[1][lbMember.getIndex()] == lbMember.getIP());
+            assertTrue("MAC expected " + valuesArray[2][lbMember.getIndex()] + " found " +
+                    lbMember.getMAC(), valuesArray[2][lbMember.getIndex()] == lbMember.getMAC());
+            assertTrue("protocol expected " + valuesArray[3][lbMember.getIndex()] + " found " +
+                    lbMember.getProtocol(), valuesArray[3][lbMember.getIndex()] == lbMember.getProtocol());
+            assertTrue("port expected " + valuesArray[4][lbMember.getIndex()] + " found " +
+                    lbMember.getPort(), valuesArray[4][lbMember.getIndex()].equals(lbMember.getPort()));
+        }
+    }
+
+    @Test
+    public void testGetMembers() throws Exception {
+        Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> lbMapLocal = lbConfig.getMembers();
+        for (LoadBalancerConfiguration.LoadBalancerPoolMember lbMember: lbMapLocal.values()){
+            assertTrue("IP expected " + valuesArray[1][lbMember.getIndex()] + " found: " +
+                    lbMember.getIP(), valuesArray[1][lbMember.getIndex()] == lbMember.getIP());
+            assertTrue("MAC expected " + valuesArray[2][lbMember.getIndex()] + " found " +
+                    lbMember.getMAC(), valuesArray[2][lbMember.getIndex()] == lbMember.getMAC());
+            assertTrue("protocol expected " + valuesArray[3][lbMember.getIndex()] + " found " +
+                    lbMember.getProtocol(), valuesArray[3][lbMember.getIndex()] == lbMember.getProtocol());
+            assertTrue("port expected " + valuesArray[4][lbMember.getIndex()] + " found " +
+                    lbMember.getPort(), valuesArray[4][lbMember.getIndex()].equals(lbMember.getPort()));
+        }
+        assertEquals("Get members does not return members", lbMap, lbConfig.getMembers());
+    }
+
+    @Test
+    public void testAddMember() throws Exception {
+        lbConfig.addMember(valuesArray[0][2].toString(), valuesArray[1][2].toString(), valuesArray[2][2].toString(),
+                valuesArray[3][2].toString(), (Integer)valuesArray[4][2]);
+        Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> lbMapLocal2 = lbConfig.getMembers();
+        assertTrue("Error, maps are unequal after adding a member. Size should be " + 3 +
+                " but size is " + lbMapLocal2.size(), 3 == lbMapLocal2.size());
+    }
+
+    @Test
+    public void testRemoveMember() throws Exception {
+        lbConfig.addMember(valuesArray[0][2].toString(), valuesArray[1][2].toString(), valuesArray[2][2].toString(),
+                valuesArray[3][2].toString(), (Integer)valuesArray[4][2]);
+        Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> lbMapLocal = lbConfig.getMembers();
+        assertTrue("Error, maps are not equal lbMapLocal size is " + lbMapLocal.size() + " size should be " +
+                3, lbMapLocal.size() == 3);
+        lbConfig.removeMember("mockUUID3");
+        Map<String, LoadBalancerConfiguration.LoadBalancerPoolMember> lbMapLocal2 = lbConfig.getMembers();
+        assertTrue("Error, maps are unequal after removing a member, size should be " + 2 + " but is " +
+                lbMapLocal2.size(), 2 == lbMapLocal2.size());
+    }
+
+    @Test
+    public void testIsValid() throws Exception {
+        assertFalse("load balancer config returned true for isValid, should be true ", lbConfig.isValid());
+        lbConfig.setProviderNetworkType("mockProviderNetworkType");
+        assertTrue("load balancer config returned false for isValid, should be true ", lbConfig.isValid());
+        lbConfig.removeMember("mockUUID2");
+        lbConfig.removeMember("mockUUID1");
+        assertFalse("load balancer config returned true for isValid, should be false ", lbConfig.isValid());
+    }
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/BridgeConfigurationManagerImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/BridgeConfigurationManagerImplTest.java
new file mode 100644 (file)
index 0000000..8a160b1
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+* Copyright (c) 2014, 2016 Intel Corp. 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.RETURNS_MOCKS;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeSystem;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+        .OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Test class for BridgeConfigurationManagerImpl
+ *
+ * @author Marcus Koontz
+ * @author Alexis de Talhouet
+ * @author Sam Hague (shague@redhat.com)
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class BridgeConfigurationManagerImplTest {
+    @Mock private Node node;
+    @Mock private OvsdbBridgeAugmentation bridge;
+    @Mock private OvsdbTerminationPointAugmentation port;
+    @Mock private NeutronNetwork neutronNetwork;
+    @Mock private ConfigurationService configurationService;
+    @Mock private Southbound southbound;
+    @InjectMocks public static BridgeConfigurationManagerImpl bridgeConfigurationManagerImpl;
+
+    private static final String ADDRESS = "127.0.0.1";
+    private static final String BR_INT = "br-int";
+    private static final String ETH1 = "eth1";
+    private static final String ETH2 = "eth2";
+    private static final String ETH3 = "eth3";
+    private static final String PORT_BR_INT = "br-int";
+    private static final String BRIDGE_UUID = "f527b951-3934-4182-9f29-33fc09f6f0c6";
+    private static final String PHYSNET1 = "physnet1";
+    private static final String PHYSNET2 = "physnet2";
+    private static final String PHYSNET3 = "physnet3";
+    private static final String PROVIDER_MAPPINGS = PHYSNET1 + ":" + ETH1 + "," + PHYSNET2 + ":" + ETH2;
+    private static final String PROVIDER_MAPPINGS_DEFAULT = PHYSNET1 + ":" + ETH1;
+
+    @Test
+    public void testGetBridgeUuid() {
+        when(southbound.getBridgeUuid(any(Node.class), anyString()))
+                .thenReturn(null)
+                .thenReturn(BRIDGE_UUID);
+
+        assertEquals("Error, null should have been returned", null,
+                bridgeConfigurationManagerImpl.getBridgeUuid(node, BR_INT));
+        assertEquals("Error, did not return UUID of correct bridge", BRIDGE_UUID,
+                bridgeConfigurationManagerImpl.getBridgeUuid(node, BR_INT));
+        verify(southbound, times(2)).getBridgeUuid(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testIsNodeNeutronReady() throws Exception {
+        when(southbound.getBridge(any(Node.class), anyString()))
+                .thenReturn(null)
+                .thenReturn(bridge);
+
+        verifyNoMoreInteractions(configurationService);
+        assertFalse("Error, did not return correct boolean from isNodeNeutronReady",
+                bridgeConfigurationManagerImpl.isNodeNeutronReady(node));
+
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+        assertTrue("Error, did not return correct boolean from isNodeNeutronReady",
+                bridgeConfigurationManagerImpl.isNodeNeutronReady(node));
+
+        verify(configurationService, times(2)).getIntegrationBridgeName();
+        verify(southbound, times(2)).getBridge(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testIsNodeOverlayReady() throws Exception {
+        when(southbound.getBridge(any(Node.class), anyString()))
+                .thenReturn(null)
+                .thenReturn(bridge);
+
+        BridgeConfigurationManagerImpl bridgeConfigurationManagerImplSpy =
+                spy(new BridgeConfigurationManagerImpl());
+        doReturn(false).when(bridgeConfigurationManagerImplSpy).isNodeNeutronReady(any(Node.class));
+        bridgeConfigurationManagerImplSpy.setConfigurationService(configurationService);
+        bridgeConfigurationManagerImplSpy.setSouthbound(southbound);
+
+        verifyNoMoreInteractions(configurationService);
+
+        assertFalse("Error, did not return correct boolean from isNodeOverlayReady",
+                bridgeConfigurationManagerImplSpy.isNodeOverlayReady(node));
+
+        doReturn(true).when(bridgeConfigurationManagerImplSpy).isNodeNeutronReady(any(Node.class));
+
+        assertFalse("Error, did not return correct boolean from isNodeOverlayReady",
+                bridgeConfigurationManagerImplSpy.isNodeOverlayReady(node));
+
+        assertTrue("Error, did not return correct boolean from isNodeOverlayReady",
+                bridgeConfigurationManagerImplSpy.isNodeOverlayReady(node));
+
+        verify(configurationService, times(2)).getNetworkBridgeName();
+        verify(southbound, times(2)).getBridge(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testIsPortOnBridge() throws Exception {
+        when(southbound.extractTerminationPointAugmentation(any(Node.class), anyString()))
+                .thenReturn(null)
+                .thenReturn(port);
+
+        assertFalse("Error, port " + PORT_BR_INT + " should not be found",
+                bridgeConfigurationManagerImpl.isPortOnBridge(node, PORT_BR_INT));
+        assertTrue("Error, port " + PORT_BR_INT + " should be found",
+                bridgeConfigurationManagerImpl.isPortOnBridge(node, PORT_BR_INT));
+        verify(southbound, times(2)).extractTerminationPointAugmentation(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testIsNodeTunnelReady() throws Exception {
+        when(southbound.isBridgeOnOvsdbNode(any(Node.class), anyString()))
+                .thenReturn(false)
+                .thenReturn(true);
+
+        verifyNoMoreInteractions(configurationService);
+        assertFalse("Error, did not return correct boolean from isNodeTunnelReady",
+                bridgeConfigurationManagerImpl.isNodeTunnelReady(node, node));
+
+        when(configurationService.isL3ForwardingEnabled()).thenReturn(false);
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+        assertTrue("Error, did not return correct boolean from isNodeTunnelReady",
+                bridgeConfigurationManagerImpl.isNodeTunnelReady(node, node));
+
+        verify(configurationService, times(1)).isL3ForwardingEnabled();
+        verify(configurationService, times(3)).getIntegrationBridgeName();
+        verify(southbound, times(2)).isBridgeOnOvsdbNode(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testIsNodeVlanReady() throws Exception {
+        when(southbound.isBridgeOnOvsdbNode(any(Node.class), anyString()))
+                .thenReturn(false)
+                .thenReturn(true);
+
+        when(southbound.extractTerminationPointAugmentation(any(Node.class), anyString()))
+                .thenReturn(null)
+                .thenReturn(port);
+
+        when(neutronNetwork.getProviderPhysicalNetwork()).thenReturn("test");
+
+        verifyNoMoreInteractions(configurationService);
+        assertFalse("Error, did not return correct boolean from isNodeTunnelReady",
+                bridgeConfigurationManagerImpl.isNodeVlanReady(node, node, neutronNetwork));
+
+        BridgeConfigurationManagerImpl bridgeConfigurationManagerImplSpy =
+                spy(new BridgeConfigurationManagerImpl());
+        doReturn(ETH1).when(bridgeConfigurationManagerImplSpy).getPhysicalInterfaceName(any(Node.class), anyString());
+        bridgeConfigurationManagerImplSpy.setConfigurationService(configurationService);
+        bridgeConfigurationManagerImplSpy.setSouthbound(southbound);
+
+        assertFalse("Error, did not return correct boolean from isNodeVlanReady",
+                bridgeConfigurationManagerImpl.isNodeVlanReady(node, node, neutronNetwork));
+
+        assertTrue("Error, did not return correct boolean from isNodeVlanReady",
+                bridgeConfigurationManagerImpl.isNodeVlanReady(node, node, neutronNetwork));
+
+        verify(configurationService, times(3)).getIntegrationBridgeName();
+        verify(neutronNetwork, times(2)).getProviderPhysicalNetwork();
+    }
+
+    @Test
+    public void testIsNodeL3Ready() {
+        when(southbound.isBridgeOnOvsdbNode(any(Node.class), anyString())).thenReturn(true);
+        when(southbound.extractTerminationPointAugmentation(any(Node.class), anyString())).thenReturn(mock(OvsdbTerminationPointAugmentation.class));
+        when(southbound.readBridgeNode(any(Node.class), anyString())).thenReturn(mock(Node.class));
+
+        assertTrue("Error, isNodeL3Ready didn't return true", bridgeConfigurationManagerImpl.isNodeL3Ready(node, node));
+    }
+
+    @Test
+    public void testPrepareNode() {
+        when(configurationService.getIntegrationBridgeName()).thenReturn(BR_INT);
+        when(southbound.isBridgeOnOvsdbNode(any(Node.class), anyString())).thenReturn(false);
+
+        // TODO Figure out the strings
+        //when(ConfigProperties.getProperty(any(Class.class), anyString())).thenReturn(ADDRESS);
+
+        when(southbound.addBridge(any(Node.class), anyString(), anyList(), eq(DatapathTypeSystem.class))).thenReturn(true);
+        when(configurationService.isL3ForwardingEnabled()).thenReturn(true);
+
+        bridgeConfigurationManagerImpl.prepareNode(node);
+
+        // TODO This test doesn't verify anything
+    }
+
+    @Test
+    public void testCreateLocalNetwork() throws Exception {
+        NeutronNetwork neutronNetworkMock = mock(NeutronNetwork.class, RETURNS_MOCKS);
+        String networkTypes[] = {"vlan", "vxlan", "gre"};
+        BridgeConfigurationManagerImpl bridgeConfigurationManagerImplSpy =
+                spy(new BridgeConfigurationManagerImpl());
+        bridgeConfigurationManagerImplSpy.setConfigurationService(configurationService);
+        bridgeConfigurationManagerImplSpy.setSouthbound(southbound);
+
+        for (String networkType : networkTypes) {
+            when(neutronNetworkMock.getProviderNetworkType()).thenReturn(networkType);
+            when(southbound.readOvsdbNode(any(Node.class))).thenReturn(node);
+
+            doAnswer(new Answer<Boolean>() {
+                @Override
+                public Boolean answer(InvocationOnMock invocation) {
+                    return Boolean.TRUE;
+                }
+            }).when(bridgeConfigurationManagerImplSpy).isNodeVlanReady(any(Node.class), any(Node.class), any(NeutronNetwork.class));
+
+            doAnswer(new Answer<Boolean>() {
+                @Override
+                public Boolean answer(InvocationOnMock invocation) {
+                    return Boolean.TRUE;
+                }
+            }).when(bridgeConfigurationManagerImplSpy).isNodeTunnelReady(any(Node.class), any(Node.class));
+
+            assertTrue("bridgeConfigMock.isNodeVlanReady is not true",
+                    bridgeConfigurationManagerImplSpy.isNodeVlanReady(node, node, neutronNetworkMock));
+            assertTrue("bridgeConfigMock.isNodeTunnelReady is not true",
+                    bridgeConfigurationManagerImplSpy.isNodeTunnelReady(node, node));
+
+            assertTrue("Error, isCreated is not true for " + networkType,
+                    bridgeConfigurationManagerImplSpy.createLocalNetwork(node, neutronNetworkMock));
+            switch (networkType) {
+                case "vlan":
+                    verify(neutronNetworkMock, times(1)).getProviderNetworkType();
+                    break;
+                case "vxlan":
+                    verify(neutronNetworkMock, times(2)).getProviderNetworkType();
+                    break;
+                case "gre":
+                    verify(neutronNetworkMock, times(3)).getProviderNetworkType();
+                    break;
+            }
+            reset(neutronNetworkMock);
+            reset(node);
+            reset(bridgeConfigurationManagerImplSpy);
+        }
+    }
+
+    @Test
+    public void testGetPhysicalInterfaceName() throws Exception {
+        when(southbound.getOtherConfig(any(Node.class), Matchers.eq(OvsdbTables.OPENVSWITCH), anyString()))
+                .thenReturn(null)
+                .thenReturn(null)
+                .thenReturn(PROVIDER_MAPPINGS);
+        String networkNames[] = {PHYSNET1, PHYSNET2};
+        String interfaceNames[] = {ETH1, ETH2};
+
+        verifyNoMoreInteractions(configurationService);
+        when(configurationService.getDefaultProviderMapping()).thenReturn(PROVIDER_MAPPINGS_DEFAULT);
+
+        assertNull("Error, should not have found " + PHYSNET2 + ":" + ETH2,
+                bridgeConfigurationManagerImpl.getPhysicalInterfaceName(node, PHYSNET2));
+        assertEquals("Error, should have found " + PHYSNET1 + ":" + ETH1,
+                ETH1, bridgeConfigurationManagerImpl.getPhysicalInterfaceName(node, PHYSNET1));
+        for (int i = 0; i < networkNames.length; i++) {
+            assertEquals("Error, network: " + networkNames[i]
+                            + ", did not match interface: "+ interfaceNames[i],
+                    interfaceNames[i],
+                    bridgeConfigurationManagerImpl.getPhysicalInterfaceName(node, networkNames[i]));
+        }
+        assertNull(PHYSNET1, bridgeConfigurationManagerImpl.getPhysicalInterfaceName(node, PHYSNET3));
+        verify(configurationService, times(5)).getProviderMappingsKey();
+        verify(configurationService, times(2)).getDefaultProviderMapping();
+        verify(southbound, times(5)).getOtherConfig(any(Node.class), eq(OvsdbTables.OPENVSWITCH), anyString());
+    }
+
+    @Test
+    public void testGetAllPhysicalInterfaceNames() throws Exception {
+        when(southbound.getOtherConfig(any(Node.class), eq(OvsdbTables.OPENVSWITCH), anyString()))
+                .thenReturn(null)
+                .thenReturn(PROVIDER_MAPPINGS);
+
+        verifyNoMoreInteractions(configurationService);
+        when(configurationService.getDefaultProviderMapping()).thenReturn(PROVIDER_MAPPINGS_DEFAULT);
+
+        List<String> interfaces = bridgeConfigurationManagerImpl.getAllPhysicalInterfaceNames(node);
+        assertEquals("Error, should have found 1 interface", 1, interfaces.size());
+        assertTrue("Error, should have found " + ETH1, interfaces.contains(ETH1));
+        assertFalse("Error, should not have found " + ETH2, interfaces.contains(ETH2));
+        interfaces = bridgeConfigurationManagerImpl.getAllPhysicalInterfaceNames(node);
+        assertEquals("Error, should have found 2 interfaces", 2, interfaces.size());
+        assertTrue("Error, should have found " + ETH1, interfaces.contains(ETH1));
+        assertTrue("Error, should have found " + ETH1, interfaces.contains(ETH2));
+        assertFalse("Error, should not have found " + ETH3, interfaces.contains(ETH3));
+
+        verify(configurationService, times(2)).getProviderMappingsKey();
+        verify(configurationService, times(1)).getDefaultProviderMapping();
+        verify(southbound, times(2)).getOtherConfig(any(Node.class), eq(OvsdbTables.OPENVSWITCH), anyString());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        NetworkingProviderManager networkingProviderManager = mock(NetworkingProviderManager.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(ConfigurationService.class, configurationService);
+        ServiceHelper.overrideGlobalInstance(NetworkingProviderManager.class, networkingProviderManager);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        bridgeConfigurationManagerImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
+        assertEquals("Error, did not return the correct object", getField("networkingProviderManager"), networkingProviderManager);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = BridgeConfigurationManagerImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(bridgeConfigurationManagerImpl);
+    }
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/ConfigurationServiceImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/ConfigurationServiceImplTest.java
new file mode 100644 (file)
index 0000000..ef94073
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.config.ConfigProperties;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link ConfigurationServiceImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ConfigurationServiceImplTest {
+
+    @InjectMocks private ConfigurationServiceImpl configurationServiceImpl;
+
+    @Mock private Southbound southbound;
+
+    private static final String ADDRESS = "127.0.0.1";
+    private static final String IS_FOWARDING_ENABLE = "yes";
+
+    /**
+     * Test method {@link ConfigurationServiceImpl#getTunnelEndPoint(Node)}
+     */
+    @Test
+    public void testGetTunnelEndPoint() throws Exception {
+        when(southbound.getOtherConfig(any(Node.class), any(OvsdbTables.class), anyString())).thenReturn(ADDRESS);
+
+        assertEquals("Error, did not return the expected address",  ADDRESS, configurationServiceImpl.getTunnelEndPoint(mock(Node.class)).getHostAddress());
+    }
+
+    @Test
+    public void testGetOpenFlowVersion() {
+        assertEquals("Error, did not return the correct OF version", Constants.OPENFLOW13, configurationServiceImpl.getOpenflowVersion(mock(Node.class)));
+    }
+
+    @Test
+    public void testIsL3FowardingEnable() {
+        ConfigProperties.overrideProperty("ovsdb.l3.fwd.enabled", IS_FOWARDING_ENABLE);
+
+        assertTrue("Error, l3 fowarding should be activated", configurationServiceImpl.isL3ForwardingEnabled());
+    }
+
+    /**
+     * Test method {@link ConfigurationServiceImpl#getDefaultGatewayMacAddress(Node)}
+     */
+    @Test
+    public void testGetDefaultGatewayMacAddress(){
+        Node node = mock(Node.class);
+        NodeId nodeId = mock(NodeId.class);
+
+        when(node.getNodeId()).thenReturn(nodeId);
+        when(nodeId.getValue()).thenReturn("nodeIdValue");
+        ConfigProperties.overrideProperty("ovsdb.l3gateway.mac." + node.getNodeId().getValue(), "gateway");
+
+        assertEquals("Error, did not return the defaultGatewayMacAddress of the node", "gateway",
+                configurationServiceImpl.getDefaultGatewayMacAddress(node));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        configurationServiceImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = ConfigurationServiceImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(configurationServiceImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpServiceTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpServiceTest.java
new file mode 100644 (file)
index 0000000..100716e
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2016 NEC Corporation 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+/**
+ * Unit test for {@link DistributedArpService}
+ */
+@PrepareForTest({ServiceHelper.class, InetAddress.class, DistributedArpService.class})
+@RunWith(PowerMockRunner.class)
+public class DistributedArpServiceTest {
+
+    @Mock private DistributedArpService distributedArpService;
+    /**
+     * ID used for testing different scenarios.
+     */
+    private static final String ID = "45";
+    /**
+     * IP used for testing different scenarios.
+     */
+    private static final String IP = "127.0.0.1";
+    /**
+     * MALFORM_IP used for testing different scenarios.
+     */
+    private static final String MALFORM_IP = "127.0.0.1.5";
+    /**
+     * INTF_NAME used for testing different scenarios.
+     */
+    private static final String INTF_NAME = "br-int";
+    /**
+     * UUID used for testing different scenarios.
+     */
+    private static final String UUID = "7da709ff-397f-4778-a0e8-994811272fdb";
+    /**
+     * FIXED_IP_ADDRESS used for testing different scenarios.
+     */
+    private static final String FIXED_IP_ADDRESS = "192.168.1.0";
+    /**
+     * MAC_ADDRESS used for testing different scenarios.
+     */
+    private static final String MAC_ADDRESS = "00:00:5E:00:02:01";
+    /**
+     * MAC_ADDRESS_2 used for testing different scenarios.
+     */
+    private static final String MAC_ADDRESS_2 = "00:00:5E:00:02:02";
+    /**
+     * PORT_INT used for testing different scenarios.
+     */
+    private static final String PORT_INT = "port_int";
+
+    @Before
+    public void setUp() throws Exception{
+        distributedArpService = PowerMockito.spy(new DistributedArpService());
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#handlePortEvent} is called
+     * and then checks that the port event process to write arp rules for neutron ports based on action.
+     */
+    @Test
+    public void testHandlePortEvent() throws Exception {
+        NeutronPort neutronPortOne = PowerMockito.mock(NeutronPort.class);
+        NeutronPort neutronPortTwo = PowerMockito.mock(NeutronPort.class);
+        List<NeutronPort> list_neutronPort = new ArrayList<>();
+        list_neutronPort.add(neutronPortOne);
+        list_neutronPort.add(neutronPortTwo);
+        INeutronPortCRUD neutronPortCache = PowerMockito.mock(INeutronPortCRUD.class);
+        MemberModifier.field(DistributedArpService.class, "neutronPortCache").set(distributedArpService, neutronPortCache);
+        PowerMockito.when(neutronPortCache, "getAllPorts").thenReturn(list_neutronPort);
+
+        // Suppress the called to these functions.
+        MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "handleNeutronPortForArp", NeutronPort.class, Action.class));
+
+        //Case 1: Delete Action.
+        Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPortOne, Action.DELETE);
+        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("handleNeutronPortForArp", any(NeutronPort.class), eq(Action.DELETE));
+
+        //Case 2: Add Action.
+        Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPortOne, Action.ADD);
+        PowerMockito.verifyPrivate(distributedArpService, times(2)).invoke("handleNeutronPortForArp", any(NeutronPort.class), eq(Action.ADD));
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#programStaticRuleStage1} is called
+     * and then checks that the arp rules are added/removed based on neutron port event.
+     */
+    @Test
+    public void testProgramStaticRuleStage1() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "programStaticRuleStage2", Long.class, String.class, String.class, String.class, Action.class));
+        PowerMockito.when(distributedArpService, "programStaticRuleStage2", anyLong(), anyString(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
+
+        //Case 1: Add Action.
+        Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage1", Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.ADD);
+        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("programStaticRuleStage2", anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
+
+        //Case 2: Delete Action.
+        Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage1", Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.DELETE);
+        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("programStaticRuleStage2", anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#programStaticRuleStage2} is called
+     * and then checks that the arp rules are programmed by invoke arpProvider.
+     */
+    @Test
+    public void testProgramStaticRuleStage2() throws Exception {
+        //Case 1: StatusCode BADREQUEST.
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.BADREQUEST), Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage2", Long.valueOf(45), PORT_INT, MAC_ADDRESS, MALFORM_IP, Action.ADD));
+        PowerMockito.mockStatic(InetAddress.class);
+        InetAddress inetAddress = mock(InetAddress.class);
+        PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
+
+        //Case 2: StatusCode SUCCESS.
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage2", Long.valueOf(45), PORT_INT, MAC_ADDRESS, IP, Action.DELETE));
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#handleNeutornPortForArp} is called
+     * and then checks that the arp rules are written based on event for neutron port.
+     */
+    @Test
+    public void testHandleNeutornPortForArp() throws Exception {
+        Neutron_IPs neutronIp = mock(Neutron_IPs.class);
+        when(neutronIp.getIpAddress()).thenReturn(FIXED_IP_ADDRESS);
+        List<Neutron_IPs> neutronIps = new ArrayList<>();
+        neutronIps.add(neutronIp);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getNetworkUUID()).thenReturn(UUID);
+        when(neutronPort.getMacAddress()).thenReturn(MAC_ADDRESS_2);
+        when(neutronPort.getFixedIPs()).thenReturn(neutronIps);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn(ID);
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(mock(Node.class));
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        MemberModifier.field(DistributedArpService.class, "tenantNetworkManager").set(distributedArpService, tenantNetworkManager);
+        when(tenantNetworkManager.isTenantNetworkPresentInNode(any(Node.class), eq(ID))).thenReturn(true);
+        PowerMockito.doReturn(15L).when(distributedArpService, "getDatapathIdIntegrationBridge", any(Node.class));
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        MemberModifier.field(DistributedArpService.class, "neutronNetworkCache").set(distributedArpService, neutronNetworkCache);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        when(nodeCacheManager.getBridgeNodes()).thenReturn(nodes);
+        MemberModifier.field(DistributedArpService.class, "nodeCacheManager").set(distributedArpService, nodeCacheManager);
+        MemberModifier.field(DistributedArpService.class, "flgDistributedARPEnabled").set(distributedArpService, true);
+
+        // Suppress the called to these functions.
+        MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "programStaticRuleStage1", Long.class, String.class, String.class, String.class, Action.class));
+
+        //Case 1: Add Action.
+        Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, Action.ADD);
+        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("getDatapathIdIntegrationBridge", any(Node.class));
+        Mockito.verify(distributedArpService, times(1)).programStaticRuleStage1(anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
+
+        //Case 2: Delete Action.
+        Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, Action.DELETE);
+        PowerMockito.verifyPrivate(distributedArpService, times(2)).invoke("getDatapathIdIntegrationBridge", any(Node.class));
+        Mockito.verify(distributedArpService, times(1)).programStaticRuleStage1(anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#getDatapathIdIntegrationBridge} is called
+     * and then checks the node integration bridge, then return its datapathID.
+     */
+    @Test
+    public void testGetDatapathIdIntegrationBridge() throws Exception {
+        Southbound southbound = mock(Southbound.class);
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+
+        MemberModifier.field(DistributedArpService.class, "southbound").set(distributedArpService, southbound);
+        MemberModifier.field(DistributedArpService.class, "configurationService").set(distributedArpService, configurationService);
+
+        PowerMockito.when(southbound.getBridge(any(Node.class), anyString())).thenReturn(mock(OvsdbBridgeAugmentation.class));
+        PowerMockito.when(configurationService.getIntegrationBridgeName()).thenReturn("");
+        PowerMockito.when(southbound.getDataPathId(any(Node.class))).thenReturn(45L);
+
+        //Assert check for correct Dp Id.
+        assertEquals("Error, did not return the correct Dpid", 45, (long)Whitebox.invokeMethod(distributedArpService, "getDatapathIdIntegrationBridge", mock(Node.class)));
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#processInterfaceEvent} is called
+     * and then checks that the event is processing.
+     */
+    @Test
+    public void testProcessInterfaceEvent() throws Exception {
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        PowerMockito.doNothing().when(distributedArpService).handlePortEvent(any(NeutronPort.class), any(Action.class));
+        // init instance variables.
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        MemberModifier.field(DistributedArpService.class, "tenantNetworkManager").set(distributedArpService , tenantNetworkManager);
+
+        // Mock variables
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        OvsdbTerminationPointAugmentation intf = mock(OvsdbTerminationPointAugmentation.class);
+        when(intf.getName()).thenReturn(INTF_NAME);
+
+        when(tenantNetworkManager.getTenantPort(intf)).thenReturn(neutronPort);
+
+        //Case 1: Add Action.
+        distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, Action.ADD);
+        Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.ADD);
+
+        //Case 2: Delete Action.
+        distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, Action.DELETE);
+        Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.DELETE);
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#setDependencies} is called
+     * and then checks the object instances.
+     */
+    @Test
+    public void testSetDependencies() throws Exception {
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        ArpProvider arpProvider = mock(ArpProvider.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
+        ServiceHelper.overrideGlobalInstance(ConfigurationService.class, configurationService);
+        ServiceHelper.overrideGlobalInstance(ArpProvider.class, arpProvider);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        distributedArpService.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
+        assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
+        assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    /**
+     * Test that checks if @{DistributedArpService#setDependencies} is called
+     * and then checks the object instances.
+     */
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
+        distributedArpService.setDependencies(iNeutronNetworkCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
+
+        INeutronPortCRUD iNeutronPortCRUD = mock(INeutronPortCRUD.class);
+        distributedArpService.setDependencies(iNeutronPortCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), iNeutronPortCRUD);
+
+        ArpProvider arpProvider = mock(ArpProvider.class);
+        distributedArpService.setDependencies(arpProvider);
+        assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = DistributedArpService.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(distributedArpService);
+    }
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/EventDispatcherImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/EventDispatcherImplTest.java
new file mode 100644 (file)
index 0000000..c793abb
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.Random;
+import java.util.concurrent.BlockingQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link EventDispatcherImpl}
+ */
+public class EventDispatcherImplTest {
+
+    private EventDispatcherImpl eventDispatcherImpl = new EventDispatcherImpl();
+
+    private AbstractHandler handler = mock(AbstractHandler.class);
+    private ServiceReference<?> ref = mock(ServiceReference.class);
+
+    private AbstractEvent.HandlerType handlerTypeObject = AbstractEvent.HandlerType.NEUTRON_FLOATING_IP;
+
+    @Before
+    public void setUp() {
+        Random r = new Random();
+
+        when(ref.getProperty(org.osgi.framework.Constants.SERVICE_ID)).thenReturn(r.nextLong());
+        when(ref.getProperty(Constants.EVENT_HANDLER_TYPE_PROPERTY)).thenReturn(handlerTypeObject);
+    }
+
+    /**
+     * Test methods {@link EventDispatcherImpl#eventHandlerRemoved(ServiceReference)}
+     * and {@link EventDispatcherImpl#eventHandlerAdded(ServiceReference, AbstractHandler)}
+     */
+    @Test
+    public void testHandlerAddedAndRemoved() throws Exception{
+        AbstractHandler[] handlers = ( AbstractHandler[]) getField("handlers");
+
+        assertNotEquals("Error, handler should be null", handlers[handlerTypeObject.ordinal()], handler);
+
+        eventDispatcherImpl.eventHandlerAdded(ref, handler);
+
+        assertEquals("Error, did not return the added handler", handlers[handlerTypeObject.ordinal()], handler);
+
+        eventDispatcherImpl.eventHandlerRemoved(ref);
+
+        assertNull("Error, handler should be null as it has just been removed", handlers[handlerTypeObject.ordinal()]);
+    }
+
+    /**
+     * Test method {@link EventDispatcherImpl#enqueueEvent(AbstractEvent)}
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testEnqueueEvent() throws Exception{
+        BlockingQueue<AbstractEvent> events = (BlockingQueue<AbstractEvent>) getField("events");
+
+        assertEquals("Error, did not return the expected size, nothing has been added yet", 0, events.size());
+
+        eventDispatcherImpl.eventHandlerAdded(ref, handler);
+
+        AbstractEvent mockEvent = mock(AbstractEvent.class);
+        when(mockEvent.getHandlerType()).thenReturn(handlerTypeObject);
+        final int numEnqueues = 4;
+        for (int i = 0; i < numEnqueues; i++) {
+            eventDispatcherImpl.enqueueEvent(mockEvent);
+        }
+
+        // Because events are processed in a different thread, this is a race
+        // We want to ensure that all the events were enqueued; so the sum of
+        // what's been processed and what's still in the queue must equal the
+        // number of events we enqueued
+        eventDispatcherImpl.stop();
+        verify(handler, times(numEnqueues - events.size())).processEvent(mockEvent);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = EventDispatcherImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(eventDispatcherImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3AdapterTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3AdapterTest.java
new file mode 100644 (file)
index 0000000..658fcf4
--- /dev/null
@@ -0,0 +1,994 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.Status;
+import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+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.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+/**
+ * Unit test for {@link NeutronL3Adapter}
+ */
+@PrepareForTest({ServiceHelper.class, InetAddress.class, NeutronL3Adapter.class, DistributedArpService.class})
+@RunWith(PowerMockRunner.class)
+public class NeutronL3AdapterTest {
+
+    @Mock private NeutronL3Adapter neutronL3Adapter;
+    @Mock private DistributedArpService distributedArpService;
+
+    private static final String ID = "45";
+    private static final String IP = "127.0.0.1";
+    private static final String MALFORM_IP = "127.0.0.1.5";
+    private static final String INTF_NAME = "br-int";
+    private static final String EXTERNAL_ROUTER_MAC_UPDATE = "";
+    private static final String UUID = "7da709ff-397f-4778-a0e8-994811272fdb";
+    private static final String FIXED_IP_ADDRESS = "192.168.1.0";
+    private static final String FLOATING_IP_ADDRESS = "192.168.1.1";
+    private static final String OWNER_ROUTER_INTERFACE = "network:router_interface";
+    private static final String OWNER_FLOATING_IP = "network:floatingip";
+    private static final String MAC_ADDRESS = "00:00:5E:00:02:01";
+    private static final String MAC_ADDRESS_2 = "00:00:5E:00:02:02";
+    private static final String PORT_INT = "port_int";
+    private static final String SEG_ID = "2";
+    private static final String CIDR = "192.168.100.0/24";
+    private static final String OFPort = "OFPort|45";
+    private static final String IP_MASK = "127.0.0.1/32";
+
+    @SuppressWarnings("rawtypes")
+    private Class floatingIpClass;
+    private Object floatingIpObject;
+
+    @Before
+    public void setUp() throws Exception{
+        neutronL3Adapter = PowerMockito.mock(NeutronL3Adapter.class, Mockito.CALLS_REAL_METHODS);
+        Whitebox.setInternalState(neutronL3Adapter, "distributedArpService", distributedArpService);
+        // init instance variables
+        MemberModifier.field(NeutronL3Adapter.class, "enabled").set(neutronL3Adapter, true);
+
+        // floating ip (nested private class from NeutronL3Adapter)
+        floatingIpClass = Whitebox.getInnerClassType(NeutronL3Adapter.class, "FloatIpData");
+        floatingIpObject = createFloatingIpObject();
+    }
+
+    @Test
+    public void testUpdateExternalRouterMac() throws Exception {
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "flushExistingIpRewrite"));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "rebuildExistingIpRewrite"));
+
+        neutronL3Adapter.updateExternalRouterMac(EXTERNAL_ROUTER_MAC_UPDATE);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("flushExistingIpRewrite");
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("rebuildExistingIpRewrite");
+    }
+
+    @Test
+    public void testhandleNeutronSubnetEvent() throws Exception {
+        Map<String,NeutronNetwork> networkCleanupCache = new HashMap<>();
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        // Mock variables
+        MemberModifier.field(NeutronL3Adapter.class, "networkCleanupCache").set(neutronL3Adapter , networkCleanupCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronNetworkCache").set(neutronL3Adapter , neutronNetworkCache);
+        neutronL3Adapter.handleNeutronSubnetEvent(mock(NeutronSubnet.class), Action.ADD);
+    }
+
+    @Test
+    public void testHandleNeutronPortEvent() throws Exception {
+        Map<String, NeutronRouter_Interface> subnetIdToRouterInterfaceCache = new HashMap<>();
+        Map<String,NeutronPort> portCleanupCache = new HashMap<>();
+        // Mock variables
+        Neutron_IPs neutronIP = mock(Neutron_IPs.class);
+        when(neutronIP.getSubnetUUID()).thenReturn(UUID);
+        List<Neutron_IPs> list_neutronIP = new ArrayList<>();
+        list_neutronIP.add(neutronIP);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getDeviceOwner()).thenReturn(OWNER_ROUTER_INTERFACE);
+        when(neutronPort.getFixedIPs()).thenReturn(list_neutronIP);
+        INeutronFloatingIPCRUD neutronFloatingIpCache = mock(INeutronFloatingIPCRUD.class);
+
+        // init instance variables
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , mock(INeutronPortCRUD.class));
+        subnetIdToRouterInterfaceCache.put(UUID, mock(NeutronRouter_Interface.class));
+        MemberModifier.field(NeutronL3Adapter.class, "subnetIdToRouterInterfaceCache").set(neutronL3Adapter , subnetIdToRouterInterfaceCache);
+        MemberModifier.field(NeutronL3Adapter.class, "portCleanupCache").set(neutronL3Adapter , portCleanupCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronFloatingIpCache").set(neutronL3Adapter , neutronFloatingIpCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "updateL3ForNeutronPort", NeutronPort.class, boolean.class));
+        Mockito.doNothing().when(neutronL3Adapter).handleNeutronRouterInterfaceEvent(any(NeutronRouter.class), any(NeutronRouter_Interface.class), any(Action.class));
+
+        neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.ADD);
+        Mockito.verify(neutronL3Adapter).handleNeutronRouterInterfaceEvent(any(NeutronRouter.class), any(NeutronRouter_Interface.class), eq(Action.ADD));
+
+        when(neutronPort.getDeviceOwner()).thenReturn("");
+        neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.ADD);
+        Mockito.verify(neutronL3Adapter, times(2)).handleNeutronRouterInterfaceEvent(any(NeutronRouter.class), any(NeutronRouter_Interface.class), eq(Action.ADD));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("updateL3ForNeutronPort", any(NeutronPort.class), eq(false));
+
+        neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.DELETE);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("updateL3ForNeutronPort", any(NeutronPort.class), eq(true));
+    }
+
+    @Test
+    public void testhandleNeutronRouterEvent() throws Exception {
+        // Nothing to be done here
+        neutronL3Adapter.handleNeutronRouterEvent(mock(NeutronRouter.class), Action.ADD);
+    }
+
+    @Test
+    public void testHandleNeutronRouterInterfaceEvent() throws Exception {
+        // Mock variables
+        NeutronRouter_Interface neutronRouterInterface = mock(NeutronRouter_Interface.class);
+        when(neutronRouterInterface.getPortUUID()).thenReturn(UUID);
+        when(neutronRouterInterface.getSubnetUUID()).thenReturn(UUID);
+
+        Neutron_IPs neutronIP = mock(Neutron_IPs.class);
+        when(neutronIP.getSubnetUUID()).thenReturn(UUID);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        List<Neutron_IPs> list_neutronIP = new ArrayList<>();
+        list_neutronIP.add(neutronIP);
+        when(neutronPort.getFixedIPs()).thenReturn(list_neutronIP);
+        List<NeutronPort> list_neutronPort = new ArrayList<>();
+        list_neutronPort.add(neutronPort);
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        when(neutronPortCache.getAllPorts()).thenReturn(list_neutronPort);
+
+        // init instance variables
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , neutronPortCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowsForNeutronRouterInterface", NeutronRouter_Interface.class, Boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "updateL3ForNeutronPort", NeutronPort.class, boolean.class));
+
+        neutronL3Adapter.handleNeutronRouterInterfaceEvent(mock(NeutronRouter.class), neutronRouterInterface, Action.ADD);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForNeutronRouterInterface", any(NeutronRouter_Interface.class), eq(false));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("updateL3ForNeutronPort", any(NeutronPort.class), eq(false));
+
+        neutronL3Adapter.handleNeutronRouterInterfaceEvent(mock(NeutronRouter.class), neutronRouterInterface, Action.DELETE);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForNeutronRouterInterface", any(NeutronRouter_Interface.class), eq(true));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("updateL3ForNeutronPort", any(NeutronPort.class), eq(true));
+    }
+
+    @Test
+    public void testHandleNeutronFloatingIPEvent() throws Exception {
+        // Mock variables
+        NeutronFloatingIP neutronFloatingIP = mock(NeutronFloatingIP.class);
+        when(neutronFloatingIP.getFixedIPAddress()).thenReturn(FIXED_IP_ADDRESS);
+        when(neutronFloatingIP.getFloatingIPAddress()).thenReturn(FLOATING_IP_ADDRESS);
+        when(neutronFloatingIP.getID()).thenReturn(UUID);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowsForFloatingIPArpAdd", NeutronFloatingIP.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowsForFloatingIPInbound", NeutronFloatingIP.class, Action.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowsForFloatingIPOutbound", NeutronFloatingIP.class, Action.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowsForFloatingIPArpDelete", String.class));
+
+        neutronL3Adapter.handleNeutronFloatingIPEvent(neutronFloatingIP, Action.ADD);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForFloatingIPArpAdd", any(NeutronFloatingIP.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForFloatingIPInbound", any(NeutronFloatingIP.class), eq(Action.ADD));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForFloatingIPOutbound", any(NeutronFloatingIP.class), eq(Action.ADD));
+
+        neutronL3Adapter.handleNeutronFloatingIPEvent(neutronFloatingIP, Action.DELETE);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForFloatingIPArpDelete", anyString());
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForFloatingIPInbound", any(NeutronFloatingIP.class), eq(Action.DELETE));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForFloatingIPOutbound", any(NeutronFloatingIP.class), eq(Action.DELETE));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testProgramFlowsForFloatingIPInbound() throws Exception {
+        Map floatIpDataMapCache = new HashMap();
+
+        NeutronFloatingIP neutronFloatingIp = mock(NeutronFloatingIP.class);
+        when(neutronFloatingIp.getID()).thenReturn(ID);
+
+        // init instance variables
+        floatIpDataMapCache .put(ID, floatingIpObject);
+        MemberModifier.field(NeutronL3Adapter.class, "floatIpDataMapCache").set(neutronL3Adapter , floatIpDataMapCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programInboundIpRewriteStage1", Long.class, Long.class, String.class, String.class, String.class, Action.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForFloatingIPInbound", neutronFloatingIp, Action.ADD);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programInboundIpRewriteStage1", anyLong(), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testProgramFlowsForFloatingIPOutbound() throws Exception {
+        Map floatIpDataMapCache = new HashMap();
+
+        NeutronFloatingIP neutronFloatingIp = mock(NeutronFloatingIP.class);
+        when(neutronFloatingIp.getID()).thenReturn(ID);
+
+        // init instance variables
+        floatIpDataMapCache.put(ID, floatingIpObject);
+        MemberModifier.field(NeutronL3Adapter.class, "floatIpDataMapCache").set(neutronL3Adapter , floatIpDataMapCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage1", floatingIpClass, Action.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForFloatingIPOutbound", neutronFloatingIp, Action.ADD);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage1", any(floatingIpClass), eq(Action.ADD));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testFlushExistingIpRewrite() throws Exception {
+        Map floatIpDataMapCache = new HashMap();
+
+        // init instance variables
+        floatIpDataMapCache.put(ID, floatingIpObject);
+        MemberModifier.field(NeutronL3Adapter.class, "floatIpDataMapCache").set(neutronL3Adapter , floatIpDataMapCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage1", floatingIpClass, Action.class));
+        PowerMockito.doReturn(floatIpDataMapCache.values()).when(neutronL3Adapter, "getAllFloatingIPsWithMetadata");
+        Whitebox.invokeMethod(neutronL3Adapter, "flushExistingIpRewrite");
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage1", any(floatingIpClass), eq(Action.DELETE));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testRebuildExistingIpRewrite() throws Exception {
+        Map floatIpDataMapCache = new HashMap();
+
+        // init instance variables
+        floatIpDataMapCache.put(ID, floatingIpObject);
+        MemberModifier.field(NeutronL3Adapter.class, "floatIpDataMapCache").set(neutronL3Adapter , floatIpDataMapCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage1", floatingIpClass, Action.class));
+
+        PowerMockito.doReturn(floatIpDataMapCache.values()).when(neutronL3Adapter, "getAllFloatingIPsWithMetadata");
+        Whitebox.invokeMethod(neutronL3Adapter, "rebuildExistingIpRewrite");
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage1", any(floatingIpClass), eq(Action.ADD));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testProgramFlowsForFloatingIPArpAdd() throws Exception {
+        Map<String, Pair> neutronPortToDpIdCache = new HashMap<>();
+        Map<String, String> networkIdToRouterMacCache = new HashMap<>();
+        Map floatIpDataMapCache = new HashMap();
+
+        NeutronFloatingIP neutronFloatingIP = mock(NeutronFloatingIP.class);
+        when(neutronFloatingIP.getFixedIPAddress()).thenReturn(FIXED_IP_ADDRESS);
+        when(neutronFloatingIP.getFloatingIPAddress()).thenReturn(FLOATING_IP_ADDRESS);
+        when(neutronFloatingIP.getPortUUID()).thenReturn(UUID);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getMacAddress()).thenReturn(MAC_ADDRESS);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn(ID);
+        when(neutronNetwork.getID()).thenReturn(ID);
+
+        // init instance variables
+        floatIpDataMapCache.put(ID, floatingIpObject);
+        neutronPortToDpIdCache.put(UUID, mock(Pair.class));
+        networkIdToRouterMacCache.put(ID, MAC_ADDRESS);
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        when(neutronPortCache.getPort(anyString())).thenReturn(neutronPort);
+        PowerMockito.doReturn(neutronPort).when(neutronL3Adapter, "findNeutronPortForFloatingIp", anyString());
+        PowerMockito.doReturn(15L).when(neutronL3Adapter, "findOFPortForExtPatch", anyLong());
+        MemberModifier.field(NeutronL3Adapter.class, "floatIpDataMapCache").set(neutronL3Adapter , floatIpDataMapCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortToDpIdCache").set(neutronL3Adapter , neutronPortToDpIdCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , neutronPortCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronNetworkCache").set(neutronL3Adapter , neutronNetworkCache);
+        MemberModifier.field(NeutronL3Adapter.class, "networkIdToRouterMacCache").set(neutronL3Adapter , networkIdToRouterMacCache);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "findNeutronPortForFloatingIp", String.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "findOFPortForExtPatch", Long.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForFloatingIPArpAdd", neutronFloatingIP);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("findNeutronPortForFloatingIp", anyString());
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("findOFPortForExtPatch", anyLong());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testProgramFlowsForFloatingIPArpDelete() throws Exception {
+        Map floatIpDataMapCache = new HashMap();
+
+     // init instance variables
+        floatIpDataMapCache.put(ID, floatingIpObject);
+        MemberModifier.field(NeutronL3Adapter.class, "floatIpDataMapCache").set(neutronL3Adapter , floatIpDataMapCache);
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForFloatingIPArpDelete", ID);
+    }
+
+    @Test
+    public void testFindNeutronPortForFloatingIp() throws Exception {
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getDeviceOwner()).thenReturn(OWNER_FLOATING_IP);
+        when(neutronPort.getDeviceID()).thenReturn(ID);
+        List<NeutronPort> list_neutronPort = new ArrayList<>();
+        list_neutronPort.add(neutronPort);
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        when(neutronPortCache.getAllPorts()).thenReturn(list_neutronPort);
+
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , neutronPortCache);
+
+        assertEquals("Error, did not return the correct NeutronPort", neutronPort, Whitebox.invokeMethod(neutronL3Adapter, "findNeutronPortForFloatingIp", ID));
+    }
+
+    @Test
+    public void testFindOFPortForExtPatch() throws Exception {
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        when(configurationService.getPatchPortName(any(Pair.class))).thenReturn(PORT_INT);
+        MemberModifier.field(NeutronL3Adapter.class, "configurationService").set(neutronL3Adapter , configurationService);
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(mock(Node.class));
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        when(nodeCacheManager.getBridgeNodes()).thenReturn(nodes);
+        MemberModifier.field(NeutronL3Adapter.class, "nodeCacheManager").set(neutronL3Adapter , nodeCacheManager);
+        Southbound southbound = mock(Southbound.class);
+        when(southbound.getDataPathId(any(Node.class))).thenReturn(Long.valueOf(ID));
+        OvsdbTerminationPointAugmentation terminationPointOfBridge = mock(OvsdbTerminationPointAugmentation.class);
+        when(terminationPointOfBridge.getOfport()).thenReturn(Long.valueOf(ID));
+        when(southbound.getTerminationPointOfBridge(any(Node.class), anyString())).thenReturn(terminationPointOfBridge);
+        MemberModifier.field(NeutronL3Adapter.class, "southbound").set(neutronL3Adapter , southbound);
+
+        assertEquals("Error, did not return the correct NeutronPort", Long.valueOf(ID), Whitebox.invokeMethod(neutronL3Adapter, "findOFPortForExtPatch", Long.valueOf(ID)));
+    }
+
+    @Test
+    public void testHandleNeutronNetworkEvent() throws Exception {
+        // Nothing to be done here
+        Map<String,NeutronNetwork> networkCleanupCache = new HashMap<>();
+        // Mock variables
+        MemberModifier.field(NeutronL3Adapter.class, "networkCleanupCache").set(neutronL3Adapter , networkCleanupCache);
+        Whitebox.invokeMethod(neutronL3Adapter, "handleNeutronNetworkEvent", mock(NeutronNetwork.class), Action.ADD);
+    }
+
+    @Test
+    public void testHandleInterfaceEvent() throws Exception {
+        Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache = new HashMap<>();
+        // init instance variables
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        MemberModifier.field(NeutronL3Adapter.class, "tenantNetworkManager").set(neutronL3Adapter , tenantNetworkManager);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortToDpIdCache").set(neutronL3Adapter , neutronPortToDpIdCache);
+
+        // Mock variables
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        OvsdbTerminationPointAugmentation intf = mock(OvsdbTerminationPointAugmentation.class);
+        when(intf.getInterfaceUuid()).thenReturn(mock(Uuid.class));
+        when(intf.getName()).thenReturn(INTF_NAME);
+
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getPortUUID()).thenReturn(UUID);
+
+        when(tenantNetworkManager.getTenantPort(intf)).thenReturn(neutronPort);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "getDpidForIntegrationBridge", Node.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "handleInterfaceEventAdd", String.class, Long.class, Uuid.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "handleInterfaceEventDelete", OvsdbTerminationPointAugmentation.class, Long.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "storePortInCleanupCache", NeutronPort.class));
+
+        PowerMockito.when(neutronL3Adapter, "getDpidForIntegrationBridge", any(Node.class)).thenReturn(45L);
+        Mockito.doNothing().when(neutronL3Adapter).handleNeutronPortEvent(any(NeutronPort.class), any(Action.class));
+
+        neutronL3Adapter.handleInterfaceEvent(node, intf, mock(NeutronNetwork.class), Action.ADD);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("getDpidForIntegrationBridge", any(Node.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("handleInterfaceEventAdd", any(String.class), anyLong(), any(Uuid.class));
+        Mockito.verify(neutronL3Adapter).handleNeutronPortEvent(neutronPort, Action.ADD);
+
+        neutronL3Adapter.handleInterfaceEvent(node, intf, mock(NeutronNetwork.class), Action.DELETE);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("handleInterfaceEventDelete", any(OvsdbTerminationPointAugmentation.class), anyLong());
+        Mockito.verify(neutronL3Adapter).handleNeutronPortEvent(neutronPort, Action.DELETE);
+    }
+
+    @Test
+    public void testHandleInterfaceEventAdd() throws Exception {
+        Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache = new HashMap<>();
+        // init instance variables
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortToDpIdCache").set(neutronL3Adapter , neutronPortToDpIdCache);
+        int temp = neutronPortToDpIdCache.size();
+
+        Whitebox.invokeMethod(neutronL3Adapter, "handleInterfaceEventAdd", "", Long.valueOf(5), mock(Uuid.class));
+
+        assertEquals("Error, did not add the port", temp+1, neutronPortToDpIdCache.size());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testHandleInterfaceEventDelete() throws Exception {
+        Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache = new HashMap<>();
+        OvsdbTerminationPointAugmentation intf = mock(OvsdbTerminationPointAugmentation.class);
+        Uuid uuid = mock(Uuid.class);
+        when(intf.getInterfaceUuid()).thenReturn(uuid );
+        Pair<Long, Uuid> pair = mock(Pair.class);
+        when(pair.getRight()).thenReturn(uuid);
+
+        // init instance variables
+        neutronPortToDpIdCache.put("key", pair);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortToDpIdCache").set(neutronL3Adapter , neutronPortToDpIdCache);
+        int temp = neutronPortToDpIdCache.size();
+
+        Whitebox.invokeMethod(neutronL3Adapter, "handleInterfaceEventDelete", intf, Long.valueOf(ID));
+
+        assertEquals("Error, did not remove the port", temp-1, neutronPortToDpIdCache.size());
+    }
+
+    @Test
+    public void testUpdateL3ForNeutronPort() throws Exception {
+        Map<String, String> networkIdToRouterMacCache = new HashMap<>();
+
+        Neutron_IPs neutronIp = mock(Neutron_IPs.class);
+        when(neutronIp.getIpAddress()).thenReturn(FIXED_IP_ADDRESS);
+        List<Neutron_IPs> neutronIps = new ArrayList<>();
+        neutronIps.add(neutronIp);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getNetworkUUID()).thenReturn(UUID);
+        when(neutronPort.getMacAddress()).thenReturn(MAC_ADDRESS_2);
+        when(neutronPort.getFixedIPs()).thenReturn(neutronIps);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn(ID);
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(mock(Node.class));
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        MemberModifier.field(NeutronL3Adapter.class, "tenantNetworkManager").set(neutronL3Adapter , tenantNetworkManager);
+        when(tenantNetworkManager.isTenantNetworkPresentInNode(any(Node.class), eq(ID))).thenReturn(true);
+        PowerMockito.doReturn(15L).when(neutronL3Adapter, "getDpidForIntegrationBridge", any(Node.class));
+
+        // init instance variables
+        networkIdToRouterMacCache .put(UUID, MAC_ADDRESS);
+        MemberModifier.field(NeutronL3Adapter.class, "networkIdToRouterMacCache").set(neutronL3Adapter , networkIdToRouterMacCache);
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronNetworkCache").set(neutronL3Adapter , neutronNetworkCache);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        when(nodeCacheManager.getBridgeNodes()).thenReturn(nodes);
+        MemberModifier.field(NeutronL3Adapter.class, "nodeCacheManager").set(neutronL3Adapter , nodeCacheManager);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "getDpidForIntegrationBridge", Node.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programL3ForwardingStage1", Node.class, Long.class, String.class, String.class, String.class, Action.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "updateL3ForNeutronPort", neutronPort, false);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("getDpidForIntegrationBridge", any(Node.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programL3ForwardingStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "updateL3ForNeutronPort", neutronPort, true);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(2)).invoke("getDpidForIntegrationBridge", any(Node.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programL3ForwardingStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
+    }
+
+    @Test
+    public void testProgramL3ForwardingStage1() throws Exception {
+
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        // Suppress the called to these functions
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programL3ForwardingStage2", Node.class, Long.class, String.class, String.class, String.class, Action.class));
+
+        // init instance variables
+        PowerMockito.when(neutronL3Adapter, "programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD)).thenReturn(new Status(StatusCode.SUCCESS));
+        PowerMockito.when(neutronL3Adapter, "programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE)).thenReturn(new Status(StatusCode.SUCCESS));
+
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programL3ForwardingStage1", node, Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.ADD);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
+
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programL3ForwardingStage1", node, Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.DELETE);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
+    }
+
+    @Test
+    public void testProgramL3ForwardingStage2() throws Exception {
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.BADREQUEST), Whitebox.invokeMethod(neutronL3Adapter, "programL3ForwardingStage2", node, Long.valueOf(45), SEG_ID, MAC_ADDRESS, MALFORM_IP, Action.ADD));
+
+        PowerMockito.mockStatic(InetAddress.class);
+        InetAddress inetAddress = mock(InetAddress.class);
+        PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
+
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programL3ForwardingStage2", node, Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.ADD));
+    }
+
+    @Test
+    public void testProgramFlowsForNeutronRouterInterface() throws Exception {
+        Map<String, String> networkIdToRouterMacCache = new HashMap<>();
+        Map<String, List<Neutron_IPs>> networkIdToRouterIpListCache = new HashMap<>();
+        Map<String, NeutronRouter_Interface> subnetIdToRouterInterfaceCache = new HashMap<>();
+
+        NeutronRouter_Interface intf = mock(NeutronRouter_Interface.class);
+        when(intf.getPortUUID()).thenReturn(UUID);
+        when(intf.getSubnetUUID()).thenReturn(UUID);
+        Neutron_IPs neutronIp = mock(Neutron_IPs.class);
+        when(neutronIp.getIpAddress()).thenReturn(FIXED_IP_ADDRESS);
+        List<Neutron_IPs> ips = new ArrayList<>();
+        ips.add(neutronIp);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getMacAddress()).thenReturn(MAC_ADDRESS);
+        when(neutronPort.getFixedIPs()).thenReturn(ips);
+        when(neutronPort.getNetworkUUID()).thenReturn(UUID);
+        NeutronSubnet neutronSubnet = mock(NeutronSubnet.class);
+        when(neutronSubnet.getNetworkUUID()).thenReturn(UUID);
+        when(neutronSubnet.getGatewayIP()).thenReturn(IP);
+        when(neutronSubnet.getCidr()).thenReturn("cidr");
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn(ID);
+        when(neutronNetwork.getRouterExternal()).thenReturn(false); //might change that to true
+        when(neutronNetwork.getNetworkUUID()).thenReturn(UUID);
+        NeutronRouter neutronRouter = mock(NeutronRouter.class);
+
+        Node node = mock(Node.class);
+        List<Node> nodes = new ArrayList<>();
+        nodes.add(node);
+
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "getDpidForIntegrationBridge", Node.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowsForNeutronRouterInterfacePair", Node.class, Long.class, NeutronRouter_Interface.class, NeutronRouter_Interface.class, NeutronNetwork.class, String.class, String.class, String.class, int.class, Action.class, Boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programFlowForNetworkFromExternal", Node.class, Long.class, String.class, String.class, String.class, int.class, Action.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programIpRewriteExclusionStage1", Node.class, Long.class, String.class, String.class, Action.class));
+
+        // init instance variables
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        PowerMockito.when(neutronPortCache.getPort(anyString())).thenReturn(neutronPort);
+        PowerMockito.when(neutronPortCache.getAllPorts()).thenReturn(new ArrayList<NeutronPort>());
+        INeutronSubnetCRUD neutronSubnetCache = mock(INeutronSubnetCRUD.class);
+        PowerMockito.when(neutronSubnetCache.getSubnet(anyString())).thenReturn(neutronSubnet);
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        PowerMockito.when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        PowerMockito.when(nodeCacheManager.getBridgeNodes()).thenReturn(nodes);
+        MemberModifier.field(NeutronL3Adapter.class, "networkIdToRouterMacCache").set(neutronL3Adapter , networkIdToRouterMacCache);
+        MemberModifier.field(NeutronL3Adapter.class, "networkIdToRouterIpListCache").set(neutronL3Adapter , networkIdToRouterIpListCache);
+        MemberModifier.field(NeutronL3Adapter.class, "subnetIdToRouterInterfaceCache").set(neutronL3Adapter , subnetIdToRouterInterfaceCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , neutronPortCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronSubnetCache").set(neutronL3Adapter , neutronSubnetCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronNetworkCache").set(neutronL3Adapter , neutronNetworkCache);
+        MemberModifier.field(NeutronL3Adapter.class, "nodeCacheManager").set(neutronL3Adapter , nodeCacheManager);
+        PowerMockito.when(neutronL3Adapter, "getDpidForIntegrationBridge", any(Node.class)).thenReturn(45L);
+
+        int networkIdToRouterMacCacheSize, networkIdToRouterIpListCacheSize, subnetIdToRouterInterfaceCacheSize;
+        networkIdToRouterMacCacheSize = networkIdToRouterMacCache.size();
+        networkIdToRouterIpListCacheSize = networkIdToRouterIpListCache.size();
+        subnetIdToRouterInterfaceCacheSize = subnetIdToRouterInterfaceCache.size();
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForNeutronRouterInterface", intf, false);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("getDpidForIntegrationBridge", any(Node.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForNeutronRouterInterfacePair", any(Node.class), anyLong(), any(NeutronRouter_Interface.class), any(NeutronRouter_Interface.class), any(NeutronNetwork.class), anyString(), anyString(), anyString(), anyInt(), eq(Action.ADD), anyBoolean());
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowForNetworkFromExternal", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyInt(), eq(Action.ADD));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programIpRewriteExclusionStage1", any(Node.class), anyLong(), anyString(), anyString(), eq(Action.ADD));
+        assertEquals("Error, did not add the RouterMac", networkIdToRouterMacCacheSize, networkIdToRouterMacCache.size() -1);
+        assertEquals("Error, did not add the RouterIP", networkIdToRouterIpListCacheSize, networkIdToRouterIpListCache.size() -1);
+        assertEquals("Error, did not add the RouterInterface", subnetIdToRouterInterfaceCacheSize, subnetIdToRouterInterfaceCache.size() -1);
+
+        networkIdToRouterMacCache.put(UUID, MAC_ADDRESS);
+        networkIdToRouterIpListCache.put(UUID, ips);
+        subnetIdToRouterInterfaceCache.put(UUID, intf);
+        networkIdToRouterMacCacheSize = networkIdToRouterMacCache.size();
+        networkIdToRouterIpListCacheSize = networkIdToRouterIpListCache.size();
+        subnetIdToRouterInterfaceCacheSize = subnetIdToRouterInterfaceCache.size();
+
+        Whitebox.invokeMethod(neutronL3Adapter, "handleNeutronRouterInterfaceEvent", neutronRouter, intf, Action.DELETE);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowsForNeutronRouterInterface", intf, true);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(2)).invoke("getDpidForIntegrationBridge", any(Node.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(2)).invoke("programFlowsForNeutronRouterInterfacePair", any(Node.class), anyLong(), any(NeutronRouter_Interface.class), any(NeutronRouter_Interface.class), any(NeutronNetwork.class), anyString(), anyString(), anyString(), anyInt(), eq(Action.DELETE), anyBoolean());
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programFlowForNetworkFromExternal", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyInt(), eq(Action.DELETE));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programIpRewriteExclusionStage1", any(Node.class), anyLong(), anyString(), anyString(), eq(Action.DELETE));
+        assertEquals("Error, did not remove the RouterMac", networkIdToRouterMacCacheSize, networkIdToRouterMacCache.size() +1);
+        assertEquals("Error, did not remove the RouterIP", networkIdToRouterIpListCacheSize, networkIdToRouterIpListCache.size() +1);
+        assertEquals("Error, did not remove the RouterInterface", subnetIdToRouterInterfaceCacheSize, subnetIdToRouterInterfaceCache.size() +1);
+    }
+
+    @Test
+    public void testProgramFlowForNetworkFromExternal() throws Exception {
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programRouterInterfaceStage1", Node.class, Long.class, String.class, String.class, String.class, String.class, int.class, Action.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowForNetworkFromExternal", mock(Node.class), Long.valueOf(12), "", "", "", 4, Action.ADD);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), any(Action.class));
+    }
+
+    @Test
+    public void testProgramFlowsForNeutronRouterInterfacePair() throws Exception {
+        NeutronRouter_Interface srcNeutronRouterInterface = mock(NeutronRouter_Interface.class);
+        when(srcNeutronRouterInterface.getSubnetUUID()).thenReturn(UUID);
+        when(srcNeutronRouterInterface.getID()).thenReturn(ID);
+        when(srcNeutronRouterInterface.getPortUUID()).thenReturn(UUID);
+        NeutronRouter_Interface dstNeutronRouterInterface = mock(NeutronRouter_Interface.class);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getTenantID()).thenReturn(ID);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn(ID);
+        Neutron_IPs ip = mock(Neutron_IPs.class);
+        when(ip.getIpAddress()).thenReturn(IP);
+        List<Neutron_IPs> ips = new ArrayList<>();
+        ips.add(ip);
+        ips.add(ip);
+        ips.add(ip);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getMacAddress()).thenReturn(MAC_ADDRESS);
+        when(neutronPort.getFixedIPs()).thenReturn(ips);
+        NeutronSubnet neutronSubnet = mock(NeutronSubnet.class);
+        when(neutronSubnet.getNetworkUUID()).thenReturn(UUID);
+        when(neutronSubnet.getCidr()).thenReturn(CIDR);
+
+        INeutronSubnetCRUD neutronSubnetCache = mock(INeutronSubnetCRUD.class);
+        PowerMockito.when(neutronSubnetCache.getSubnet(anyString())).thenReturn(neutronSubnet);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronSubnetCache").set(neutronL3Adapter , neutronSubnetCache);
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        PowerMockito.when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronNetworkCache").set(neutronL3Adapter , neutronNetworkCache);
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        PowerMockito.when(neutronPortCache.getPort(anyString())).thenReturn(neutronPort);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , neutronPortCache);
+
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programRouterInterfaceStage1", Node.class, Long.class, String.class, String.class, String.class, String.class, int.class, Action.class));
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "getMaskLenFromCidr", String.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForNeutronRouterInterfacePair", mock(Node.class), Long.valueOf(12), srcNeutronRouterInterface, dstNeutronRouterInterface, neutronNetwork, SEG_ID, MAC_ADDRESS, IP, 4, Action.ADD, false);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), any(Action.class));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programFlowsForNeutronRouterInterfacePair", mock(Node.class), Long.valueOf(12), srcNeutronRouterInterface, dstNeutronRouterInterface, neutronNetwork, SEG_ID, MAC_ADDRESS, IP, 4, Action.ADD, true);
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(2)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), any(Action.class));
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("getMaskLenFromCidr", anyString());
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(4)).invoke("programFlowsForNeutronRouterInterfacePair", any(Node.class), anyLong(), any(NeutronRouter_Interface.class), any(NeutronRouter_Interface.class), any(NeutronNetwork.class), anyString(), anyString(), anyString(), anyInt(), any(Action.class), eq(false)); //3 + 1 above
+    }
+
+    @Test
+    public void testProgramRouterInterfaceStage1() throws Exception {
+
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programRouterInterfaceStage2", Node.class, Long.class, String.class, String.class, String.class, String.class, int.class, Action.class));
+
+        PowerMockito.when(neutronL3Adapter, "programRouterInterfaceStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
+
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programRouterInterfaceStage1", node, Long.valueOf(12), SEG_ID, SEG_ID, MAC_ADDRESS, IP, 4, Action.ADD);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), eq(Action.ADD));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programRouterInterfaceStage1", node, Long.valueOf(12), SEG_ID, SEG_ID, MAC_ADDRESS, IP, 4, Action.DELETE);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), eq(Action.DELETE));
+    }
+
+    @Test
+    public void testProgramRouterInterfaceStage2() throws Exception {
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.BADREQUEST), Whitebox.invokeMethod(neutronL3Adapter, "programRouterInterfaceStage2", node, Long.valueOf(45), SEG_ID, SEG_ID , MAC_ADDRESS, MALFORM_IP, 4, Action.ADD));
+
+        PowerMockito.mockStatic(InetAddress.class);
+        InetAddress inetAddress = mock(InetAddress.class);
+        PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
+
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programRouterInterfaceStage2", node, Long.valueOf(45), SEG_ID, SEG_ID, MAC_ADDRESS, IP, 4, Action.ADD));
+
+    }
+
+    @Test
+    public void testProgramInboundIpRewriteStage1() throws Exception {
+
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programInboundIpRewriteStage2", Long.class, Long.class, String.class, String.class, String.class, Action.class));
+
+        PowerMockito.when(neutronL3Adapter, "programInboundIpRewriteStage2", anyLong(), anyLong(), anyString(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
+
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage1", Long.valueOf(12), Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.ADD);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programInboundIpRewriteStage2", anyLong(), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage1", Long.valueOf(12), Long.valueOf(12),PORT_INT, MAC_ADDRESS, IP, Action.DELETE);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programInboundIpRewriteStage2", anyLong(), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
+    }
+
+    @Test
+    public void testProgramInboundIpRewriteStage2() throws Exception {
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.BADREQUEST), Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage2", Long.valueOf(45), Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.ADD));
+
+        PowerMockito.mockStatic(InetAddress.class);
+        InetAddress inetAddress = mock(InetAddress.class);
+        PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
+
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage2", Long.valueOf(45), Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.ADD));
+    }
+
+    @Test
+    public void testProgramIpRewriteExclusionStage1() throws Exception {
+
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programIpRewriteExclusionStage2", Node.class, Long.class, String.class, String.class, Action.class));
+
+        PowerMockito.when(neutronL3Adapter, "programIpRewriteExclusionStage2", any(Node.class), anyLong(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
+
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programIpRewriteExclusionStage1", node, Long.valueOf(12), SEG_ID, CIDR, Action.ADD);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programIpRewriteExclusionStage2", any(Node.class), anyLong(), anyString(), anyString(), eq(Action.ADD));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programIpRewriteExclusionStage1", node, Long.valueOf(12), SEG_ID, CIDR, Action.DELETE);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programIpRewriteExclusionStage2", any(Node.class), anyLong(), anyString(), anyString(), eq(Action.DELETE));
+    }
+
+    @Test
+    public void testProgramIpRewriteExclusionStage2() throws Exception {
+        NodeId nodeId = mock(NodeId.class);
+        when(nodeId.getValue()).thenReturn(ID);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(nodeId);
+
+        assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programIpRewriteExclusionStage2", node, Long.valueOf(45), SEG_ID, CIDR, Action.ADD));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testProgramOutboundIpRewriteStage1() throws Exception{
+
+        MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage2", floatingIpClass, Action.class));
+
+        PowerMockito.when(neutronL3Adapter, "programOutboundIpRewriteStage2", any(floatingIpClass), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
+
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programOutboundIpRewriteStage1", floatingIpObject, Action.ADD);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage2", any(floatingIpClass), eq(Action.ADD));
+
+        Whitebox.invokeMethod(neutronL3Adapter, "programOutboundIpRewriteStage1", floatingIpObject, Action.DELETE);
+
+        PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage2", any(floatingIpClass), eq(Action.DELETE));
+    }
+
+    /*@Test
+    public void testPrepareProgramOutboundIpRewriteStage2() throws Exception {
+        assertEquals("Error, did not return the correct status code", new Status(StatusCode.BADREQUEST), Whitebox.invokeMethod(neutronL3Adapter, "programOutboundIpRewriteStage2", floatingIpObject, Action.ADD));
+
+        PowerMockito.mockStatic(InetAddress.class);
+        InetAddress inetAddress = mock(InetAddress.class);
+        PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
+
+        assertEquals("Error, did not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programOutboundIpRewriteStage2", floatingIpObject, Action.ADD));
+    }*/
+
+    @Test
+    public void testGetMaskLenFromCidr() throws Exception {
+        assertEquals("Error, did not return the correct mask", 32, (int) Whitebox.invokeMethod(neutronL3Adapter, "getMaskLenFromCidr", IP_MASK));
+    }
+
+    @Test
+    public void testGetDpidForIntegrationBridge() throws Exception {
+        Southbound southbound = mock(Southbound.class);
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+
+        MemberModifier.field(NeutronL3Adapter.class, "southbound").set(neutronL3Adapter , southbound);
+        MemberModifier.field(NeutronL3Adapter.class, "configurationService").set(neutronL3Adapter , configurationService);
+
+        PowerMockito.when(southbound.getBridge(any(Node.class), anyString())).thenReturn(mock(OvsdbBridgeAugmentation.class));
+        PowerMockito.when(configurationService.getIntegrationBridgeName()).thenReturn("");
+        PowerMockito.when(southbound.getDataPathId(any(Node.class))).thenReturn(45L);
+
+        assertEquals("Error, did not return the correct Dpid", 45L, (long) Whitebox.invokeMethod(neutronL3Adapter, "getDpidForIntegrationBridge", mock(Node.class)));
+    }
+
+    @Test
+    public void testencodeExcplicitOFPort() throws Exception {
+        assertEquals("Error, did not correctly encode the port", OFPort, NeutronL3Adapter.encodeExcplicitOFPort(45L));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        Map<String,NeutronNetwork> networkCleanupCache = new HashMap<>();
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        List <NeutronNetwork> neutronNetworkList = new ArrayList<NeutronNetwork>();
+        neutronNetworkList.add(neutronNetwork);
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(neutronNetworkList);
+
+        Map<String,NeutronPort> portCleanupCache = new HashMap<>();
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        List <NeutronPort> neutronPortList = new ArrayList<NeutronPort>();
+        neutronPortList.add(neutronPort);
+        when(neutronPortCache.getAllPorts()).thenReturn(neutronPortList);
+        // Mock variables
+        MemberModifier.field(NeutronL3Adapter.class, "networkCleanupCache").set(neutronL3Adapter , networkCleanupCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronNetworkCache").set(neutronL3Adapter , neutronNetworkCache);
+        MemberModifier.field(NeutronL3Adapter.class, "portCleanupCache").set(neutronL3Adapter , portCleanupCache);
+        MemberModifier.field(NeutronL3Adapter.class, "neutronPortCache").set(neutronL3Adapter , neutronPortCache);
+
+
+        when(neutronPort.getDeviceOwner()).thenReturn(OWNER_ROUTER_INTERFACE);
+        MemberModifier.field(NeutronL3Adapter.class, "portCleanupCache").set(neutronL3Adapter , portCleanupCache);
+
+
+
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        ConfigurationService configurationService = mock(ConfigurationService.class);
+        ArpProvider arpProvider = mock(ArpProvider.class);
+        DistributedArpService distributedArpService = mock(DistributedArpService.class);
+        InboundNatProvider inboundNatProvider = mock(InboundNatProvider.class);
+        OutboundNatProvider outboundNatProvider = mock(OutboundNatProvider.class);
+        RoutingProvider routingProvider = mock(RoutingProvider.class);
+        L3ForwardingProvider l3ForwardingProvider = mock(L3ForwardingProvider.class);
+        NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+        ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
+        ServiceHelper.overrideGlobalInstance(ConfigurationService.class, configurationService);
+        ServiceHelper.overrideGlobalInstance(ArpProvider.class, arpProvider);
+        ServiceHelper.overrideGlobalInstance(DistributedArpService.class, distributedArpService);
+        ServiceHelper.overrideGlobalInstance(InboundNatProvider.class, inboundNatProvider);
+        ServiceHelper.overrideGlobalInstance(OutboundNatProvider.class, outboundNatProvider);
+        ServiceHelper.overrideGlobalInstance(RoutingProvider.class, routingProvider);
+        ServiceHelper.overrideGlobalInstance(L3ForwardingProvider.class, l3ForwardingProvider);
+        ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        neutronL3Adapter.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getAbstractHandlerField("eventDispatcher"),
+                eventDispatcher);
+        assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
+        assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
+        assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
+        assertEquals("Error, did not return the correct object", getField("distributedArpService"), distributedArpService);
+        assertEquals("Error, did not return the correct object", getField("inboundNatProvider"), inboundNatProvider);
+        assertEquals("Error, did not return the correct object", getField("outboundNatProvider"), outboundNatProvider);
+        assertEquals("Error, did not return the correct object", getField("routingProvider"), routingProvider);
+        assertEquals("Error, did not return the correct object", getField("l3ForwardingProvider"), l3ForwardingProvider);
+        assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        MemberModifier.field(NeutronL3Adapter.class, "enabled").set(neutronL3Adapter , false);
+
+        INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
+        neutronL3Adapter.setDependencies(iNeutronNetworkCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
+
+        INeutronPortCRUD iNeutronPortCRUD = mock(INeutronPortCRUD.class);
+        neutronL3Adapter.setDependencies(iNeutronPortCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), iNeutronPortCRUD);
+
+        INeutronSubnetCRUD iNeutronSubnetCRUD = mock(INeutronSubnetCRUD.class);
+        neutronL3Adapter.setDependencies(iNeutronSubnetCRUD);
+        assertEquals("Error, did not return the correct object", getField("neutronSubnetCache"), iNeutronSubnetCRUD);
+
+        ArpProvider arpProvider = mock(ArpProvider.class);
+        neutronL3Adapter.setDependencies(arpProvider);
+        assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
+
+        InboundNatProvider inboundNatProvider = mock(InboundNatProvider.class);
+        neutronL3Adapter.setDependencies(inboundNatProvider);
+        assertEquals("Error, did not return the correct object", getField("inboundNatProvider"), inboundNatProvider);
+
+        OutboundNatProvider outboundNatProvider = mock(OutboundNatProvider.class);
+        neutronL3Adapter.setDependencies(outboundNatProvider);
+        assertEquals("Error, did not return the correct object", getField("outboundNatProvider"), outboundNatProvider);
+
+        RoutingProvider routingProvider = mock(RoutingProvider.class);
+        neutronL3Adapter.setDependencies(routingProvider);
+        assertEquals("Error, did not return the correct object", getField("routingProvider"), routingProvider);
+
+        L3ForwardingProvider l3ForwardingProvider = mock(L3ForwardingProvider.class);
+        neutronL3Adapter.setDependencies(l3ForwardingProvider);
+        assertEquals("Error, did not return the correct object", getField("l3ForwardingProvider"), l3ForwardingProvider);
+
+        MemberModifier.field(NeutronL3Adapter.class, "enabled").set(neutronL3Adapter , true);
+    }
+
+    private Object getAbstractHandlerField(String fieldName) throws Exception {
+        Field field = AbstractHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(neutronL3Adapter);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = NeutronL3Adapter.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(neutronL3Adapter);
+    }
+
+    @SuppressWarnings("rawtypes")
+    private Object createFloatingIpObject() throws Exception{
+        Class clazz = Whitebox.getInnerClassType(NeutronL3Adapter.class, "FloatIpData");
+        Constructor [] constructors = clazz.getConstructors();
+        Constructor c  = constructors[0];
+        return c.newInstance(neutronL3Adapter, 415L, 415L, "a", "b", "c", "d", "e");
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/NodeCacheManagerImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/NodeCacheManagerImplTest.java
new file mode 100644 (file)
index 0000000..0832db1
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.NodeCacheManagerEvent;
+import org.opendaylight.netvirt.openstack.netvirt.api.Action;
+import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link NodeCacheManagerImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class NodeCacheManagerImplTest {
+
+    @InjectMocks private NodeCacheManagerImpl nodeCacheManagerImpl;
+    @Spy private Map<Long, NodeCacheListener> handlers = Maps.newHashMap();
+
+    @Mock private Southbound southbound;
+
+    @Test
+    public void testProcessEvent() {
+        NodeCacheManagerEvent ev = mock(NodeCacheManagerEvent.class);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(mock(NodeId.class));
+        when(ev.getNode()).thenReturn(node);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        nodeCacheManagerImpl.processEvent(ev);
+        assertEquals("Error, did not delete the event", 1, nodeCacheManagerImpl.getNodes().size());
+
+        when(ev.getAction()).thenReturn(Action.DELETE);
+        nodeCacheManagerImpl.processEvent(ev);
+        assertEquals("Error, did not delete the event", 0, nodeCacheManagerImpl.getNodes().size());
+    }
+
+    @Test
+    public void testCacheListenerAddedAndRemoved() {
+        ServiceReference ref = mock(ServiceReference.class);
+        when(ref.getProperty(org.osgi.framework.Constants.SERVICE_ID)).thenReturn(1L);
+
+        // add
+        nodeCacheManagerImpl.cacheListenerAdded(ref, mock(NodeCacheListener.class));
+        assertEquals("Error, cacheListenerAdded() did not add any listener", 1, handlers.size());
+        // remove
+        nodeCacheManagerImpl.cacheListenerRemoved(ref);
+        assertEquals("Error, cacheListenerAdded() did not remove any listener", 0, handlers.size());
+    }
+
+    @Test
+    public void testGetOvsdbNodes() {
+        addItem();
+
+        when(southbound.extractOvsdbNode(any(Node.class))).thenReturn(mock(OvsdbNodeAugmentation.class));
+
+        assertEquals("Error, getOvsdbNodes() did not return the correct value", 1, nodeCacheManagerImpl.getOvsdbNodes().size());
+    }
+
+    @Test
+    public void testGetBridgeNodes() {
+        addItem();
+
+        when(southbound.getBridge(any(Node.class))).thenReturn(mock(OvsdbBridgeAugmentation.class));
+
+        assertEquals("Error, getBridgeNodes() did not return the correct value", 1, nodeCacheManagerImpl.getBridgeNodes().size());
+    }
+
+    @Test
+    public void testGetNodes() {
+        addItem();
+
+        assertEquals("Error, getNodes() did not return the correct value", 1, nodeCacheManagerImpl.getNodes().size());
+    }
+
+    private void addItem() {
+        NodeCacheManagerEvent ev = mock(NodeCacheManagerEvent.class);
+        Node node = mock(Node.class);
+        when(node.getNodeId()).thenReturn(mock(NodeId.class));
+        when(ev.getNode()).thenReturn(node);
+
+        when(ev.getAction()).thenReturn(Action.UPDATE);
+        nodeCacheManagerImpl.processEvent(ev);
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        Southbound southbound = mock(Southbound.class);
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+        ServiceHelper.overrideGlobalInstance(EventDispatcher.class, eventDispatcher);
+
+        nodeCacheManagerImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+        assertEquals("Error, did not return the correct object", getSuperField("eventDispatcher"), eventDispatcher);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = NodeCacheManagerImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(nodeCacheManagerImpl);
+    }
+
+    private Object getSuperField(String fieldName) throws Exception {
+        Field field = NodeCacheManagerImpl.class.getSuperclass().getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(nodeCacheManagerImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbInventoryServiceImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/OvsdbInventoryServiceImplTest.java
new file mode 100644 (file)
index 0000000..82a8484
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import java.util.Set;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
+
+/**
+ * Unit test for {@link NodeCacheManagerImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class OvsdbInventoryServiceImplTest {
+
+    @InjectMocks private OvsdbInventoryServiceImpl ovsdbInventoryServiceImpl = new OvsdbInventoryServiceImpl(mock(ProviderContext.class));
+
+
+    @Test
+    public void testListenerAdded() throws Exception{
+        Set<OvsdbInventoryListener> listeners = OvsdbInventoryServiceImpl.getOvsdbInventoryListeners();
+        OvsdbInventoryListener listener = mock(OvsdbInventoryListener.class);
+
+        ovsdbInventoryServiceImpl.listenerAdded(listener);
+        assertEquals("Error, did not add the listener", 1, listeners.size());
+
+        ovsdbInventoryServiceImpl.listenerRemoved(listener);
+        assertEquals("Error, did not delete the listener", 0, listeners.size());
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/ProviderNetworkManagerImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/ProviderNetworkManagerImplTest.java
new file mode 100644 (file)
index 0000000..46174b4
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link ProviderNetworkManagerImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ProviderNetworkManagerImplTest {
+
+    @InjectMocks private ProviderNetworkManagerImpl providerNetworkManagerImpl;
+
+    @Mock private OvsdbInventoryService ovsdbInventoryService;
+
+    @Spy private Map<Node, NetworkingProvider> nodeToProviderMapping = Maps.newHashMap();
+
+    /**
+     * Test method {@link ProviderNetworkManagerImpl#getProvider(Node)}
+     */
+    @Test
+    public void testGetProvider(){
+        // TODO test the method with no networkingProvider in the map
+        // Could not be done as ProviderEntry is a private inner class of ProviderNetworkManagerImpl
+        Node node = mock(Node.class);
+        NetworkingProvider networkingProvider = mock(NetworkingProvider.class);
+        nodeToProviderMapping.put(node, networkingProvider);
+        assertEquals("Error, did not return the networkingProvider of the specified node", networkingProvider, providerNetworkManagerImpl.getProvider(node));
+    }
+
+    /**
+     * Test methods {@link ProviderNetworkManagerImpl#providerRemoved(ServiceReference)}
+     * and {@link ProviderNetworkManagerImpl#providerAdded(ServiceReference, NetworkingProvider)}
+     */
+    @Test
+    public void testProviderAddedAndRemoved() throws Exception {
+        Map<?, ?> map = (HashMap<?, ?>) getField("providers");
+
+        ServiceReference<?> ref = mock(ServiceReference.class);
+        when(ref.getProperty(org.osgi.framework.Constants.SERVICE_ID)).thenReturn(1L);
+
+        providerNetworkManagerImpl.providerAdded(ref, mock(NetworkingProvider.class));
+
+        assertEquals("Error, providerAdded() did not add the provider", 1, map.size());
+
+        providerNetworkManagerImpl.providerRemoved(ref);
+
+        assertEquals("Error, providerRemoved() did not remove the provider", 0, map.size());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        OvsdbInventoryService ovsdbInventoryService = mock(OvsdbInventoryService.class);
+
+        ServiceHelper.overrideGlobalInstance(OvsdbInventoryService.class, ovsdbInventoryService);
+
+        providerNetworkManagerImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("ovsdbInventoryService"), ovsdbInventoryService);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = ProviderNetworkManagerImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(providerNetworkManagerImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImplTest.java
new file mode 100644 (file)
index 0000000..5e0b980
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015, 2016 Hewlett-Packard Enterprise 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.openstack.netvirt.impl;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+
+/**
+ * Unit test fort {@link SecurityGroupCacheManagerImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SecurityGroupCacheManagerImplTest {
+
+    @InjectMocks private SecurityGroupCacheManagerImpl securityGroupCacheManagerImpl;
+    @Mock private INeutronPortCRUD neutronPortCache;
+    @Mock private INeutronSecurityGroupCRUD securityGroupCache;
+    @Mock NeutronPort neutronPort_Vm1;
+    @Mock NeutronPort neutronPort_Vm2;
+    @Mock NeutronPort neutronPort_Vm3;
+    @Mock NeutronPort neutronPort_Vm4;
+    @Mock NeutronPort neutronPort_Vm5;
+    @Mock SecurityServicesManager securityServicesManager;
+    @Mock NeutronSecurityGroup neutronSecurityGroup_1;
+    @Mock NeutronSecurityGroup neutronSecurityGroup_2;
+    @Mock NeutronSecurityGroup neutronSecurityGroup_3;
+    @Mock NeutronSecurityRule neutronSecurityRule_1;
+    @Mock NeutronSecurityRule neutronSecurityRule_2;
+    @Mock NeutronSecurityRule neutronSecurityRule_3;
+    @Mock Neutron_IPs neutron_ip_1;
+    @Mock Neutron_IPs neutron_ip_2;
+    @Mock Neutron_IPs neutron_ip_3;
+    @Mock Neutron_IPs neutron_ip_4;
+    @Mock Neutron_IPs neutron_ip_5;
+
+    private static final String NEUTRON_PORT_ID_VM_1 = "neutronID_VM_1";
+    private static final String NEUTRON_PORT_ID_VM_2 = "neutronID_VM_2";
+    private static final String NEUTRON_PORT_ID_VM_3 = "neutronID_VM_3";
+    private static final String NEUTRON_PORT_ID_VM_4 = "neutronID_VM_4";
+    private static final String NEUTRON_PORT_ID_VM_5 = "neutronID_VM_5";
+    private static final String SECURITY_GROUP_ID_1 = "securityGroupId_1";
+    private static final String SECURITY_GROUP_ID_2 = "securityGroupId_2";
+    private static final String SECURITY_GROUP_ID_3 = "securityGroupId_3";
+    private static final List<Neutron_IPs> neutron_IPs_1 = new ArrayList<>();
+    private static final List<Neutron_IPs> neutron_IPs_2 = new ArrayList<>();
+    private static final List<Neutron_IPs> neutron_IPs_3 = new ArrayList<>();
+    private static final List<Neutron_IPs> neutron_IPs_4 = new ArrayList<>();
+    private static final List<Neutron_IPs> neutron_IPs_5 = new ArrayList<>();
+
+    @Before
+    public void setUp() throws Exception {
+
+        List<NeutronSecurityGroup> securityGroups_Vm_1 = new ArrayList<>();
+        securityGroups_Vm_1.add(neutronSecurityGroup_1);
+        List<NeutronSecurityGroup> securityGroups_Vm_2 = new ArrayList<>();
+        securityGroups_Vm_2.add(neutronSecurityGroup_2);
+        List<NeutronSecurityGroup> securityGroups_Vm_3 = new ArrayList<>();
+        securityGroups_Vm_3.add(neutronSecurityGroup_3);
+        List<NeutronSecurityRule> securityRule_1 = new ArrayList<>();
+        securityRule_1.add(neutronSecurityRule_1);
+        List<NeutronSecurityRule> securityRule_2 = new ArrayList<>();
+        securityRule_2.add(neutronSecurityRule_2);
+        List<NeutronSecurityRule> securityRule_3 = new ArrayList<>();
+        securityRule_3.add(neutronSecurityRule_3);
+
+        neutron_IPs_1.add(neutron_ip_1);
+        neutron_IPs_2.add(neutron_ip_2);
+        neutron_IPs_3.add(neutron_ip_3);
+        neutron_IPs_4.add(neutron_ip_4);
+        neutron_IPs_5.add(neutron_ip_5);
+
+        when(neutronPort_Vm1.getID()).thenReturn(NEUTRON_PORT_ID_VM_1);
+        when(neutronPort_Vm2.getID()).thenReturn(NEUTRON_PORT_ID_VM_2);
+        when(neutronPort_Vm3.getID()).thenReturn(NEUTRON_PORT_ID_VM_3);
+        when(neutronPort_Vm4.getID()).thenReturn(NEUTRON_PORT_ID_VM_4);
+        when(neutronPort_Vm5.getID()).thenReturn(NEUTRON_PORT_ID_VM_5);
+        when(neutronPort_Vm1.getSecurityGroups()).thenReturn(securityGroups_Vm_1);
+        when(neutronPort_Vm2.getSecurityGroups()).thenReturn(securityGroups_Vm_1);
+        when(neutronPort_Vm3.getSecurityGroups()).thenReturn(securityGroups_Vm_3);
+        when(neutronPort_Vm4.getSecurityGroups()).thenReturn(securityGroups_Vm_1);
+        when(neutronPort_Vm5.getSecurityGroups()).thenReturn(securityGroups_Vm_3);
+        when(neutronSecurityGroup_1.getSecurityRules()).thenReturn(securityRule_1);
+        when(neutronSecurityGroup_2.getSecurityRules()).thenReturn(securityRule_2);
+        when(neutronSecurityGroup_3.getSecurityRules()).thenReturn(securityRule_3);
+        when(neutronSecurityGroup_1.getSecurityGroupUUID()).thenReturn(SECURITY_GROUP_ID_1);
+        when(neutronSecurityGroup_2.getSecurityGroupUUID()).thenReturn(SECURITY_GROUP_ID_2);
+        when(neutronSecurityGroup_3.getSecurityGroupUUID()).thenReturn(SECURITY_GROUP_ID_3);
+        when(neutronSecurityRule_1.getSecurityRemoteGroupID()).thenReturn(SECURITY_GROUP_ID_1);
+        when(neutronSecurityRule_3.getSecurityRemoteGroupID()).thenReturn(SECURITY_GROUP_ID_2);
+        when(neutronPort_Vm1.getFixedIPs()).thenReturn(neutron_IPs_1);
+        when(neutronPort_Vm2.getFixedIPs()).thenReturn(neutron_IPs_2);
+        when(neutronPort_Vm3.getFixedIPs()).thenReturn(neutron_IPs_3);
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(neutronPort_Vm1);
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_2))).thenReturn(neutronPort_Vm2);
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_3))).thenReturn(neutronPort_Vm3);
+    }
+
+    /**
+     * Remote Cache is empty a new port is added.
+     */
+    @Test
+    public void testPortAddedWithNoRemoteSGInCache() {
+        securityGroupCacheManagerImpl.portAdded(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_1);
+        verify(securityServicesManager, times(0)).syncSecurityRule(any(NeutronPort.class), any(NeutronSecurityRule.class), any(Neutron_IPs.class),anyBoolean());
+    }
+
+    /**
+     * Remote Cache is empty a new port is removed.
+     */
+    @Test
+    public void testPortRemovedWithNoRemoteSGInCache() {
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_1);
+        securityGroupCacheManagerImpl.portRemoved(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_1);
+        verify(securityServicesManager, times(0)).syncSecurityRule(any(NeutronPort.class), any(NeutronSecurityRule.class), any(Neutron_IPs.class),anyBoolean());
+    }
+
+    /**
+     * neutronSecurityGroup_1 has a rule which has neutronSecurityGroup_1 as remote SG.
+     * A port with neutronSecurityGroup_1 is present in cache and new one is added.
+     */
+    @Test
+    public void testPortAddedWithSelfInCache() {
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_1);
+        securityGroupCacheManagerImpl.portAdded(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_1);
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_2);
+        securityGroupCacheManagerImpl.portAdded(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_2);
+        verify(securityServicesManager, times(1)).syncSecurityRule(eq(neutronPort_Vm1), eq(neutronSecurityRule_1), eq(neutron_ip_2),eq(true));
+    }
+
+    /**
+     * neutronSecurityGroup_1 has a rule which has neutronSecurityGroup_1 as remote SG.
+     * Two port with neutronSecurityGroup_1 is present in cache and  one of them is removed.
+     */
+    @Test
+    public void testPortRemovedWithSelfInCache() {
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_1);
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_2);
+        securityGroupCacheManagerImpl.portRemoved(SECURITY_GROUP_ID_1, NEUTRON_PORT_ID_VM_2);
+        verify(securityServicesManager, times(1)).syncSecurityRule(eq(neutronPort_Vm1), eq(neutronSecurityRule_1), eq(neutron_ip_2),eq(false));
+    }
+
+    /**
+     * neutronSecurityGroup_3 has a rule which has neutronSecurityGroup_2 as remote SG.
+     * A port with neutronSecurityGroup_3 is present in cache. A new port is added with
+     * neutronSecurityGroup_2 as security group.
+     */
+    @Test
+    public void testPortAddedWithCidrInCache() {
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3);
+        securityGroupCacheManagerImpl.portAdded(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_2);
+        verify(securityServicesManager, times(1)).syncSecurityRule(eq(neutronPort_Vm3), eq(neutronSecurityRule_3), eq(neutron_ip_2),eq(true));
+    }
+
+    /**
+     * neutronSecurityGroup_3 has a rule which has neutronSecurityGroup_2 as remote SG.
+     * A port with neutronSecurityGroup_3 is present in cache. A  port with
+     * neutronSecurityGroup_2 as security group is removed..
+     */
+    @Test
+    public void testPortRemovedWithCidrInCache() {
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3);
+        securityGroupCacheManagerImpl.portRemoved(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_2);
+        verify(securityServicesManager, times(1)).syncSecurityRule(eq(neutronPort_Vm3), eq(neutronSecurityRule_3), eq(neutron_ip_2),eq(false));
+    }
+
+    /**
+     *  A port is removed from the cache.
+     */
+    @Test
+    public void testPortRemovedFromCache() {
+        securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3);
+        securityGroupCacheManagerImpl.removeFromCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3);
+        securityGroupCacheManagerImpl.portRemoved(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_2);
+        verify(securityServicesManager, times(0)).syncSecurityRule(any(NeutronPort.class), any(NeutronSecurityRule.class), any(Neutron_IPs.class),anyBoolean());
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImplTest.java
new file mode 100644 (file)
index 0000000..d4444fb
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+        .OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link SecurityServicesImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SecurityServicesImplTest {
+
+    @InjectMocks private SecurityServicesImpl securityServicesImpl;
+    @Mock
+    INeutronNetworkCRUD neutronNetworkCache;
+    @Mock private INeutronPortCRUD neutronPortCache;
+    @Mock private INeutronSubnetCRUD subNetCache;
+    @Mock private Southbound southbound;
+    @Mock private ConfigurationService configurationService;
+    @Mock NeutronNetwork neutronNetwork;
+    @Mock NeutronPort neutronPort_Vm1;
+    @Mock NeutronPort neutronPort_Vm2;
+    @Mock NeutronPort neutronPort_Vm3;
+    @Mock NeutronSecurityGroup neutronSecurityGroup_1;
+    @Mock NeutronSecurityGroup neutronSecurityGroup_2;
+    @Mock NeutronSecurityGroup neutronSecurityGroup_3;
+    @Mock NeutronSecurityRule neutronSecurityRule_1;
+    @Mock NeutronSecurityRule neutronSecurityRule_2;
+    @Mock NeutronSecurityRule neutronSecurityRule_3;
+    @Mock  NeutronPort neutronPort_Dhcp;
+    @Mock Neutron_IPs neutron_ip_1;
+    @Mock Neutron_IPs neutron_ip_2;
+    @Mock Neutron_IPs neutron_ip_3;
+    @Mock NeutronSubnet subnet;
+    @Mock Node node;
+    @Mock OvsdbTerminationPointAugmentation tp;
+    @Mock IngressAclProvider ingressAclService;
+    @Mock EgressAclProvider egressAclService;
+    @Mock NeutronL3Adapter neutronL3Adapter;
+
+    private static final String NEUTRON_PORT_ID_VM_1 = "neutronID_VM_1";
+    private static final String NEUTRON_PORT_ID_VM_2 = "neutronID_VM_2";
+    private static final String NEUTRON_PORT_ID_VM_3 = "neutronID_VM_3";
+    private static final String NEUTRON_PORT_ID_DHCP = "neutronID_VM_DHCP";
+    private static final String SECURITY_GROUP_ID_1 = "securityGroupId_1";
+    private static final String SECURITY_GROUP_ID_2 = "securityGroupId_2";
+    private static final String SECURITY_GROUP_ID_3 = "securityGroupId_3";
+    private static final String DEVICE_OWNER_VM = "compute";
+    private static final String DEVICE_OWNER_DHCP = "dhcp";
+    private static final String SUBNET_UUID = "subnet_uuid";
+    private static final List<Neutron_IPs> neutron_IPs_1 = new ArrayList<>();
+    private static final List<Neutron_IPs> neutron_IPs_2 = new ArrayList<>();
+    private static final List<Neutron_IPs> neutron_IPs_3 = new ArrayList<>();
+
+    @Before
+    public void setUp(){
+        List<NeutronSecurityGroup> securityGroups_1 = new ArrayList<>();
+        securityGroups_1.add(neutronSecurityGroup_1);
+        List<NeutronSecurityGroup> securityGroups_2 = new ArrayList<>();
+        securityGroups_2.add(neutronSecurityGroup_2);
+        List<NeutronSecurityGroup> securityGroups_3 = new ArrayList<>();
+        securityGroups_3.add(neutronSecurityGroup_3);
+        List<NeutronSecurityRule> securityRule_1 = new ArrayList<>();
+        securityRule_1.add(neutronSecurityRule_1);
+        List<NeutronSecurityRule> securityRule_2 = new ArrayList<>();
+        securityRule_1.add(neutronSecurityRule_2);
+        List<NeutronSecurityRule> securityRule_3 = new ArrayList<>();
+        securityRule_1.add(neutronSecurityRule_3);
+
+        neutron_IPs_1.add(neutron_ip_1);
+        neutron_IPs_2.add(neutron_ip_2);
+        neutron_IPs_3.add(neutron_ip_3);
+
+        when(neutronPort_Vm1.getID()).thenReturn(NEUTRON_PORT_ID_VM_1);
+        when(neutronPort_Vm2.getID()).thenReturn(NEUTRON_PORT_ID_VM_2);
+        when(neutronPort_Vm3.getID()).thenReturn(NEUTRON_PORT_ID_VM_3);
+        when(neutronPort_Vm1.getSecurityGroups()).thenReturn(securityGroups_1);
+        when(neutronPort_Vm2.getSecurityGroups()).thenReturn(securityGroups_2);
+        when(neutronPort_Vm3.getSecurityGroups()).thenReturn(securityGroups_3);
+        when(neutronSecurityGroup_1.getSecurityRules()).thenReturn(securityRule_1);
+        when(neutronSecurityGroup_2.getSecurityRules()).thenReturn(securityRule_2);
+        when(neutronSecurityGroup_3.getSecurityRules()).thenReturn(securityRule_3);
+        when(neutronSecurityGroup_1.getSecurityGroupUUID()).thenReturn(SECURITY_GROUP_ID_1);
+        when(neutronSecurityGroup_2.getSecurityGroupUUID()).thenReturn(SECURITY_GROUP_ID_2);
+        when(neutronSecurityGroup_3.getSecurityGroupUUID()).thenReturn(SECURITY_GROUP_ID_3);
+        when(neutronPort_Vm1.getDeviceOwner()).thenReturn(DEVICE_OWNER_VM);
+        when(neutronPort_Vm2.getDeviceOwner()).thenReturn(DEVICE_OWNER_VM);
+        when(neutronPort_Vm3.getDeviceOwner()).thenReturn(DEVICE_OWNER_VM);
+        when(neutronPort_Dhcp.getDeviceOwner()).thenReturn(DEVICE_OWNER_DHCP);
+        when(neutronPort_Vm1.getFixedIPs()).thenReturn(neutron_IPs_1);
+        when(neutronPort_Vm2.getFixedIPs()).thenReturn(neutron_IPs_2);
+        when(neutronPort_Vm3.getFixedIPs()).thenReturn(neutron_IPs_3);
+        when(neutron_ip_1.getSubnetUUID()).thenReturn(SUBNET_UUID);
+        List<NeutronPort> portList = new ArrayList<>();
+        portList.add(neutronPort_Vm1);
+        portList.add(neutronPort_Dhcp);
+        when(subnet.getPortsInSubnet()).thenReturn(portList);
+
+        List<Node> nodeList = new ArrayList<>();
+        nodeList.add(node);
+        List<OvsdbTerminationPointAugmentation> tpList = new ArrayList<>();
+        tpList.add(tp);
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), eq("iface-id"))).thenReturn(NEUTRON_PORT_ID_VM_1);
+        when(southbound.readOvsdbTopologyNodes()).thenReturn(nodeList);
+        when(southbound.getBridgeNode(any(Node.class), anyString())).thenReturn(node);
+        when(southbound.getTerminationPointsOfBridge(node)).thenReturn(tpList);
+        when(southbound.getDataPathId(node)).thenReturn(1L);
+        when(southbound.getBridgeName(node)).thenReturn("br-int");
+        when(southbound.getOFPort(any(OvsdbTerminationPointAugmentation.class))).thenReturn(2L);
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class),eq("attached-mac"))).thenReturn("attached-mac");
+        when(configurationService.getIntegrationBridgeName()).thenReturn("br-int");
+        when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn("1000");
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(neutronPort_Vm1);
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_DHCP))).thenReturn(neutronPort_Dhcp);
+        when(neutronPortCache.getAllPorts()).thenReturn(portList);
+        when(subNetCache.getSubnet(eq(SUBNET_UUID))).thenReturn(subnet);
+    }
+
+    /**
+     * Test method {@link SecurityServicesImpl#isPortSecurityReady(OvsdbTerminationPointAugmentation)}
+     */
+    @Test
+    public void testIsPortSecurityReady(){
+        assertTrue("Error, did not return expected boolean for isPortSecurityReady", securityServicesImpl.isPortSecurityReady(mock(OvsdbTerminationPointAugmentation.class)));
+    }
+
+    /**
+     * Test method {@link SecurityServicesImpl#getSecurityGroupInPortList(OvsdbTerminationPointAugmentation)}
+     */
+    @Test
+    public void testSecurityGroupInPort(){
+        assertEquals("Error, did not return the good neutronSecurityGroup of securityGroups",
+                     neutronSecurityGroup_1, securityServicesImpl.getSecurityGroupInPortList(mock(OvsdbTerminationPointAugmentation.class)).get(0));
+    }
+
+    /**
+     * Test getDhcpServerPort returning a valid port.
+     */
+    @Test
+    public void testGetDhcpServerPort() {
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,neutronPort_Dhcp);
+    }
+
+    /**
+     * Test getDhcpServerPort with null port id returned by the southbound.
+     */
+    @Test
+    public void testGetDhcpServerPortWithNullPortId() {
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(null);
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getDhcpServerPort with port not present in cache.
+     */
+    @Test
+    public void testGetDhcpServerPortWithNullPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(null);
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getDhcpServerPort with a dhcp port as the input port.
+     */
+    @Test
+    public void testGetDhcpServerPortWithDhcpPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(neutronPort_Dhcp);
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,neutronPort_Dhcp);
+    }
+
+    /**
+     * Test getDhcpServerPort with a dhcp port with fixed ip null
+     * for the input port..
+     */
+    @Test
+    public void testGetDhcpServerPortWithFixedIpNull() {
+        when(neutronPort_Vm1.getFixedIPs()).thenReturn(null);
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getDhcpServerPort with a dhcp port with fixed ip empty
+     * for the input port.
+     */
+    @Test
+    public void testGetDhcpServerPortWithFixedIpEmpty() {
+        when(neutronPort_Vm1.getFixedIPs()).thenReturn(new ArrayList<Neutron_IPs>());
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getDhcpServerPort with a dhcp port with no port in subnet.
+     */
+    @Test
+    public void testGetDhcpServerPortWithNoPortinSubnet() {
+        when(subnet.getPortsInSubnet()).thenReturn(new ArrayList<NeutronPort>());
+        NeutronPort dhcpPort = securityServicesImpl.getDhcpServerPort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getNeutronPortFromDhcpIntf with port not present in cache.
+     */
+    @Test
+    public void testGetNeutronPortFromDhcpIntfWithNullPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(null);
+        NeutronPort dhcpPort = securityServicesImpl.getNeutronPortFromDhcpIntf(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getNeutronPortFromDhcpIntf with port id returned null
+     * from the southbound.
+     */
+    @Test
+    public void testGetNeutronPortFromDhcpIntfWithNullPortId() {
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(null);
+        NeutronPort dhcpPort = securityServicesImpl.getNeutronPortFromDhcpIntf(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test getNeutronPortFromDhcpIntf valid
+     */
+    @Test
+    public void testGetNeutronPortFromDhcpIntfWithDhcpPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(neutronPort_Dhcp);
+        NeutronPort dhcpPort = securityServicesImpl.getNeutronPortFromDhcpIntf(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,neutronPort_Dhcp);
+    }
+
+    /**
+     * Test getNeutronPortFromDhcpIntf with the port passed
+     * a vm port.
+     */
+    @Test
+    public void testGetNeutronPortFromDhcpIntfWithVmPort() {
+        NeutronPort dhcpPort = securityServicesImpl.getNeutronPortFromDhcpIntf(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(dhcpPort,null);
+    }
+
+    /**
+     * Test isComputePort with the port passed a vm port.
+     */
+    @Test
+    public void testIsComputePortWithComputePort() {
+        boolean isComputePort = securityServicesImpl.isComputePort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(isComputePort,true);
+    }
+
+    /**
+     * Test isComputePort with the port passed a dhcp port.
+     */
+    @Test
+    public void testIsComputePortWithDhcpPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(neutronPort_Dhcp);
+        boolean isComputePort = securityServicesImpl.isComputePort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(isComputePort,false);
+    }
+
+    /**
+     * Test isComputePort with port id null from southbound.
+     */
+    @Test
+    public void testIsComputePortWithNullPortId() {
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(null);
+        boolean isComputePort = securityServicesImpl.isComputePort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(isComputePort,false);
+    }
+
+    /**
+     * Test isComputePort with port not present in cache.
+     */
+    @Test
+    public void testIsComputePortWithNullPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(null);
+        boolean isComputePort = securityServicesImpl.isComputePort(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(isComputePort,false);
+    }
+
+    /**
+     * Test getIpAddressList valid.
+     */
+    @Test
+    public void testGetIpAddressList() {
+        List<Neutron_IPs> ipList = securityServicesImpl.getIpAddressList(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(ipList,neutron_IPs_1);
+    }
+
+    /**
+     * Test getIpAddressList with port not present in cache..
+     */
+    @Test
+    public void testGetIpAddressListWithNullPort() {
+        when(neutronPortCache.getPort(eq(NEUTRON_PORT_ID_VM_1))).thenReturn(null);
+        List<Neutron_IPs> ipList = securityServicesImpl.getIpAddressList(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(ipList,null);
+    }
+
+
+    /**
+     * Test getIpAddressList  with port id null from southbound.
+     */
+    @Test
+    public void testGetIpAddressListWithNullPortId() {
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(null);
+        List<Neutron_IPs> ipList = securityServicesImpl.getIpAddressList(mock(OvsdbTerminationPointAugmentation.class));
+        assertEquals(ipList,null);
+    }
+
+    /**
+     * Test getVmListForSecurityGroup valid.
+     */
+    @Test
+    public void testGetVmListForSecurityGroup() {
+        Map<String,NeutronPort> portMap = new HashMap<>();
+        portMap.put("Uuid1",neutronPort_Vm1);
+        portMap.put("Uuid2",neutronPort_Vm2);
+        portMap.put("Uuid3",neutronPort_Vm3);
+        portMap.put("Uuid4",neutronPort_Dhcp);
+        when(neutronL3Adapter.getPortCleanupCache()).thenReturn(portMap);
+        List<Neutron_IPs> ipList = securityServicesImpl.getVmListForSecurityGroup(NEUTRON_PORT_ID_VM_1, SECURITY_GROUP_ID_2);
+        assertEquals(ipList,neutron_IPs_2);
+    }
+
+    /**
+     * Test getVmListForSecurityGroup with no vm with the
+     * SG associated..
+     */
+    @Test
+    public void testGetVmListForSecurityGroupWithNoVm() {
+        List<NeutronPort> portList = new ArrayList<>();
+        portList.add(neutronPort_Vm1);
+        portList.add(neutronPort_Vm2);
+        portList.add(neutronPort_Vm3);
+        portList.add(neutronPort_Dhcp);
+        when(neutronPortCache.getAllPorts()).thenReturn(portList);
+        List<Neutron_IPs> ipList = securityServicesImpl.getVmListForSecurityGroup(NEUTRON_PORT_ID_VM_1, SECURITY_GROUP_ID_1);
+        assert(ipList.isEmpty());
+    }
+
+    /**
+     * Test syncSecurityGroup addition
+     */
+    @Test
+    public void testSyncSecurityGroupAddition() {
+        List<NeutronSecurityGroup> securityGroupsList = new ArrayList<>();
+        securityGroupsList.add(neutronSecurityGroup_1);
+        securityServicesImpl.syncSecurityGroup(neutronPort_Vm1, securityGroupsList, true);
+        verify(ingressAclService, times(1)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(true));
+        verify(egressAclService, times(1)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(true));
+    }
+
+    /**
+     * Test syncSecurityGroup deletion
+     */
+    @Test
+    public void testSyncSecurityGroupDeletion() {
+        List<NeutronSecurityGroup> securityGroupsList = new ArrayList<>();
+        securityGroupsList.add(neutronSecurityGroup_1);
+        securityServicesImpl.syncSecurityGroup(neutronPort_Vm1, securityGroupsList, false);
+        verify(ingressAclService, times(1)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+        verify(egressAclService, times(1)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityGroup deletion with port null
+     */
+    @Test
+    public void testSyncSecurityGroupPortNull() {
+        List<NeutronSecurityGroup> securityGroupsList = new ArrayList<>();
+        securityGroupsList.add(neutronSecurityGroup_1);
+        securityServicesImpl.syncSecurityGroup(null, securityGroupsList, false);
+        verify(ingressAclService, times(0)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+        verify(egressAclService, times(0)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityGroup deletion with Sg null
+     */
+    @Test
+    public void testSyncSecurityGroupSgNull() {
+        List<NeutronSecurityGroup> securityGroupsList = new ArrayList<>();
+        securityGroupsList.add(neutronSecurityGroup_1);
+        when(neutronPort_Vm1.getSecurityGroups()).thenReturn(null);
+        securityServicesImpl.syncSecurityGroup(neutronPort_Vm1, null, false);
+        verify(ingressAclService, times(0)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+        verify(egressAclService, times(0)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityGroup deletion with Mac null
+     */
+    @Test
+    public void testSyncSecurityGroupAttachedMacNull() {
+        List<NeutronSecurityGroup> securityGroupsList = new ArrayList<>();
+        securityGroupsList.add(neutronSecurityGroup_1);
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class),eq("attached-mac"))).thenReturn(null);
+        securityServicesImpl.syncSecurityGroup(neutronPort_Vm1, securityGroupsList, false);
+        verify(ingressAclService, times(0)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+        verify(egressAclService, times(0)).programPortSecurityGroup(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityGroup_1), eq(NEUTRON_PORT_ID_VM_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityRule addition of egress rule.
+     */
+    @Test
+    public void testSyncSecurityRuleAdditionEgress() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_EGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, true);
+        verify(egressAclService, times(1)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(true));
+    }
+
+    /**
+     * Test syncSecurityRule addition of ingress rule.
+     */
+    @Test
+    public void testSyncSecurityRuleAdditionIngress() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, true);
+        verify(ingressAclService, times(1)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(true));
+    }
+
+    /**
+     * Test syncSecurityRule deletion of egress rule.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionEgress() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_EGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(egressAclService, times(1)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityRule deletion of ingress rule.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionIngress() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(ingressAclService, times(1)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityRule deletion of ingress rule with port null.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionIngressPortNull() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(null, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(ingressAclService, times(0)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityRule deletion of ingress rule with sg null.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionIngressSgNull() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronPort_Vm1.getSecurityGroups()).thenReturn(null);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(ingressAclService, times(0)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityRule deletion of ingress rule with mac null.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionIngressAttachedMacNull() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class),eq("attached-mac"))).thenReturn(null);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(ingressAclService, times(0)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+
+    /**
+     * Test syncSecurityRule deletion of ingress rule no ipv4 ether.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionIngressNonIpV4() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn(NeutronSecurityRule.DIRECTION_INGRESS);
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV6);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(ingressAclService, times(0)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+    /**
+     * Test syncSecurityRule deletion of ingress rule with invalid direction.
+     */
+    @Test
+    public void testSyncSecurityRuleDeletionInvalidDirection() {
+        List<NeutronSecurityRule> securityRuleList = new ArrayList<>();
+        securityRuleList.add(neutronSecurityRule_1);
+        when(neutronSecurityRule_1.getSecurityRuleDirection()).thenReturn("outgress");
+        when(neutronSecurityRule_1.getSecurityRuleEthertype()).thenReturn(NeutronSecurityRule.ETHERTYPE_IPV4);
+        securityServicesImpl.syncSecurityRule(neutronPort_Vm1, neutronSecurityRule_1, neutron_ip_1, false);
+        verify(ingressAclService, times(0)).programPortSecurityRule(eq(new Long(1)), eq("1000"), eq("attached-mac"), eq(2L), eq(neutronSecurityRule_1), eq(neutron_ip_1), eq(false));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        securityServicesImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        securityServicesImpl.setDependencies(neutronPortCache);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), neutronPortCache);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = SecurityServicesImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(securityServicesImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/TenantNetworkManagerImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/TenantNetworkManagerImplTest.java
new file mode 100644 (file)
index 0000000..13285c4
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.VlanConfigurationCache;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+        .OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link TenantNetworkManagerImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class TenantNetworkManagerImplTest {
+
+    @InjectMocks private TenantNetworkManagerImpl tenantNetworkManagerImpl;
+
+    @Mock private INeutronPortCRUD neutronPortCache;
+    @Mock private INeutronNetworkCRUD neutronNetworkCache;
+    @Mock private VlanConfigurationCache vlanConfigurationCache;
+    @Mock private NetworkingProviderManager networkingProviderManager;
+    @Mock private Southbound southbound;
+
+    private static final String NETWORK_ID= "networkId";
+    private static final String SEG_ID = "segId";
+    private static final String INTERFACE_ID = "intId";
+    /**
+     * Test method {@link TenantNetworkManagerImpl#getInternalVlan(Node, String)}
+     */
+    @Test
+    public void testGetInternalVlan() {
+        when(vlanConfigurationCache.getInternalVlan(any(Node.class), eq(NETWORK_ID))).thenReturn(10);
+
+        assertEquals("Error, did not return the correct internalVlan" , 10, tenantNetworkManagerImpl.getInternalVlan(mock(Node.class), NETWORK_ID));
+        assertEquals("Error, did not return the correct internalVlan", 0, tenantNetworkManagerImpl.getInternalVlan(mock(Node.class), "unexistingNetwork"));
+
+        verify(vlanConfigurationCache, times(2)).getInternalVlan(any(Node.class), anyString());
+    }
+
+    /**
+     * Test method {@link TenantNetworkManagerImpl#reclaimInternalVlan(Node, NeutronNetwork)}
+     */
+    @Test
+    public void testReclaimInternalVlan() {
+        when(vlanConfigurationCache.reclaimInternalVlan(any(Node.class), eq(NETWORK_ID))).thenReturn(10);
+
+        tenantNetworkManagerImpl.reclaimInternalVlan(mock(Node.class), mock(NeutronNetwork.class));
+        tenantNetworkManagerImpl.reclaimInternalVlan(mock(Node.class), mock(NeutronNetwork.class));
+
+        verify(vlanConfigurationCache, times(2)).reclaimInternalVlan(any(Node.class), anyString());
+    }
+
+    /**
+     * Test method {@link TenantNetworkManagerImpl#programInternalVlan(Node, OvsdbTerminationPointAugmentation, NeutronNetwork)}
+     */
+    @Test
+    public void testProgramInternalVlan(){
+        when(vlanConfigurationCache.getInternalVlan(any(Node.class), anyString())).thenReturn(10);
+
+        tenantNetworkManagerImpl.programInternalVlan(mock(Node.class), mock(OvsdbTerminationPointAugmentation.class), mock(NeutronNetwork.class));
+
+        verify(vlanConfigurationCache, times(1)).getInternalVlan(any(Node.class), anyString());
+    }
+
+    /**
+     * Test method {@link TenantNetworkManagerImpl#isTenantNetworkPresentInNode(Node, String)}
+     */
+    @Test
+    public void testIsTenantNetworkPresentInNode() {
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn(SEG_ID);
+        when(neutronNetwork.getNetworkUUID()).thenReturn(NETWORK_ID);
+        List<NeutronNetwork> listNeutronNetwork = new ArrayList<>();
+        listNeutronNetwork.add(neutronNetwork);
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(listNeutronNetwork);
+
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(INTERFACE_ID);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPort.getNetworkUUID()).thenReturn(NETWORK_ID);
+        when(neutronPortCache.getPort(anyString())).thenReturn(neutronPort);
+
+        List<OvsdbTerminationPointAugmentation> ports = new ArrayList<>();
+        ports.add(mock(OvsdbTerminationPointAugmentation.class));
+        when(southbound.readTerminationPointAugmentations(any(Node.class))).thenReturn(ports);
+
+        assertTrue("Error, did not return correct boolean for isTenantNetworkPresentInNode", tenantNetworkManagerImpl.isTenantNetworkPresentInNode(mock(Node.class), SEG_ID));
+    }
+
+    /**
+     * Test method {@link TenantNetworkManagerImpl#getNetworkId(String)}
+     */
+    @Test
+    public void testGetNetworkId() {
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        List<NeutronNetwork> listNeutronNetwork = new ArrayList<>();
+        listNeutronNetwork.add(neutronNetwork);
+
+        when(neutronNetwork.getProviderSegmentationID()).thenReturn("segId");
+        when(neutronNetwork.getNetworkUUID()).thenReturn("networkUUID");
+        when(neutronNetworkCache.getAllNetworks()).thenReturn(listNeutronNetwork);
+
+        assertEquals("Error, did not return the UUID of the correct network", listNeutronNetwork.get(0).getNetworkUUID(), tenantNetworkManagerImpl.getNetworkId("segId"));
+
+        verify(neutronNetworkCache, times(1)).getAllNetworks();
+    }
+
+    /**
+     * Test method {@link TenantNetworkManagerImpl#getTenantNetwork(OvsdbTerminationPointAugmentation)}
+     */
+    @Test
+    public void testGetTenantNetwork() {
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(INTERFACE_ID);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPortCache.getPort(anyString())).thenReturn(neutronPort);
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
+
+        assertEquals("Error, did not return the correct tenant", neutronNetwork, tenantNetworkManagerImpl.getTenantNetwork(mock(OvsdbTerminationPointAugmentation.class)));
+    }
+
+    @Test
+    public void testGetTenantPort() {
+        when(southbound.getInterfaceExternalIdsValue(any(OvsdbTerminationPointAugmentation.class), anyString())).thenReturn(INTERFACE_ID);
+        NeutronPort neutronPort = mock(NeutronPort.class);
+        when(neutronPortCache.getPort(anyString())).thenReturn(neutronPort);
+
+        assertEquals("Error, did not return the correct tenant", neutronPort, tenantNetworkManagerImpl.getTenantPort(mock(OvsdbTerminationPointAugmentation.class)));
+    }
+
+    @Test
+    public void testNetworkCreated() {
+        tenantNetworkManagerImpl.networkCreated(mock(Node.class), NETWORK_ID);
+        verify(vlanConfigurationCache, times(1)).assignInternalVlan(any(Node.class), anyString());
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        VlanConfigurationCache vlanConfigurationCache = mock(VlanConfigurationCache.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(VlanConfigurationCache.class, vlanConfigurationCache);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        tenantNetworkManagerImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("vlanConfigurationCache"), vlanConfigurationCache);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    @Test
+    public void testSetDependenciesObject() throws Exception{
+        INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
+        tenantNetworkManagerImpl.setDependencies(neutronNetworkCache);
+        assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), neutronNetworkCache);
+
+        INeutronPortCRUD neutronPortCache = mock(INeutronPortCRUD.class);
+        tenantNetworkManagerImpl.setDependencies(neutronPortCache);
+        assertEquals("Error, did not return the correct object", getField("neutronPortCache"), neutronPortCache);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = TenantNetworkManagerImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(tenantNetworkManagerImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/VlanConfigurationCacheImplTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/VlanConfigurationCacheImplTest.java
new file mode 100644 (file)
index 0000000..acabc08
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, 2016 Inocybe 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.openstack.netvirt.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
+        .OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Unit test for {@link VlanConfigurationCacheImpl}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class VlanConfigurationCacheImplTest {
+
+    @InjectMocks public VlanConfigurationCacheImpl vlanConfigurationCacheImpl;
+
+    @Mock private TenantNetworkManager tenantNetworkManager;
+    @Mock private Southbound southbound;
+
+    private static final String NODE_UUID = "nodeUUID";
+    private static final String NETWORK_ID= "networkId";
+    private static final int VLAN_ID = 4;
+    /**
+     * Function configuring the node
+     */
+    @Before
+    public void setUp(){
+        when(southbound.getOvsdbNodeUUID(any(Node.class))).thenReturn(NODE_UUID);
+        List<OvsdbTerminationPointAugmentation> ports = new ArrayList<>();
+        OvsdbTerminationPointAugmentation port = mock(OvsdbTerminationPointAugmentation.class);
+        VlanId vlanId = mock(VlanId.class);
+        when(vlanId.getValue()).thenReturn(VLAN_ID);
+        when(port.getVlanTag()).thenReturn(vlanId);
+        when(southbound.getTerminationPointsOfBridge(any(Node.class))).thenReturn(ports );
+        NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
+        when(neutronNetwork.getNetworkUUID()).thenReturn(NETWORK_ID);
+        when(tenantNetworkManager.getTenantNetwork(any(OvsdbTerminationPointAugmentation.class))).thenReturn(neutronNetwork );
+    }
+
+    /**
+     * Test method {@link VlanConfigurationCacheImpl#assignInternalVlan(Node, String)}
+     */
+    @Test
+    public void testAssignReclaimAndGetInternalVlan() {
+        assertEquals("Error, assignInternalVlan() did not return the correct internalVlanId (first added)", 1, (int) vlanConfigurationCacheImpl.assignInternalVlan(any(Node.class), NETWORK_ID));
+        assertEquals("Error, assignInternalVlan () did not return the correct internalVlanId (second added)", 2, (int) vlanConfigurationCacheImpl.assignInternalVlan(any(Node.class), NETWORK_ID + "1"));
+
+        assertEquals("Error, getInternalVlan() did not return the correct internalVlan", 1, (int) vlanConfigurationCacheImpl.getInternalVlan(any(Node.class), NETWORK_ID));
+
+        assertEquals("Error, reclaimInternalVlan() did not return the correct internalVlanId", 1, (int) vlanConfigurationCacheImpl.reclaimInternalVlan(any(Node.class), NETWORK_ID));
+        assertEquals("Error, reclaimInternalVlan() did not return the correct internalVlanId", 2, (int) vlanConfigurationCacheImpl.reclaimInternalVlan(any(Node.class), NETWORK_ID + "1"));
+    }
+
+    @Test
+    public void testSetDependencies() throws Exception {
+        TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
+        Southbound southbound = mock(Southbound.class);
+
+        ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
+        ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
+
+        vlanConfigurationCacheImpl.setDependencies(mock(ServiceReference.class));
+
+        assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
+        assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
+    }
+
+    private Object getField(String fieldName) throws Exception {
+        Field field = VlanConfigurationCacheImpl.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(vlanConfigurationCacheImpl);
+    }
+}
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterfaceTest.java b/openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterfaceTest.java
new file mode 100644 (file)
index 0000000..fdb01e2
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015, 2016 NEC Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+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.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.FloatingipBuilder;
+
+/**
+ * Unit test for {@link NeutronFloatingIPInterface}
+ */
+public class NeutronFloatingIPInterfaceTest extends AbstractDataBrokerTest {
+    /**
+     * UUID_VALUE used for testing different scenarios.
+     */
+    private static final String UUID_VALUE = "b9a13232-525e-4d8c-be21-cd65e3436034";
+    /**
+     * FIXED_IP_ADDRESS used for testing different scenarios.
+     */
+    private static final String FIXED_IP_ADDRESS = "10.0.0.3";
+    /**
+     * FLOATING_IP_ADDRESS used for testing different scenarios.
+     */
+    private static final String FLOATING_IP_ADDRESS = "172.24.4.228";
+    /**
+     * STATUS used for testing different scenarios.
+     */
+    private static final String STATUS = "ACTIVE";
+
+    private NeutronFloatingIPInterface getTestInterface(DataBroker broker) {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        return new NeutronFloatingIPInterface(providerContext);
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#floatingIPExists} is called
+     * and then checks that floating Ip exists or not.
+     */
+    @Test
+    public void testFloatingIPExists() throws TransactionCommitFailedException {
+        // floatingIPExists() returns true if the underlying data broker contains the node, false otherwise
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+
+        // First case: the underlying data broker returns nothing (we haven't inserted the IP yet)
+        assertFalse(testInterface.floatingIPExists(UUID_VALUE));
+
+        // Add an IP
+        addTestFloatingIP(broker, testInterface);
+
+        // Second case: the underlying data broker returns something
+        assertTrue(testInterface.floatingIPExists(UUID_VALUE));
+    }
+
+    private void addTestFloatingIP(DataBroker broker, NeutronFloatingIPInterface testInterface)
+            throws TransactionCommitFailedException {
+        WriteTransaction writeTransaction = broker.newWriteOnlyTransaction();
+        Floatingip floatingip = new FloatingipBuilder().setUuid(new Uuid(UUID_VALUE)).build();
+        writeTransaction.put(LogicalDatastoreType.CONFIGURATION,
+                testInterface.createInstanceIdentifier(floatingip), floatingip);
+        writeTransaction.submit().checkedGet();
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#getFloatingIP} is called
+     * and then checks that it gets floating Ip or not.
+     */
+    @Test
+    public void testGetFloatingIP() throws TransactionCommitFailedException {
+        // getFloatingIP() returns the floating IP if the underlying data broker contains the node, null otherwise
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+
+        // First case: the underlying data broker returns nothing (we haven't inserted the IP yet)
+        assertNull(testInterface.getFloatingIP(UUID_VALUE));
+
+        // Add an IP
+        addTestFloatingIP(broker, testInterface);
+
+        // Second case: the underlying data broker returns something
+        final NeutronFloatingIP returnedFloatingIp = testInterface.getFloatingIP(UUID_VALUE);
+        assertNotNull(returnedFloatingIp);
+        assertEquals("UUID mismatch", UUID_VALUE, returnedFloatingIp.getID());
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#getAllFloatingIPs} is called
+     * and then checks that it gets all floating Ips in a list or not.
+     */
+    @Test
+    public void testGetAllFloatingIPs() throws TransactionCommitFailedException {
+        // getAllFloatingIPs() returns all the floating IPs in the underlying data broker
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+
+        // First case: the underlying data broker returns nothing (we haven't inserted the IP yet)
+        assertTrue("Non-empty list of floating IPs", testInterface.getAllFloatingIPs().isEmpty());
+
+        // Add an IP
+        addTestFloatingIP(broker, testInterface);
+
+        // Second case: the underlying data broker returns something
+        final List<NeutronFloatingIP> allFloatingIPs = testInterface.getAllFloatingIPs();
+        assertFalse("Empty list of floating IPs", allFloatingIPs.isEmpty());
+        assertEquals("Incorrect number of floating IPs", 1, allFloatingIPs.size());
+        assertEquals("UUID mismatch", UUID_VALUE, allFloatingIPs.get(0).getID());
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#addFloatingIP} is called
+     * and then verifies whether floating Ip already exists in datastore if not then
+     * ensures floating ip addition by invoking MD-SAL add.
+     */
+    @Test
+    public void testAddFloatingIP() throws TransactionCommitFailedException {
+        // addFloatingIP() adds the given floating IP if it isn't already in the data store
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+
+        // First case: addFloatingIP() adds the floating IP
+        NeutronFloatingIP insertedFloatingIp = new NeutronFloatingIP();
+        insertedFloatingIp.setID(UUID_VALUE);
+        assertTrue("Floating IP already present", testInterface.addFloatingIP(insertedFloatingIp));
+
+        // TODO Retrieve the floating IP directly and make sure it's correct
+
+        // Second case: the floating IP is already present
+        assertFalse("Floating IP missing", testInterface.addFloatingIP(insertedFloatingIp));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#removeFloatingIP} is called
+     * and then verifies by reading floating ip from datastore and ensures floating ip
+     * removal by invoking MD-SAL remove.
+     */
+    @Test
+    public void testRemoveFloatingIP() throws TransactionCommitFailedException {
+        // removeFloatingIP() removes the given floating IP if it's present in the data store
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+
+        // First case: the floating IP isn't present
+        assertFalse("Floating IP present", testInterface.removeFloatingIP(UUID_VALUE));
+
+        // Add an IP
+        addTestFloatingIP(broker, testInterface);
+
+        // Second case: the floating IP is present
+        assertTrue("Floating IP absent", testInterface.removeFloatingIP(UUID_VALUE));
+
+        // TODO Attempt to retrieve the floating IP and make sure it's absent
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#updateFloatingIP} is called
+     * and then verifies by reading floating ip from datastore and ensures floating ip
+     * updation by invoking MD-SAL update.
+     */
+    @Test
+    public void testUpdateFloatingIP() throws TransactionCommitFailedException {
+        // updateFloatingIP() updates the given floating IP only if it's already in the data store
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+
+        // First case: the floating IP isn't present
+        NeutronFloatingIP testFloatingIp = new NeutronFloatingIP();
+        testFloatingIp.setID(UUID_VALUE);
+        assertFalse("Floating IP present", testInterface.updateFloatingIP(UUID_VALUE, testFloatingIp));
+
+        // Add an IP
+        addTestFloatingIP(broker, testInterface);
+
+        // Second case: the floating IP is present
+        assertTrue("Floating IP absent", testInterface.updateFloatingIP(UUID_VALUE, testFloatingIp));
+
+        // TODO Change some attributes and make sure they're updated
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#toMd} is called
+     * and then checks that it sets vales into floating Ip.
+     */
+    @Test
+    public void testToMd() throws Exception {
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+        NeutronFloatingIP neutronFloatingIP = new NeutronFloatingIP();
+        neutronFloatingIP.setID(UUID_VALUE);
+        neutronFloatingIP.setFloatingNetworkUUID(UUID_VALUE);
+        neutronFloatingIP.setPortUUID(UUID_VALUE);
+        neutronFloatingIP.setFixedIPAddress(FIXED_IP_ADDRESS);
+        neutronFloatingIP.setFloatingIPAddress(FLOATING_IP_ADDRESS);
+        neutronFloatingIP.setTenantUUID(UUID_VALUE);
+        neutronFloatingIP.setRouterUUID(UUID_VALUE);
+        neutronFloatingIP.setStatus(STATUS);
+        Floatingip floatingipReceived = testInterface.toMd(neutronFloatingIP);
+        assertEquals("UUID mismatch", UUID_VALUE, floatingipReceived.getUuid().getValue());
+        assertEquals("FloatingNetworkId mismatch", UUID_VALUE, floatingipReceived.getFloatingNetworkId().getValue());
+        assertEquals("Port ID mismatch", UUID_VALUE, floatingipReceived.getPortId().getValue());
+        assertEquals("Fixed IP Address mismatch", FIXED_IP_ADDRESS, String.valueOf(floatingipReceived.getFixedIpAddress().getValue()));
+        assertEquals("Floating IP Address mismatch", FLOATING_IP_ADDRESS, String.valueOf(floatingipReceived.getFloatingIpAddress().getValue()));
+        assertEquals("Tenant Id mismatch", UUID_VALUE, floatingipReceived.getTenantId().getValue());
+        assertEquals("Router Id mismatch", UUID_VALUE, floatingipReceived.getRouterId().getValue());
+        assertEquals("Status mismatch", STATUS, floatingipReceived.getStatus());
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#fromMd} is called
+     * and then checks that it gets values from Floating Ip.
+     */
+    @Test
+    public void testFromMd() throws Exception {
+        DataBroker broker = getDataBroker();
+        NeutronFloatingIPInterface testInterface = getTestInterface(broker);
+        Floatingip actualfloatingip = new FloatingipBuilder()
+                .setUuid(new Uuid(UUID_VALUE))
+                .setFixedIpAddress(
+                        new IpAddress(FIXED_IP_ADDRESS.toCharArray()))
+                .setFloatingIpAddress(
+                        new IpAddress(FLOATING_IP_ADDRESS.toCharArray()))
+                .setFloatingNetworkId(new Uuid(UUID_VALUE))
+                .setPortId(new Uuid(UUID_VALUE))
+                .setRouterId(new Uuid(UUID_VALUE)).setStatus(STATUS)
+                .setTenantId(new Uuid(UUID_VALUE)).build();
+        NeutronFloatingIP neutronFloatingIPReceived = testInterface.fromMd(actualfloatingip);
+        assertEquals("UUID mismatch", UUID_VALUE, neutronFloatingIPReceived.getID());
+        assertEquals("FloatingNetworkId mismatch", UUID_VALUE, neutronFloatingIPReceived.getFloatingNetworkUUID());
+        assertEquals("Port ID mismatch", UUID_VALUE, neutronFloatingIPReceived.getPortUUID());
+        assertEquals("Fixed IP Address mismatch", FIXED_IP_ADDRESS, neutronFloatingIPReceived.getFixedIPAddress());
+        assertEquals("Floating IP Address mismatch", FLOATING_IP_ADDRESS, neutronFloatingIPReceived.getFloatingIPAddress());
+        assertEquals("Tenant Id mismatch", UUID_VALUE, neutronFloatingIPReceived.getTenantUUID());
+        assertEquals("Router Id mismatch", UUID_VALUE, neutronFloatingIPReceived.getRouterUUID());
+        assertEquals("Status mismatch", STATUS, neutronFloatingIPReceived.getStatus());
+    }
+}
diff --git a/openstack/pom.xml b/openstack/pom.xml
new file mode 100644 (file)
index 0000000..da0cc52
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>openstack</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <packaging>pom</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>net-virt</module>
+    <module>net-virt-providers</module>
+    <module>net-virt-it</module>
+    <module>net-virt-sfc</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/ovsdb-ui/bundle/pom.xml b/ovsdb-ui/bundle/pom.xml
new file mode 100644 (file)
index 0000000..68e7734
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 Inocybe Technologies, 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+      <groupId>org.opendaylight.odlparent</groupId>
+      <artifactId>odlparent-lite</artifactId>
+      <version>1.7.0-SNAPSHOT</version>
+      <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.netvirt</groupId>
+    <artifactId>ovsdb-ui-bundle</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+    <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+    <licenses>
+        <license>
+            <name>Eclipse Public License v1.0</name>
+            <url>http://www.eclipse.org/legal/epl-v10.html</url>
+        </license>
+    </licenses>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+    </scm>
+
+    <properties>
+      <dlux.version>0.4.0-SNAPSHOT</dlux.version>
+    </properties>
+
+    <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.dlux</groupId>
+          <artifactId>loader</artifactId>
+          <version>${dlux.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.netvirt</groupId>
+          <artifactId>ovsdb-ui-module</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <resources>
+          <resource>
+            <directory>target/generated-resources</directory>
+          </resource>
+          <resource>
+            <directory>src/main/resources</directory>
+         </resource>
+        </resources>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-dependency-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>unpack-loader-resources</id>
+                <goals>
+                  <goal>unpack</goal>
+                </goals>
+                <phase>generate-resources</phase>
+                <configuration>
+               <artifactItems>
+                   <artifactItem>
+                      <groupId>org.opendaylight.netvirt</groupId>
+                      <artifactId>ovsdb-ui-module</artifactId>
+                      <version>${project.version}</version>
+                      <overWrite>true</overWrite>
+                      <outputDirectory>${project.build.directory}/generated-resources</outputDirectory>
+                    </artifactItem>
+                  </artifactItems>
+                  <excludes>META-INF\/**, ovsdb\/spec\/**, ovsdb\/mocks\/**</excludes>
+                  <ignorePermissions>false</ignorePermissions>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>org.osgi.service.http,
+                                        org.osgi.framework;version="1.0.0",
+                                        org.opendaylight.dlux.loader,
+                                        org.slf4j
+                        </Import-Package>
+                    <Export-Package></Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/ovsdb-ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/ovsdb-ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644 (file)
index 0000000..99eede7
--- /dev/null
@@ -0,0 +1,21 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+    <reference id="httpService" availability="mandatory" activation="eager" interface="org.osgi.service.http.HttpService"/>
+    <reference id="loader" availability="mandatory" activation="eager" interface="org.opendaylight.dlux.loader.DluxModuleLoader"/>
+
+    <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.opendaylight.dlux.loader.DluxModule">
+        <property name="httpService" ref="httpService"/>
+        <property name="loader" ref="loader"/>
+        <property name="moduleName" value="ovsdb"/>
+        <property name="url" value="/src/app/ovsdb"/>
+        <property name="directory" value="/ovsdb"/>
+        <property name="requireJs" value="app/ovsdb/ovsdb.module"/>
+        <property name="angularJs" value="app.ovsdb"/>
+        <property name="cssDependencies">
+            <list>
+                <value>src/app/ovsdb/css/select2.min.css</value>
+                <value>src/app/ovsdb/css/toggle-switch.css</value>
+                <value>src/app/ovsdb/css/ovsdb.css</value>
+            </list>
+        </property>
+    </bean>
+</blueprint>
diff --git a/ovsdb-ui/module/pom.xml b/ovsdb-ui/module/pom.xml
new file mode 100644 (file)
index 0000000..167156a
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 Inocybe Technologies, 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+      <groupId>org.opendaylight.odlparent</groupId>
+      <artifactId>odlparent-lite</artifactId>
+      <version>1.7.0-SNAPSHOT</version>
+      <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.netvirt</groupId>
+    <artifactId>ovsdb-ui-module</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+    <licenses>
+        <license>
+            <name>Eclipse Public License v1.0</name>
+            <url>http://www.eclipse.org/legal/epl-v10.html</url>
+        </license>
+    </licenses>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+    </scm>
+</project>
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/Graph.js b/ovsdb-ui/module/src/main/resources/ovsdb/Graph.js
new file mode 100644 (file)
index 0000000..977e75b
--- /dev/null
@@ -0,0 +1,371 @@
+define(['app/ovsdb/lib/d3.min', 'app/ovsdb/OvsCore', 'app/ovsdb/matrix', 'underscore'], function(d3, OvsCore, Geom, _) {
+  'use strict';
+
+  var root = null,
+    forceLayout = null,
+    baseBB = null,
+    nodes = null,
+    links = null,
+    nodeData = [],
+    linkData = [],
+    drag = null,
+    nodePosCache = null;
+
+  function Graph(id, width, height) {
+    var x = d3.scale.linear()
+      .domain([0, width])
+      .range([0, width]);
+
+    var y = d3.scale.linear()
+      .domain([0, height])
+      .range([height, 0]);
+
+    var tmp = d3.select(id).append("svg")
+    .attr('width', width)
+    .attr('height', height)
+    .append("svg:g")
+    .attr('class', 'layer_0');
+
+    tmp.append('svg:rect')
+    .attr('width', width)
+    .attr('height', height)
+    .attr('fill', 'white');
+
+    root = tmp.call(d3.behavior.zoom().x(x).y(y).scaleExtent([1, 6]).on("zoom", zoom))
+      .append("g");
+
+    this.matrix = new Geom.Matrix();
+
+  //  this._bg = tmp.insert('svg:polygon', ':first-child');
+  //  this._bg.attr('id', 'ttt').attr('fill', 'rgb(250, 220, 220)').attr('stroke', 'rgb(250,0,0)');
+
+    drag = d3.behavior.drag()
+      .origin(function(d) {
+        return d;
+      })
+      .on("dragstart", dragstarted.bind(this))
+      .on("drag", dragmove.bind(this))
+      .on("dragend", dragend.bind(this));
+
+    // a layout for the bridge and his link
+    forceLayout = new d3.layout.force()
+      .gravity(0.05)
+      .charge(-400)
+      .linkDistance(80)
+      .size([width, height])
+      .on('tick', this.update.bind(this));
+
+    addDefs();
+  }
+
+  function zoom() {
+    root.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+  }
+
+  function dragstarted(d) {
+    d3.event.sourceEvent.stopPropagation();
+    forceLayout.stop();
+  }
+
+  function dragmove(d) {
+    d.x += d3.event.dx;
+    d.y += d3.event.dy;
+    d.px += d3.event.dx;
+    d.py += d3.event.dy;
+    this.update();
+  }
+
+  function dragend(d) {
+    d.fixed = true;
+    this.update();
+    forceLayout.resume();
+    baseBB = null;
+  }
+
+  // Define reusable svg item like box-shadow
+  function addDefs() {
+    // box-shadow
+    var defs = d3.select('svg').insert('svg:defs', ':first-child');
+    var filter = defs.append('svg:filter').attr('id', 'selectNode').attr('x', '-20%').attr('y', '-20%').attr('width', '140%').attr('height', '140%');
+    filter.append('feGaussianBlur').attr('stdDeviation', '2').attr('result', 'coloredBlur');
+    var femerge = filter.append('feMerge');
+    femerge.append('feMergeNode').attr('in', 'coloredBlur');
+    femerge.append('feMergeNode').attr('in', 'SourceGraphic');
+  }
+
+  function sortLink(links) {
+    links.sort(function(a,b) {
+      if (a.source > b.source) {
+        return 1;
+      } else if (a.source < b.source) {
+        return -1;
+      }
+      else {
+        if (a.target > b.target) {
+          return 1;
+        }
+        if (a.target < b.target) {
+          return -1;
+        } else {
+          return 0;
+        }
+      }
+    });
+  }
+
+  function setLinkIndexAndNum(links) {
+    _.each(links, function(link, i) {
+      if (i != 0 && links[i].source == links[i-1].source &&
+        links[i].target == links[i-1].target) {
+          links[i].linkindex = links[i-1].linkindex + 1;
+        } else {
+          links[i].linkindex = 1;
+        }
+    });
+  }
+
+  // Properties to quick access and set nodes and links
+  Object.defineProperties(Graph.prototype, {
+    links: {
+      get: function() {
+        return links;
+      },
+      set: function(value) {
+        sortLink(value);
+        setLinkIndexAndNum(value);
+
+        forceLayout.links(value);
+        links = root.selectAll('links')
+          .data(value)
+          .enter().append('svg:path')
+          .attr('class', function(d) {
+            return d.linkType;
+          })
+          .attr('fill', 'none')
+          .attr('stroke-dasharray', function(d) {
+            return d.dashArray;
+          })
+          .attr('stroke-width', function(d) {
+            return d.width;
+          })
+          .attr('stroke', function(d) {
+            return d.color;
+          });
+      }
+    },
+    nodes: {
+      get: function() {
+        return nodes;
+      },
+      set: function(value) {
+        var _this = this; // context change in callback function and we need both
+
+        forceLayout.nodes(value);
+        nodes = root.selectAll('.nodes')
+          .data(value)
+          .enter().append('svg:g')
+          .call(drag)
+          .attr('class', function(d) {
+            return (d.node instanceof OvsCore.BridgeNode) ? 'bridge' : 'switch';
+          })
+          .on('click', function(d) {
+            if (d3.event.defaultPrevented) return;
+            _this.onNodeClick(d, nodes, links, this);
+          })
+          .on("mouseover", function(d) {
+            _this.onNodeOver(d, nodes, links, this);
+          })
+          .on("mouseout", function(d) {
+            _this.onNodeOut(d, nodes, links, this);
+          });
+
+        nodes.append('text')
+          .attr('x', 0)
+          .attr('y', 30)
+          .attr('fill', 'black')
+          .attr('text-anchor', 'middle')
+          .text(function(d) {
+            if (d.node instanceof OvsCore.BridgeNode)
+              return d.node.flowInfo.ip;
+            else
+              return d.node.otherLocalIp;
+          });
+
+        //svg node
+        var layer = d3.selectAll('g.switch').append('svg:g').attr('class', 'switch').attr('transform', 'translate(-16 -16)');
+        layer.append('svg:rect').style('fill-rule', 'evenodd').attr('ry', '3.6808').attr('height', '28.901')
+          .attr('width', '28.784').style('stroke', '#002b69').attr('y', '0').attr('x', '0').style('stroke-width', "3px").style('fill', '#2a7fff');
+        layer.append('svg:path').attr('d', 'm27.043 6.2-5.0754 3.3764-.01018-2.1082-5.9209-.022.01773-2.6018 5.9031-.037.08118-2.1164z').style('fill', "#002b69");
+        layer.append('svg:path').attr('d', "m26.866 19.4-5.0754 3.3764-.01018-2.1082-5.9209-.022.01773-2.6018 5.9031-.037.08118-2.1164z").style('fill', "#002b69");
+        layer.append('svg:path').attr('d', "m3.0872 11.6 5.0754 3.3764.01018-2.1082 5.9209-.022-.01773-2.6018-5.9031-.037-.08118-2.1164z").style('fill', "#002b69");
+        layer.append('svg:path').attr('d', "m3.2639 24.8 5.0754 3.3764.01018-2.1082 5.9209-.022-.01773-2.6018-5.9031-.037-.08118-2.1164z").style('fill', "#002b69");
+
+        //svg bridge
+        var layer = d3.selectAll('g.bridge').append('svg:g').attr('transform', 'translate(-16 -16)');
+        layer.append('svg:path').style('fill', '#d40000').style('stroke', '#ff0000').style('stroke-width', '0.10413094')
+          .style('stroke-linecap', 'round') //stroke-linejoin:round
+          .attr('d', 'm 2.9656662,3.4868 c 4.8978761,7.5117 16.2156478,6.1742 21.9929178,2.0807 l 2.154019,-1.5814 -0.08265,18.1941 -2.055088,2.0313 -24.17161713,0.055 -0.0255688,-18.6893 z');
+        layer.append('svg:path').style('fill', '#ff5555').style('stroke', '#ff0000').style('stroke-width', '0.10413094')
+          .style('stroke-linecap', 'round') //stroke-linejoin:round
+          .attr('d', 'm 0.83642587,5.5637 c 4.89787603,7.5117 18.41115613,4.1109 24.18842613,0.018 l -0.06627,18.6546 -24.12215693,0 z');
+      }
+    }
+  });
+
+  // Update the node and link position on the canvas
+  Graph.prototype.update = function(e) {
+    var k = 1 , //.1 * e.alpha
+      isDragging = (e !== null)
+/*
+    if (!isDragging) {
+      k = .1 * e.alpha;
+    }
+
+    if (!isDragging) {
+      forceLayout.nodes().forEach(function(o) {
+        var i = (o.node instanceof OvsCore.OvsNode) ? 1 : 0;
+        o.y += (layerAnchor[i].y - o.y) * k;
+        o.x += (layerAnchor[i].x - o.x) * k;
+      });
+    }*/
+
+    if (links) {
+      links.attr('d', (function(d) {
+        var srcT = this.matrix.transformPoint(d.source.x, d.source.y),
+          targetT = this.matrix.transformPoint(d.target.x, d.target.y),
+          src = {x:srcT.elements[0],y:srcT.elements[1]},
+          tgt = {x:targetT.elements[0],y:targetT.elements[1]},
+          anchor1 = {}, anchor2 = {};
+
+        if (d.linkType === 'tunnel') {
+          // curve the line and arc it on a direction of a 90 degree vector
+          var perp = { x : -tgt.y, y: tgt.x};
+          var srcNorm = Math.sqrt(src.x * src.x + src.y * src.y);
+          var perpNorm = Math.sqrt(perp.x * perp.x + perp.y * perp.y);
+          var dy = (perp.y/perpNorm - src.y/srcNorm);
+          var dx = (perp.x/perpNorm - src.x/srcNorm);
+
+          anchor1 = {x: src.x - dx * 30, y: src.y - dy * 30 };
+          anchor2 = {x: tgt.x - dx * 30, y: tgt.y - dy * 30 };
+        } else {
+          // default strait line
+          anchor1 = src;
+          anchor2 = tgt;
+        }
+
+        return OvsCore.Util.String.Format('M{0},{1} C{2},{3} {4},{5} {6},{7}',
+          srcT.elements[0], srcT.elements[1],
+          anchor1.x, anchor1.y,
+          anchor2.x, anchor2.y,
+          targetT.elements[0], targetT.elements[1]
+        );
+      }).bind(this));
+    }
+
+    nodes.attr("transform", (function(d) {
+      var a = new Geom.Matrix.fromString(root.attr('transform'));
+      var tmp = Geom.Matrix.combine(a, this.matrix);
+
+      var transV = this.matrix.transformPoint(d.x, d.y);
+      var v = tmp.transformPoint(d.x, d.y);
+      d.pos = {
+        x: v.elements[0],
+        y: v.elements[1]
+      };
+      nodePosCache[d.node.nodeId] =  { pos: d.pos, fixed: d.fixed};
+      return "translate(" + transV.elements[0] + ',' + transV.elements[1] + ')';
+    }).bind(this));
+  };
+
+  Graph.prototype.setPosCache = function(cache) {
+    nodePosCache = cache;
+  };
+
+  // Apply few matrix transform to fake a perspective effet
+  Graph.prototype.applyPerspective = function(value) {
+    if (!baseBB)
+      baseBB = root.node().getBBox();
+
+    var padding = 50;
+    var persMatrix = new Geom.Matrix()
+      .translate(-(baseBB.x + baseBB.width / 2), -(baseBB.y + baseBB.height / 2))
+      .skew(-25, 0)
+      .scale(1, 0.6)
+      .translate(baseBB.x + baseBB.width / 2, baseBB.y + baseBB.height / 2);
+
+    this.matrix.transform = value ? this.matrix.transform.x(persMatrix.transform) : this.matrix.transform.x(persMatrix.transform.inverse());
+
+    var p1 = this.matrix.transformPoint(baseBB.x - padding, baseBB.y - padding);
+    var p2 = this.matrix.transformPoint(baseBB.x - padding, baseBB.y + baseBB.height + padding);
+    var p3 = this.matrix.transformPoint(baseBB.x + baseBB.width + padding, baseBB.y + baseBB.height + padding);
+    var p4 = this.matrix.transformPoint(baseBB.x + baseBB.width + padding, baseBB.y - padding);
+
+    this._bg.attr('points', OvsCore.Util.String.Format("{0},{1} {2},{3} {4},{5} {6},{7}",
+      p1.elements[0],
+      p1.elements[1],
+      //--
+      p2.elements[0],
+      p2.elements[1],
+      //--
+      p3.elements[0],
+      p3.elements[1],
+      //--
+      p4.elements[0],
+      p4.elements[1])).style('display', (value) ? 'block' : 'none');
+
+    this.update();
+  };
+
+  function positionateBaseOnCache() {
+    forceLayout.stop();
+    forceLayout.nodes().forEach(function(d) {
+      var nodeCached = nodePosCache[d.node.nodeId];
+      d.px = d.x = nodeCached.pos.x;
+      d.py = d.y = nodeCached.pos.y;
+      d.fixed = nodeCached.fixed;
+    });
+    forceLayout.resume();
+  }
+
+  // start the force layout
+  Graph.prototype.start = function() {
+    forceLayout.linkStrength(function(link) {
+      if (link.linkType === 'bridgeOvsLink') {
+        return 0;
+      }
+      return 1;
+    });
+    forceLayout.start();
+    if (_.size(nodePosCache) > 0) {
+      positionateBaseOnCache();
+    }
+  };
+
+  Graph.prototype.freeDOM = function() {
+    nodes.remove();
+    links.remove();
+    forceLayout.nodes([]);
+    forceLayout.links([]);
+  };
+
+  // Enable to manipulate attributes of the graph group node
+  Graph.prototype.attr = function(name, value) {
+    return root.attr(name, value);
+  };
+
+  // Enable the monipulate the css of the graph group node
+  Graph.prototype.style = function(name, value) {
+    return root.style(name, value);
+  };
+
+  Graph.prototype.selectAll = function(a) {
+    return root.selectAll(a);
+  };
+
+  // callback function
+  Graph.prototype.onNodeOver = _.noop;
+  Graph.prototype.onNodeOut = _.noop;
+  Graph.prototype.onNodeClick = _.noop;
+
+  return Graph;
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/LogicalGraph.js b/ovsdb-ui/module/src/main/resources/ovsdb/LogicalGraph.js
new file mode 100644 (file)
index 0000000..735fc6e
--- /dev/null
@@ -0,0 +1,520 @@
+define(['app/ovsdb/lib/d3.min', 'app/ovsdb/OvsCore', 'underscore'], function (d3, OvsCore, _) {
+  'use strict';
+
+  var root = null,
+    canvasWidth = -1,
+    canvasHeight = -1,
+    bbox = {
+      x: 0,
+      y: 15,
+      width: 0,
+      height: 0
+    },
+    // config
+    nodeWidth = 15,
+    nodeHeight = -1,
+    defaultRouterWidth = 52,
+    defaultRouterHeight = 52,
+    networkMargin = {
+      width: 120,
+      height: 15
+    },
+    routerMargin = {
+      width: 120,
+      height: 40
+    },
+    vmMargin = {
+      width: 90,
+      height: 30
+    },
+    defaultVmsWidth = 48,
+    defaultVmsHeight = 48,
+    ipNetworkTextMaxLength = 60,
+    networkOffset = 15,
+    linkHeight = 5,
+    // datas
+    networkData = [],
+    routerData = [],
+    vmData = [],
+    linkData = [],
+    tmpNetHolder = {},
+    // d3 layer over datas
+    d3Node = null,
+    d3Link = null,
+    d3Vm = null,
+    d3Router = null,
+    randomize = OvsCore.Util.Math.Random(42);
+
+  function LogicalGraph(id, width, height) {
+    canvasWidth = width;
+    canvasHeight = height;
+
+    nodeHeight = height - 15;
+
+    var tmp = d3.select(id).append("svg")
+      .attr('width', width)
+      .attr('height', height)
+      .append("svg:g")
+      .attr('class', 'layer_0');
+
+    tmp.append('svg:rect')
+      .attr('width', width)
+      .attr('height', height)
+      .attr('fill', 'white');
+
+    root = tmp.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
+      .append("g");
+    tmp.on("dblclick.zoom", null);
+    addDefs();
+  }
+
+  // Define reusable svg item like box-shadow
+  function addDefs() {
+    // box-shadow
+    var defs = d3.select('svg').insert('svg:defs', ':first-child');
+    var filter = defs.append('svg:filter').attr('id', 'boxShadow').attr('x', '0').attr('y', '0').attr('width', '200%').attr('height', '200%');
+    filter.append('feOffset').attr('in', 'SourceAlpha').attr('result', 'offOut').attr('dx', 0).attr('dy', 0);
+    filter.append('feGaussianBlur').attr('stdDeviation', '5').attr('in', 'offOut').attr('result', 'blurOut');
+    filter.append('feOffset').attr('in', 'SourceGraphic').attr('in2', 'blurOut').attr('mode', 'normal');
+  }
+
+  function zoom() {
+    root.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+  }
+
+  Object.defineProperties(LogicalGraph.prototype, {
+    networks: {
+      set: function (value) {
+        networkData = value;
+        value.forEach(function (net) {
+          routerData = routerData.concat(net.routers);
+        });
+        value.forEach(function (net) {
+          vmData = vmData.concat(net.instances);
+        });
+      }
+    }
+  });
+
+  LogicalGraph.prototype.start = function () {
+    setTopologyPosition.call(this, networkData);
+    addLinksToDom.call(this, linkData);
+    addNetWorkRouterVmsToDom.call(this, networkData, routerData, vmData);
+    update.call(this);
+  };
+
+  LogicalGraph.prototype.freeDOM = function () {
+    d3Node.remove();
+    d3Link.remove();
+    d3Vm.remove();
+    d3Router.remove();
+
+    networkData = [];
+    routerData = [];
+    vmData = [];
+    linkData = [];
+    bbox = {
+      x: 0,
+      y: 15,
+      width: 0,
+      height: 0
+    };
+  };
+
+  function addLinksToDom(linksData) {
+    d3Link = root.selectAll('.llink')
+      .data(linksData).enter().append('svg:g');
+
+    d3Link.append('rect')
+      .attr('width', function (d) {
+        return d.target.x - d.source.x;
+      })
+      .attr('height', linkHeight)
+      .style('fill', function (d) {
+        return d.color;
+      });
+
+    d3Link.append('text')
+      .attr('x', 40)
+      .attr('y', -3)
+      .text(function (d) {
+        return d.text;
+      });
+  }
+
+  function addNetWorkRouterVmsToDom(networks, routers, vms) {
+    var ctx = this,
+      timer = null;
+
+    d3Node = root.selectAll('.network')
+      .data(networks).enter()
+      .append('svg:g');
+    d3Router = root.selectAll('.routers')
+      .data(routers).enter()
+      .append('svg:g');
+    d3Vm = root.selectAll('.vm')
+      .data(vms).enter()
+      .append('svg:g');
+
+    // append coresponding form
+    d3Node.append('svg:rect')
+      .attr('width', nodeWidth)
+      .attr('height', nodeHeight)
+      .attr('rx', 10)
+      .attr('ry', 10)
+      .style('fill', function (d) {
+        return d.color;
+      }).on('click', function (d) {
+        if (d3.event.defaultPrevented) return;
+        timer = setTimeout(function () {
+          ctx.onClick(d);
+        }.bind(this), 150);
+      }).on('dblclick', function (d) {
+        clearTimeout(timer);
+        ctx.dblClick(d);
+      });
+
+    // append the network name text
+    d3Node.append('text')
+      .attr('x', nodeWidth / 2)
+      .attr('y', nodeHeight / 2)
+      .style('text-anchor', 'middle')
+      .style('writing-mode', 'tb')
+      .style('font-size', '12px')
+      .style('glyph-orientation-vertical', '0')
+      .text(function (d) {
+        return d.name;
+      });
+
+    // text info for the network ip
+    d3Node.append('text')
+      .attr('x', nodeWidth + 10)
+      .attr('y', nodeHeight - 15)
+      .attr('transform',
+        OvsCore.Util.String.Format('translate({0} {1}) rotate(-90) translate(-{0} -{1})', nodeWidth + 10, nodeHeight - 15))
+      .attr('class', 'linfolabel')
+      .text(function (d) {
+        return d.ip;
+      });
+
+    // vm
+    d3Vm.append('svg:image')
+      .attr('width', defaultVmsWidth)
+      .attr('height', defaultVmsHeight)
+      .attr('filter', 'url(#boxShadow)')
+      .attr('xlink:href', function (d) {
+        return d.type === 'network:dhcp' ?
+          'src/app/ovsdb/assets/dhcp.png' : 'src/app/ovsdb/assets/vm.png';
+      })
+      .on('click', function (d) {
+        if (d3.event.defaultPrevented) return;
+        timer = setTimeout(function () {
+          ctx.onClick(d);
+        }.bind(this), 150);
+      }).on('dblclick', function (d) {
+        clearTimeout(timer);
+        ctx.dblClick(d);
+      });
+
+    // router
+    d3Router.append('svg:image')
+      .attr('width', defaultRouterWidth)
+      .attr('height', defaultRouterHeight)
+      .attr('xlink:href', 'src/app/ovsdb/assets/router.png')
+      .on('click', function (d) {
+        if (d3.event.defaultPrevented) return;
+        timer = setTimeout(function () {
+          ctx.onClick(d);
+        }.bind(this), 150);
+      }).on('dblclick', function (d) {
+        clearTimeout(timer);
+        ctx.dblClick(d);
+      });
+
+    // router name label
+    d3Router.append('text')
+      .attr('x', defaultRouterWidth * 0.5)
+      .attr('y', defaultRouterHeight + 15)
+      .attr('text-anchor', 'middle')
+      .attr('class', 'linfolabel')
+      .text(function (d) {
+        return d.name;
+      });
+
+    // vm name label
+    d3Vm.append('text')
+      .attr('x', defaultVmsWidth * 0.5)
+      .attr('y', defaultVmsHeight + 15)
+      .attr('text-anchor', 'middle')
+      .attr('class', 'linfolabel')
+      .text(function (d) {
+        return d.name;
+      });
+
+    // vm floating ip label
+    d3Vm.append('text')
+      .attr('x', -35)
+      .attr('y', 40)
+      .attr('text-anchor', 'middle')
+      .text(function (d) {
+        return (d.floatingIp) ? d.floatingIp.ip : '';
+      });
+
+  }
+
+  function findNetworkWithRouter(router) {
+    var result = [];
+    _.each(router.interfaces, function (inter) {
+      if (inter.type === 'router_interface') {
+        var net = tmpNetHolder[inter.networkId] || null;
+
+        if (net) {
+          result.push({
+            network: net,
+            interface: inter
+          });
+        }
+      }
+    });
+
+    return result;
+  }
+
+  function positionateNetwork(network, x, y, margin) {
+    network.x = x;
+    network.y = y;
+    margin = margin || 0;
+    network.color = d3.hsl(randomize.next() * 360, 1, 0.6).toString();
+
+    // look is the network is the highest
+    bbox.height = network.y > bbox.height ? network.y : bbox.height;
+    bbox.width = network.x > bbox.width ? network.x : bbox.width;
+
+    // get the number of "childs" (router, vm)
+    var nbRouter = network.routers.length;
+    var nbVm = network.instances.length;
+
+    if (!network.external) {
+      _.each(network.subnets, function (subnet, i) {
+        network.ip += subnet.cidr;
+        if (i < network.subnets.length - 1) {
+          network.ip += ', ';
+        }
+      });
+    }
+
+    // if needed, ajust the height of the network
+    // to be able to display all children
+    ajustHeighBaseOnChilds(nbRouter, nbVm);
+
+    var py = positionateRouter(network, x + routerMargin.width, y + margin);
+
+    positionateVm(network, x + vmMargin.width, py + 35 + margin);
+    delete tmpNetHolder[network.id];
+  }
+
+  function positionateRouter(network, x, y) {
+    var px = x,
+      py = y;
+
+    // loop over all routers
+    _.each(network.routers, function (router, i) {
+      router.x = getRouterCentroid(x, py).x;
+      router.y = py;
+      py += getRouterMarginHeight();
+
+      if (network.external) {
+        // find network ip with the gateway ip
+        var gateway = router.externalGateway.external_fixed_ips[0].ip_address;
+        var netIp = gateway.slice(0, gateway.lastIndexOf('.')) + '.0';
+        network.ip = netIp;
+      }
+
+      // look is the router is the highest
+      bbox.height = router.y > bbox.height ? router.y : bbox.height;
+      bbox.width = router.x > bbox.width ? router.x : bbox.width;
+
+      linkData.push({
+        source: {
+          x: network.x + (nodeWidth * 0.5),
+          y: router.y + (defaultRouterHeight * 0.5)
+        },
+        target: {
+          x: router.x + (defaultRouterWidth * 0.5),
+          y: router.y + (nodeWidth * 0.5)
+        },
+        color: network.color,
+        text: router.externalGateway.external_fixed_ips[0].ip_address
+      });
+
+      // go to the next layer
+      var nets = findNetworkWithRouter(router),
+        step = defaultRouterHeight / (nets.length + 1);
+
+      _.forEach(nets, function (net, i) {
+        var netPos = getNetworkLayerPosition(bbox.width + defaultRouterWidth);
+
+        positionateNetwork(net.network, netPos.x, netPos.y);
+        linkData.push({
+          source: {
+            x: router.x + (2 * nodeWidth),
+            y: router.y + step * (i + 1)
+          },
+          target: {
+            x: net.network.x + (nodeWidth * 0.5),
+            y: router.y + (nodeWidth * 0.5)
+          },
+          color: net.network.color,
+          text: net.interface.ip.ip_address
+        });
+      });
+    });
+    return py;
+  }
+
+  function positionateVm(network, x, y) {
+
+    // I do vm before router because router
+    // will step to another BUS
+    _.each(network.instances, function (vm) {
+      vm.x = x;
+      vm.y = y;
+
+      // look is the network is the highest
+      bbox.height = vm.y > bbox.height ? vm.y : bbox.height;
+      bbox.width = vm.x > bbox.width ? vm.x : bbox.width;
+
+      y += getVmMarginHeight();
+      linkData.push({
+        source: {
+          x: network.x + (nodeWidth * 0.5),
+          y: vm.y + (defaultVmsHeight * 0.5)
+        },
+        target: {
+          x: vm.x + (defaultVmsWidth * 0.5),
+          y: vm.y + (nodeWidth * 0.5)
+        },
+        color: network.color,
+        text: vm.ip
+      });
+    });
+  }
+
+  /*
+   *  Scan the whole "BUS" to display it properly
+   * ------------------------------------------------
+   *  I build it in a virtual space, if it need to be
+   *  resize it at the end when the overal bounding
+   *  box is known
+   */
+  function setTopologyPosition(networks) {
+    _.each(networks, function (net) {
+      tmpNetHolder[net.id] = net;
+    });
+
+    var i = 0;
+    for (var key in tmpNetHolder) {
+      var margin = (i === 0) ? 5 : networkMargin.width,
+        net = tmpNetHolder[key];
+      if (net.routers.length > 0) {
+        positionateNetwork(net, bbox.x + bbox.width + margin, bbox.y);
+        ++i;
+      }
+    }
+
+    for (var key in tmpNetHolder) {
+      var margin = networkMargin.width,
+        net = tmpNetHolder[key];
+      positionateNetwork(net, bbox.x + bbox.width + margin, bbox.y);
+    }
+  }
+
+  /*
+   * Check and ajust the height for a network.
+   */
+  function ajustHeighBaseOnChilds(nbRouter, nbVm) {
+    // calculate the height for the number of childs
+    var childHeight = nbRouter * (getRouterMarginHeight()) +
+      nbVm * (getVmMarginHeight()) + ipNetworkTextMaxLength;
+
+    // if heigh bigger than the default network height resize it
+    if (childHeight > nodeHeight) {
+      nodeHeight = childHeight + networkOffset;
+    }
+  }
+
+  /*
+   * Set the view to the modal position
+   */
+  function update() {
+
+    d3Node.attr('transform', function (d) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.x, d.y
+      );
+    });
+
+    d3Router.attr('transform', function (d, i) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.x, d.y
+      );
+    });
+
+    d3Vm.attr('transform', function (d) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.x, d.y
+      );
+    });
+
+    d3Link.attr('transform', function (d) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.source.x, d.source.y
+      );
+    });
+
+    // resize the graph if bigger than the canvas
+    var bbox = root.node().getBBox();
+    if (bbox.width > canvasWidth || bbox.height > canvasHeight) {
+      var sx = (canvasWidth - 30) / bbox.width,
+        sy = (canvasHeight - 30) / bbox.height,
+        s = sx < sy ? sx : sy;
+      d3.select('.layer_0').attr('transform', 'scale(' + s + ')');
+      console.log(root.node().getBBox());
+    }
+  }
+
+  function getRouterCentroid(x, y) {
+    return {
+      x: x + defaultRouterWidth * 0.5,
+      y: y + defaultRouterHeight * 0.5
+    };
+  }
+
+  function getRouterMarginHeight() {
+    return (defaultRouterHeight + routerMargin.height);
+  }
+
+  function getVmMarginHeight() {
+    return (defaultVmsHeight + vmMargin.height);
+  }
+
+  function getNetworkLayerPosition(x) {
+    return {
+      x: x + networkMargin.width,
+      y: networkMargin.height
+    };
+  }
+
+  function getVmLayerPosition(nbRouter, x) {
+    var t = {
+      x: x + vmMargin.width * 2,
+      y: getRoutersDim(nbRouter).height + getVmMarginHeight()
+    };
+    return t;
+  }
+
+  LogicalGraph.prototype.onClick = _.noop;
+  LogicalGraph.prototype.dblClick = _.noop;
+
+  return LogicalGraph;
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/OvsCore.js b/ovsdb-ui/module/src/main/resources/ovsdb/OvsCore.js
new file mode 100644 (file)
index 0000000..70733ef
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+
+define(['underscore'], function (_) {
+
+  var Topology = (function () {
+
+    function Topology(topoId) {
+      this.topoId = topoId || '';
+      this._bridgeNodes = {};
+      this._ovsdbNodes = {};
+      this._links = {};
+    }
+
+    Object.defineProperties(Topology.prototype, {
+      bridgeNodes: {
+        get: function () {
+          return this._bridgeNodes;
+        }
+      },
+      nodes: {
+        get: function () {
+          return _.extend({}, this._bridgeNodes, this._ovsdbNodes);
+        }
+      },
+      ovsdbNodes: {
+        get: function () {
+          return this._ovsdbNodes;
+        }
+      },
+      links: {
+        get: function () {
+          return this._links;
+        }
+      }
+    });
+
+    Topology.prototype.registerBridgeNode = function (bridgeNode) {
+      this._bridgeNodes[bridgeNode.nodeId] = bridgeNode;
+    };
+
+    Topology.prototype.registerOvsdbNode = function (ovsdbNode) {
+      this._ovsdbNodes[ovsdbNode.nodeId] = ovsdbNode;
+    };
+
+    Topology.prototype.registerLink = function (link) {
+      if (this._links[link.linkId]) {
+        console.warn('Two links have the same id (' + link.linkId + '), the first one will be overrided');
+      }
+      this._links[link.linkId] = link;
+    };
+
+    Topology.prototype.updateLink = function () {
+      _.each(this._links, (function (link, key) {
+        if (link instanceof Link) {
+          srcNode = _.filter(this._bridgeNodes, function (node) {
+            return node.getFLowName() === link.srcNodeId;
+          });
+          destNode = _.filter(this._bridgeNodes, function (node) {
+            return node.getFLowName() === link.destNodeId;
+          });
+          link.srcNodeId = srcNode[0].nodeId;
+          link.destNodeId = destNode[0].nodeId;
+        }
+        link.source = Object.keys(this.nodes).indexOf(link.srcNodeId);
+        link.target = Object.keys(this.nodes).indexOf(link.destNodeId);
+
+      }).bind(this));
+    };
+
+    return Topology;
+  })();
+
+  var OvsNode = (function () {
+    function OvsNode(nodeId, inetMgr, inetNode, otherLocalIp, ovsVersion) {
+      this.nodeId = nodeId;
+      this.inetMgr = inetMgr;
+      this.inetNode = inetNode;
+      this.otherLocalIp = otherLocalIp;
+      this.ovsVersion = ovsVersion;
+    }
+
+    OvsNode.prototype.showIpAdress = function () {
+      return this.otherLocalIp;
+    };
+
+    OvsNode.prototype.pretty = function () {
+      return {
+        'tabs': ['Info'],
+        'containts': [{
+          'hasHeader': false,
+          'headers': [],
+          'datas': [
+            {
+              key: 'ID',
+              value: this.nodeId
+            },
+            {
+              key: 'InetMgr',
+              value: this.inetMgr
+            },
+            {
+              key: 'InetNode',
+              value: this.inetNode
+            },
+            {
+              key: 'Local IP',
+              value: this.otherLocalIp
+            },
+            {
+              key: 'OVS Version',
+              value: this.ovsVersion
+            }
+          ]
+        }]
+      };
+    };
+
+    return OvsNode;
+  })();
+
+  var BridgeNode = (function () {
+
+    function BridgeNode(nodeId, dpIp, name, controllerTarget, controllerConnected) {
+      this.nodeId = nodeId;
+      this.dpIp = dpIp;
+      this.name = name;
+      this.controllerTarget = controllerTarget;
+      this.controllerConnected = controllerConnected;
+      this._tpList = [];
+      this.flowInfo = {};
+      this.flowTable = [];
+    }
+
+    Object.defineProperties(BridgeNode.prototype, {
+      tPs: {
+        get: function () {
+          return this._tpList;
+        }
+      },
+    });
+
+    var dpToFlow = function (dpId) {
+      return 'openflow:' + parseInt(dpId.replace(/:/g, ''), 16);
+    };
+
+    BridgeNode.prototype.getFLowName = function () {
+      return (!this.dpIp) ? this.nodeId : dpToFlow(this.dpIp);
+    };
+
+    BridgeNode.prototype.addTerminationPoint = function (tp) {
+      this._tpList.push(tp);
+      this._tpList.sort(function (tp1, tp2) {
+        return tp1.ofPort - tp2.ofPort;
+      });
+    };
+
+    BridgeNode.prototype.addFlowTableInfo = function (flowTable) {
+      this.flowTable.push(flowTable);
+      this.flowTable.sort(function (ft1, ft2) {
+        return ft1.key - ft2.key;
+      });
+    };
+
+    BridgeNode.prototype.pretty = function () {
+      return {
+        'tabs': [
+          'Basic Info',
+          'Ports',
+          'Flow Info',
+          'Flow Tables'
+        ],
+        'containts': [
+          {
+            'hasHeader': false,
+            'headers': [],
+            'datas': [
+              {
+                key: 'ID',
+                value: this.nodeId
+              },
+              {
+                key: 'Name',
+                value: this.name
+              },
+              {
+                key: 'OpenFlow Name',
+                value: this.getFLowName()
+              },
+              {
+                key: 'Controller Target',
+                value: this.controllerTarget
+              },
+              {
+                key: 'Controller Connected',
+                value: this.controllerConnected
+              }
+            ]
+          },
+          {
+            'hasHeader': true,
+            'header': ['Of Port', 'Name', 'Mac', 'IFace Id', ],
+            'datas': this._tpList.map(function (s) {
+              return [s.ofPort, s.name, s.mac, s.ifaceId];
+            })
+          },
+          {
+            'hasHeader': false,
+            'headers': [],
+            'datas': [
+              {
+                key: 'Manufacturer',
+                value: this.flowInfo.manufacturer
+              },
+              {
+                key: 'Hardware',
+                value: this.flowInfo.hardware
+              },
+              {
+                key: 'Software',
+                value: this.flowInfo.software
+              },
+              {
+                key: 'Feature',
+                value: this.flowInfo.features
+              },
+              {
+                key: 'Ip',
+                value: this.flowInfo.ip
+              }
+              ]
+          },
+          {
+            'hasHeader': true,
+            'headers': ['Table Id', 'Value'],
+            'datas': this.flowTable.map(function (t) {
+              return [t.key, t.value];
+            })
+          }
+        ]
+      };
+    };
+
+    return BridgeNode;
+  })();
+
+  var TerminationPoint = (function () {
+    function TerminationPoint(name, ofPort, tpType, mac, ifaceId) {
+      this.name = name;
+      this.ofPort = ofPort;
+      this.tpType = tpType;
+      this.mac = mac || '';
+      this.ifaceId = ifaceId || '';
+    }
+    return TerminationPoint;
+  })();
+
+  var Tunnel = (function () {
+    function Tunnel(name, ofPort, tpType, mac, ifaceId, localIp, remoteIp) {
+      TerminationPoint.call(this, name, ofPort, tpType, mac, ifaceId);
+      this.localIp = localIp;
+      this.remoteIp = remoteIp;
+    }
+    Tunnel.prototype = Object.create(TerminationPoint.prototype);
+    Tunnel.prototype.constructor = Tunnel;
+
+    return Tunnel;
+  })();
+
+  var BaseLink = (function () {
+    function BaseLink(linkId, srcNodeId, destNodeId, linkType, styles) {
+      this.linkId = linkId;
+      this.srcNodeId = srcNodeId;
+      this.destNodeId = destNodeId;
+      this.linkType = linkType;
+
+      // styling
+      styles = _.extend({}, styles);
+      this.color = styles.color;
+      this.width = styles.width || 1;
+      this.dashArray = styles.dashArray || 'None';
+
+      // d3js needed values
+      this.source = -1;
+      this.target = -1;
+    }
+    return BaseLink;
+  })();
+
+  var Link = (function () {
+    function Link(linkId, srcNodeId, destNodeId) {
+      var opt = {
+        color: 'black'
+      };
+
+      BaseLink.call(this, linkId, srcNodeId, destNodeId, 'link', opt);
+    }
+
+    Link.prototype = Object.create(BaseLink.prototype);
+    Link.prototype.constructor = Link;
+
+    return Link;
+  })();
+
+  var TunnelLink = (function () {
+    function TunnelLink(linkId, srcNodeId, destNodeId, linkType, color) {
+      var opt = {
+        color: 'green',
+        width: 2,
+        dashArray: '5,5'
+      };
+      BaseLink.call(this, linkId, srcNodeId, destNodeId, 'tunnel', opt);
+    }
+
+    TunnelLink.prototype = Object.create(BaseLink.prototype);
+    TunnelLink.prototype.constructor = TunnelLink;
+
+    return TunnelLink;
+  })();
+
+  var BridgeOvsLink = (function () {
+    function BridgeOvsLink(linkId, srcNodeId, destNodeId, linkType, color) {
+      var opt = {
+        color: 'gray',
+        dashArray: '10,10'
+      };
+      BaseLink.call(this, linkId, srcNodeId, destNodeId, 'bridgeOvsLink', opt);
+    }
+
+    BridgeOvsLink.prototype = Object.create(BaseLink.prototype);
+    BridgeOvsLink.prototype.constructor = BridgeOvsLink;
+
+    return BridgeOvsLink;
+  })();
+
+  var Util = (function () {
+    var Maths = (function () {
+      function Maths() {
+
+      }
+      // random function in javascript use timespan only
+      Maths.Random = function (nseed) {
+        var constant = Math.pow(2, 13) + 1,
+          prime = 1987,
+          maximum = 1000;
+
+        if (nseed) {
+          seed = nseed;
+        }
+
+        return {
+          next: function (min, max) {
+            seed *= constant;
+            seed += prime;
+
+            return min && max ? min + seed % maximum / maximum * (max - min) : seed % maximum / maximum;
+          }
+        };
+      };
+      return Maths;
+    })();
+
+    var String = (function () {
+
+      function String() {
+
+      }
+      String.Format = function () {
+        var s = arguments[0];
+        for (var i = 0; i < arguments.length - 1; i++) {
+          var reg = new RegExp("\\{" + i + "\\}", "gm");
+          s = s.replace(reg, arguments[i + 1]);
+        }
+        return s;
+      };
+
+      return String;
+
+    })();
+    return {
+      Math: Maths,
+      String: String
+    };
+  })();
+
+  var Neutron = (function () {
+
+    var SubNet = (function () {
+      function SubNet(id, networkId, name, ipVersion, cidr, gatewayIp, tenantId) {
+        this.id = id;
+        this.networkId = networkId;
+        this.name = name;
+        this.ipVersion = ipVersion;
+        this.cidr = cidr;
+        this.gatewayIp = gatewayIp;
+        this.tenantId = tenantId;
+      }
+      return SubNet;
+    })();
+
+    var Network = (function () {
+      function Network(id, name, shared, status, external, tenantId) {
+        this.id = id;
+        this.ip = '';
+        this.name = name;
+        this.shared = shared;
+        this.status = status;
+        this.external = external;
+        this.tenantId = tenantId;
+        this.subnets = [];
+        this.instances = [];
+        this.routers = [];
+      }
+
+      Network.prototype.addSubNets = function (subnets) {
+        if (subnets) {
+          if (_.isArray(subnets)) {
+            var i = 0;
+            for (; i < subnets.length; ++i) {
+              this.subnets.push(subnets[i]);
+            }
+          } else {
+            this.subnets.push(subnet);
+          }
+        }
+      };
+
+      Network.prototype.asSubnet = function (subnet) {
+        return _.every(subnet, function (sub) {
+          return _.some(this.subnets, function (s) {
+            return s.id === sub;
+          });
+        }.bind(this));
+      };
+
+      Network.prototype.pretty = function () {
+        return {
+          'tabs': [
+            'Info',
+            'Subnets'
+          ],
+          'containts': [
+            {
+              'hasHeader': false,
+              'headers': [],
+              'datas': [
+                {
+                  key: 'ID',
+                  value: this.id
+                },
+                {
+                  key: 'Ip',
+                  value: this.ip
+                },
+                {
+                  key: 'Name',
+                  value: this.name
+                },
+                {
+                  key: 'Shared',
+                  value: this.shared
+                },
+                {
+                  key: 'Status',
+                  value: this.status
+                },
+                {
+                  key: 'External',
+                  value: this.external
+                },
+                {
+                  key: 'Tenant Id',
+                  value: this.tenantId
+                }
+              ]
+            },
+            {
+              'hasHeader': true,
+              'header': ['ID', 'Name', 'Ip Version', 'Ip', 'Gateway Ip'],
+              'datas': this.subnets.map(function (s) {
+                return [s.id, s.name, s.ipVersion, s.cidr, s.gatewayIp];
+              })
+            }
+          ]
+        };
+      };
+
+      return Network;
+    })();
+
+    var Port = (function () {
+      function Port(id, networkId, name, tenantId, deviceId, deviceOwner, fixed_ips, mac) {
+        this.id = id;
+        this.networkId = networkId;
+        this.name = name;
+        this.tenantId = '' + tenantId || '';
+        this.deviceId = deviceId;
+        this.deviceOwner = deviceOwner;
+        this.fixed_ips = fixed_ips;
+        this.mac = mac;
+      }
+
+      Port.prototype.pretty = function () {
+        return [
+          {
+            key: 'ID',
+            value: this.id
+          },
+          {
+            key: 'Name',
+            value: name
+          },
+          {
+            key: 'Tenant Id',
+            value: this.tenantId
+          },
+          {
+            key: 'Device Id',
+            value: this.deviceId
+          },
+          {
+            key: 'Device Owner',
+            value: this.deviceOwner
+          },
+          {
+            key: 'MAC',
+            value: this.mac
+          }
+        ];
+      };
+
+      return Port;
+    })();
+
+    var Router = (function () {
+      function Router(id, name, status, tenantId, externalGateway) {
+        this.id = id;
+        this.name = name;
+        this.status = status;
+        this.tenantId = tenantId;
+        this.interfaces = [];
+        this.externalGateway = externalGateway;
+      }
+
+      Router.prototype.pretty = function () {
+        return {
+          'tabs': [
+            'Info',
+            'Interfaces'
+          ],
+          'containts': [
+            {
+              'hasHeader': false,
+              'headers': [],
+              'datas': [
+                {
+                  key: 'ID',
+                  value: this.id
+                },
+                {
+                  key: 'Name',
+                  value: this.name
+                },
+                {
+                  key: 'status',
+                  value: this.status
+                },
+                {
+                  key: 'Tenant ID',
+                  value: this.tenantId
+                }
+              ]
+            },
+            {
+              'hasHeader': true,
+              'header': ['ID', 'Type', 'Mac Address', 'Ip', 'Tenant Id'],
+              'datas': this.interfaces.map(function (s) {
+                return [s.id, s.type, s.mac, s.ip.ip_address, s.tenantId];
+              })
+            }
+          ]
+        };
+      };
+
+      return Router;
+    })();
+
+    var Instance = (function () {
+      function Instance(id, networkId, name, ip, mac, deviceOwner, tenantId, topoInfo) {
+        this.id = id;
+        this.networkId = networkId;
+        this.name = name;
+        this.ip = ip;
+        this.mac = '' + mac;
+        this.type = deviceOwner;
+        this.tenantId = tenantId;
+        this.topoInfo = topoInfo || [];
+        this.floatingIp = {};
+      }
+
+      Instance.prototype.extractFloatingIps = function (floatingIps) {
+        var ctx = this;
+        this.floatingIp = _.find(floatingIps, function (fIp) {
+          return fIp.tenantId === ctx.tenantId &&
+            fIp.fixedIp === ctx.ip;
+        });
+      };
+
+      Instance.prototype.pretty = function () {
+        return {
+          'tabs': [
+            'Info',
+            'Ports'
+          ],
+          'containts': [
+            {
+              'hasHeader': false,
+              'headers': [],
+              'datas': [
+                {
+                  key: 'ID',
+                  value: this.id
+                },
+                {
+                  key: "Network Id",
+                  value: this.networkId
+                },
+                {
+                  key: 'Name',
+                  value: this.name
+                },
+                {
+                  key: 'Ip',
+                  value: this.ip
+                },
+                {
+                  key: 'Floating Ip',
+                  value: (this.floatingIp) ? this.floatingIp.ip : 'Not found'
+                },
+                {
+                  key: 'MAC',
+                  value: this.mac
+                },
+                {
+                  key: 'Type',
+                  value: this.type
+                },
+                {
+                  key: 'Tenant ID',
+                  value: this.tenantId
+                }
+              ]
+            },
+            {
+              'hasHeader': true,
+              'header': ['Name', 'Of Port', 'Mac', 'Flow', 'Ovsdb Node', 'Ovsdb Node IP'],
+              'datas': this.topoInfo.map(function (s) {
+                return [s.name, s.ofPort, s.mac, s.bridge.getFLowName(), s.ovsNode.nodeId, s.ovsNode.showIpAdress()];
+              })
+            }
+          ]
+        };
+      };
+
+      return Instance;
+    })();
+
+    var FloatingIp = (function () {
+      function FloatingIp(id, networkId, portId, fixedIp, floatingIp, tentantId, status) {
+        this.id = id;
+        this.networkId = networkId;
+        this.portId = portId;
+        this.fixedIp = fixedIp;
+        this.ip = floatingIp;
+        this.tenantId = tentantId;
+        this.status = status;
+      }
+
+      return FloatingIp;
+    })();
+
+    return {
+      Network: Network,
+      Port: Port,
+      Instance: Instance,
+      FloatingIp: FloatingIp,
+      Router: Router,
+      SubNet: SubNet
+    };
+  })();
+
+  return {
+    OvsNode: OvsNode,
+    BridgeNode: BridgeNode,
+    TerminationPoint: TerminationPoint,
+    Topology: Topology,
+    Tunnel: Tunnel,
+    BaseLink: BaseLink,
+    Link: Link,
+    TunnelLink: TunnelLink,
+    BridgeOvsLink: BridgeOvsLink,
+    Util: Util,
+    Neutron: Neutron
+  };
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png b/ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png
new file mode 100644 (file)
index 0000000..d52cbd4
Binary files /dev/null and b/ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png differ
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png b/ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png
new file mode 100644 (file)
index 0000000..fde4ce5
Binary files /dev/null and b/ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png differ
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png b/ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png
new file mode 100644 (file)
index 0000000..50cbcf6
Binary files /dev/null and b/ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png differ
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/css/ovsdb.css b/ovsdb-ui/module/src/main/resources/ovsdb/css/ovsdb.css
new file mode 100644 (file)
index 0000000..a27e9b1
--- /dev/null
@@ -0,0 +1,220 @@
+/*\r
+ * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+*/\r
+\r
+#errorMessage {\r
+  display: none;\r
+}\r
+.switch-light {\r
+  width: 140px;\r
+}\r
+.switch-light span > span {\r
+  color: black;\r
+}\r
+.link {\r
+  stroke: #999;\r
+  stroke-opacity: 0.8;\r
+}\r
+.form-inline > span,\r
+label {\r
+  padding-right: 15px;\r
+}\r
+#list_container {\r
+  border: 1px solid white;\r
+  background-color: #414042;\r
+  height: 600px;\r
+}\r
+#list_container label {\r
+  color: white;\r
+}\r
+svg,\r
+#list_container {\r
+  width: 100%;\r
+}\r
+svg {\r
+  border: none;\r
+  border-radius: 0;\r
+  background-image: none;\r
+  background-color: white;\r
+  height: 580px;\r
+}\r
+#list_container > .row {\r
+  margin-left: 15px;\r
+  margin-right: 15px;\r
+}\r
+.container {\r
+  padding-top: 15px;\r
+  width: 1200px;\r
+}\r
+.row {\r
+  padding-bottom: 15px;\r
+}\r
+.select2-selection__choice {\r
+  background-color: orange !important;\r
+  border-color: black !important;\r
+  color: black !important;\r
+}\r
+.select2-selection__choice > span {\r
+  color: black !important;\r
+}\r
+.select2-results {\r
+  color: black !important;\r
+}\r
+.table.table-bordered {\r
+  background-color: white;\r
+  color: black;\r
+}\r
+#graph_header {\r
+  width: 100%;\r
+  height: 20px;\r
+  background-color: white;\r
+  border-bottom: 1px solid #ccc;\r
+}\r
+.icon-fullscreen,\r
+.icon-resize-small {\r
+  margin-right: 5px;\r
+  margin-top: 2px;\r
+}\r
+.bg_rect {\r
+  fill: #FFA6A6;\r
+  opacity: .4;\r
+  stroke: #ff0000;\r
+}\r
+kbd {\r
+  color: #333;\r
+  border-radius: 3px;\r
+  padding: 2px 4px;\r
+  font-size: 90%;\r
+  background-color: #DDD;\r
+  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.25);\r
+}\r
+.network_info {\r
+  text-align: center;\r
+  width: 170px;\r
+  height: 80px;\r
+  padding: 5px;\r
+  border-radius: 5px;\r
+  border: 1px solid black;\r
+}\r
+#network_summary {\r
+  width: auto;\r
+  height: auto;\r
+  left: 15px;\r
+  padding: 5px;\r
+}\r
+.graph_window {\r
+  position: absolute !important;\r
+  background-color: rgba(255, 255, 255, 0.7);\r
+  -webkit-box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+  -moz-box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+  box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+  padding: 5px;\r
+  z-index: 2;\r
+  border-radius: 5px;\r
+  top: 25px;\r
+  min-height: 35px;\r
+  min-width: 100px;\r
+  overflow: hidden;\r
+}\r
+#graph_summary {\r
+  width: 160px;\r
+  height: 100px;\r
+  right: 10px;\r
+}\r
+\r
+div.window_body {\r
+  height: 80%;\r
+  font-size:12px;\r
+  color:#ccc;\r
+}\r
+div.window_content {\r
+  position:relative;\r
+  max-height:350px;\r
+  height:100%;\r
+  overflow-y: auto;\r
+}\r
+div.window_header > hr {\r
+  margin-top: 0;\r
+  margin-bottom: 10px;\r
+}\r
+div.window_header > span {\r
+  width: 100%;\r
+  display: inline;\r
+}\r
+#network_table_window,\r
+#node_table_window {\r
+  width: 355px;\r
+  height: 215px;\r
+}\r
+#node_table_window {\r
+  top: 300px;\r
+  left: 25px;\r
+}\r
+#network_table_window {\r
+  top: 300px;\r
+  right: 25px;\r
+}\r
+.window-icon {\r
+  color: black;\r
+  float: right;\r
+  margin-right: 5px;\r
+}\r
+.window-icon:hover {\r
+  background-color: #ddd;\r
+  cursor: pointer;\r
+}\r
+\r
+.linfolabel {\r
+  font-size : 12px;\r
+  letter-spacing: 1px;\r
+}\r
+#tabs > ul > li > a {\r
+  color:white !important;\r
+}\r
+#tabs > ul > li.ui-state-active {\r
+  border: 1px solid white;\r
+}\r
+\r
+#tabs > ul > li.ui-state-hover > a{\r
+  color:black !important;\r
+}\r
+\r
+#tabs > ul > li > a:focus {\r
+  background-color:inherit !important;\r
+}\r
+\r
+#lDialog, #pDialog {\r
+  position:absolute;\r
+  font-size: 11px;\r
+  width: auto;\r
+  min-width: 450px;\r
+  display:none;\r
+  background-color: rgb(255, 255, 255);\r
+  border: 1px solid black;\r
+  border-radius: 10px;\r
+  height: auto;\r
+  padding: 10px;\r
+}\r
+\r
+.window_content > ul > li.ui-state-active {\r
+  border-top: 1px solid #dddddd;\r
+  border-left: 1px solid #dddddd;\r
+  border-right: 1px solid #dddddd;\r
+}\r
+\r
+.arrow-left {\r
+       width: 0;\r
+       height: 0;\r
+       border-top: 10px solid transparent;\r
+       border-bottom: 10px solid transparent;\r
+\r
+       border-right:10px solid blue;\r
+}\r
+\r
+span.selection {\r
+  font-size: 10px;\r
+}\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/css/select2.min.css b/ovsdb-ui/module/src/main/resources/ovsdb/css/select2.min.css
new file mode 100755 (executable)
index 0000000..1c72344
--- /dev/null
@@ -0,0 +1 @@
+.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle;}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none;}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px;}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none;}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap;}.select2-container .select2-search--inline{float:left;}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none;}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051;}.select2-results{display:block;}.select2-results__options{list-style:none;margin:0;padding:0;}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none;}.select2-results__option[aria-selected]{cursor:pointer;}.select2-container--open .select2-dropdown{left:0;}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0;}.select2-search--dropdown{display:block;padding:4px;}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box;}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none;}.select2-search--dropdown.select2-search--hide{display:none;}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0);}.select2-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px;}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px;}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999;}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px;}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0;}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left;}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto;}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default;}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none;}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px;}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%;}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left;}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px;}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px;}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder{float:right;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto;}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0;}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default;}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none;}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0;}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa;}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;}.select2-container--default .select2-results__option[role=group]{padding:0;}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999;}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd;}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em;}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white;}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px;}.select2-container--classic .select2-selection--single{background-color:#f6f6f6;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #ffffff 50%, #eeeeee 100%);background-image:-o-linear-gradient(top, #ffffff 50%, #eeeeee 100%);background-image:linear-gradient(to bottom, #ffffff 50%, #eeeeee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb;}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px;}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px;}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999;}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#cccccc', GradientType=0);}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0;}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left;}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto;}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb;}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none;}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px;}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #ffffff 0%, #eeeeee 50%);background-image:-o-linear-gradient(top, #ffffff 0%, #eeeeee 50%);background-image:linear-gradient(to bottom, #ffffff 0%, #eeeeee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #ffffff 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #ffffff 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #ffffff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0;}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb;}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px;}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none;}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px;}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px;}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto;}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb;}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0;}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0;}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;}.select2-container--classic .select2-dropdown{background-color:white;border:1px solid transparent;}.select2-container--classic .select2-dropdown--above{border-bottom:none;}.select2-container--classic .select2-dropdown--below{border-top:none;}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;}.select2-container--classic .select2-results__option[role=group]{padding:0;}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey;}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:white;}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px;}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb;}
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/css/toggle-switch.css b/ovsdb-ui/module/src/main/resources/ovsdb/css/toggle-switch.css
new file mode 100644 (file)
index 0000000..78cb2b3
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+* CSS TOGGLE SWITCHES
+* Unlicense
+*
+* Ionuț Colceriu - ghinda.net
+* https://github.com/ghinda/css-toggle-switch
+*
+*/
+/* Supported values are px, rem-calc, em-calc */
+/* Functions */
+/* Toggle Switches */
+/* Shared */
+/* Checkbox
+*/
+/* Radio Switch
+*/
+/* Hide by default
+*/
+.switch-toggle a, .switch-light span span {
+  display: none; }
+
+/* We can't test for a specific feature,
+* so we only target browsers with support for media queries.
+*/
+@media only screen {
+  /* Checkbox switch
+  */
+  .switch-light {
+    display: block;
+    min-height: 1.875em;
+    /* Outline the toggles when the inputs are focused
+  */
+    position: relative;
+    overflow: visible;
+    padding: 0;
+    margin-left: 6.25em;
+    /* Position the label over all the elements, except the slide-button (<a>)
+  * Clicking anywhere on the label will change the switch-state
+  */
+    /* Don't hide the input from screen-readers and keyboard access
+  */ }
+    .switch-light * {
+      -webkit-box-sizing: border-box;
+      -moz-box-sizing: border-box;
+      box-sizing: border-box; }
+    .switch-light a {
+      display: block;
+      -webkit-transition: all 0.2s ease-out;
+      -moz-transition: all 0.2s ease-out;
+      transition: all 0.2s ease-out; }
+    .switch-light label, .switch-light > span {
+      line-height: 1.875em;
+      vertical-align: middle; }
+    .switch-light input:focus ~ a, .switch-light input:focus + label {
+      outline: 1px dotted #888; }
+    .switch-light label {
+      position: relative;
+      z-index: 3;
+      display: block;
+      width: 100%; }
+    .switch-light input {
+      position: absolute;
+      opacity: 0;
+      z-index: 5; }
+      .switch-light input:checked ~ a {
+        right: 0%; }
+    .switch-light > span {
+      position: absolute;
+      left: -6.25em;
+      width: 100%;
+      margin: 0;
+      padding-right: 6.25em;
+      text-align: left; }
+      .switch-light > span span {
+        position: absolute;
+        top: 0;
+        left: 0;
+        z-index: 5;
+        display: block;
+        width: 50%;
+        margin-left: 6.25em;
+        text-align: center; }
+        .switch-light > span span:last-child {
+          left: 50%; }
+    .switch-light a {
+      position: absolute;
+      right: 50%;
+      top: 0;
+      z-index: 4;
+      display: block;
+      width: 50%;
+      height: 100%;
+      padding: 0; }
+
+  /* Radio switch
+  */
+  .switch-toggle {
+    display: block;
+    min-height: 1.875em;
+    /* Outline the toggles when the inputs are focused
+  */
+    position: relative;
+    display: table;
+    table-layout: fixed;
+    /* For callout panels in foundation
+  */
+    padding: 0 !important;
+    /* Generate styles for the multiple states */ }
+    .switch-toggle * {
+      -webkit-box-sizing: border-box;
+      -moz-box-sizing: border-box;
+      box-sizing: border-box; }
+    .switch-toggle a {
+      display: block;
+      -webkit-transition: all 0.2s ease-out;
+      -moz-transition: all 0.2s ease-out;
+      transition: all 0.2s ease-out; }
+    .switch-toggle label, .switch-toggle > span {
+      line-height: 1.875em;
+      vertical-align: middle; }
+    .switch-toggle input:focus ~ a, .switch-toggle input:focus + label {
+      outline: 1px dotted #888; }
+    .switch-toggle * {
+      font-size: 1em; }
+    .switch-toggle input {
+      position: absolute;
+      opacity: 0; }
+    .switch-toggle input + label {
+      position: relative;
+      z-index: 2;
+      display: table-cell;
+      width: 50%;
+      padding: 0 0.5em;
+      margin: 0;
+      text-align: center; }
+    .switch-toggle a {
+      position: absolute;
+      top: 0;
+      left: 0;
+      padding: 0;
+      z-index: 1;
+      width: 50%;
+      height: 100%; }
+    .switch-toggle input:last-of-type:checked ~ a {
+      left: 50%; }
+    .switch-toggle.switch-3 label, .switch-toggle.switch-3 a {
+      width: 33.3333333333%; }
+    .switch-toggle.switch-3 input:checked:nth-of-type(2) ~ a {
+      left: 33.3333333333%; }
+    .switch-toggle.switch-3 input:checked:last-of-type ~ a {
+      left: 66.6666666667%; }
+    .switch-toggle.switch-4 label, .switch-toggle.switch-4 a {
+      width: 25%; }
+    .switch-toggle.switch-4 input:checked:nth-of-type(2) ~ a {
+      left: 25%; }
+    .switch-toggle.switch-4 input:checked:nth-of-type(3) ~ a {
+      left: 50%; }
+    .switch-toggle.switch-4 input:checked:last-of-type ~ a {
+      left: 75%; }
+    .switch-toggle.switch-5 label, .switch-toggle.switch-5 a {
+      width: 20%; }
+    .switch-toggle.switch-5 input:checked:nth-of-type(2) ~ a {
+      left: 20%; }
+    .switch-toggle.switch-5 input:checked:nth-of-type(3) ~ a {
+      left: 40%; }
+    .switch-toggle.switch-5 input:checked:nth-of-type(4) ~ a {
+      left: 60%; }
+    .switch-toggle.switch-5 input:checked:last-of-type ~ a {
+      left: 80%; }
+
+  /* Standalone Themes */
+  /* Candy Theme
+  * Based on the "Sort Switches / Toggles (PSD)" by Ormal Clarck
+  * http://www.premiumpixels.com/freebies/sort-switches-toggles-psd/
+  */
+  .switch-candy {
+    background-color: #2d3035;
+    border-radius: 3px;
+    color: #fff;
+    font-weight: bold;
+    text-align: center;
+    text-shadow: 1px 1px 1px #191b1e;
+    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.2); }
+    .switch-candy label {
+      color: #fff;
+      -webkit-transition: color 0.2s ease-out;
+      -moz-transition: color 0.2s ease-out;
+      transition: color 0.2s ease-out; }
+    .switch-candy input:checked + label {
+      color: #333;
+      text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); }
+    .switch-candy a {
+      border: 1px solid #333;
+      background-color: #70c66b;
+      border-radius: 3px;
+      background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+      background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+      box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.45); }
+    .switch-candy > span {
+      color: #333;
+      text-shadow: none; }
+    .switch-candy span {
+      color: #fff; }
+    .switch-candy.switch-candy-blue a {
+      background-color: #38a3d4; }
+    .switch-candy.switch-candy-yellow a {
+      background-color: #f5e560; }
+
+  /* Android Theme
+  */
+  .switch-android {
+    background-color: #464747;
+    border-radius: 1px;
+    box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0;
+    color: #fff;
+    /* Selected ON switch-light
+    */ }
+    .switch-android label {
+      color: #fff; }
+    .switch-android > span span {
+      opacity: 0;
+      margin-left: 7.1875em;
+      -webkit-transition: all 0.1s;
+      -moz-transition: all 0.1s;
+      transition: all 0.1s; }
+      .switch-android > span span:first-of-type {
+        opacity: 1; }
+    .switch-android > span span, .switch-android input + label {
+      font-size: 85%;
+      line-height: 2.15625em; }
+    .switch-android a {
+      background-color: #666;
+      border-radius: 1px;
+      box-shadow: inset rgba(255, 255, 255, 0.2) 0 1px 0, inset rgba(0, 0, 0, 0.3) 0 -1px 0; }
+    .switch-android.switch-light input:checked ~ a {
+      background-color: #0E88B1; }
+    .switch-android.switch-light input:checked ~ span span:first-of-type {
+      opacity: 0; }
+    .switch-android.switch-light input:checked ~ span span:last-of-type {
+      opacity: 1; }
+    .switch-android.switch-toggle, .switch-android > span span {
+      text-transform: uppercase; }
+
+  /* iOS Theme
+  */
+  .switch-ios.switch-light {
+    color: #868686; }
+    .switch-ios.switch-light a {
+      left: 0;
+      width: 1.875em;
+      background-color: #fff;
+      border: 1px solid #d3d3d3;
+      border-radius: 100%;
+      -webkit-transition: all 0.3s ease-out;
+      -moz-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+      box-shadow: inset 0 -3px 3px rgba(0, 0, 0, 0.025), 0 1px 4px rgba(0, 0, 0, 0.15), 0 4px 4px rgba(0, 0, 0, 0.1); }
+    .switch-ios.switch-light > span span {
+      width: 100%;
+      left: 0;
+      opacity: 0; }
+      .switch-ios.switch-light > span span:first-of-type {
+        opacity: 1;
+        padding-left: 1.875em; }
+      .switch-ios.switch-light > span span:last-of-type {
+        padding-right: 1.875em; }
+    .switch-ios.switch-light > span:before {
+      content: '';
+      display: block;
+      width: 100%;
+      height: 100%;
+      position: absolute;
+      left: 6.25em;
+      top: 0;
+      background-color: #fafafa;
+      border: 1px solid #d3d3d3;
+      border-radius: 30px;
+      -webkit-transition: all 0.5s ease-out;
+      -moz-transition: all 0.5s ease-out;
+      transition: all 0.5s ease-out;
+      box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+    .switch-ios.switch-light input:checked ~ a {
+      left: 100%;
+      margin-left: -1.875em; }
+    .switch-ios.switch-light input:checked ~ span:before {
+      border-color: #53d76a;
+      box-shadow: inset 0 0 0 30px #53d76a; }
+    .switch-ios.switch-light input:checked ~ span span:first-of-type {
+      opacity: 0; }
+    .switch-ios.switch-light input:checked ~ span span:last-of-type {
+      opacity: 1;
+      color: #fff; }
+  .switch-ios.switch-toggle {
+    background-color: #fafafa;
+    border: 1px solid #d3d3d3;
+    border-radius: 30px;
+    box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+    .switch-ios.switch-toggle a {
+      background-color: #53d76a;
+      border-radius: 25px;
+      -webkit-transition: all 0.3s ease-out;
+      -moz-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out; }
+    .switch-ios.switch-toggle label {
+      color: #868686; }
+  .switch-ios input:checked + label {
+    color: #3a3a3a; }
+ }
+
+/* Bugfix for older Webkit, including mobile Webkit. Adapted from
+* http://css-tricks.com/webkit-sibling-bug/
+*/
+@media only screen and (-webkit-max-device-pixel-ratio: 2) and (max-device-width: 80em) {
+  .switch-light, .switch-toggle {
+    -webkit-animation: webkitSiblingBugfix infinite 1s; } }
+
+@-webkit-keyframes webkitSiblingBugfix {
+  from {
+    -webkit-transform: translate3d(0, 0, 0); }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0); } }
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/lib/d3.min.js b/ovsdb-ui/module/src/main/resources/ovsdb/lib/d3.min.js
new file mode 100644 (file)
index 0000000..34d5513
--- /dev/null
@@ -0,0 +1,5 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function r(n){return null===n?0/0:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function l(){this._=Object.create(null)}function s(n){return(n+="")===pa||n[0]===va?va+n:n}function f(n){return(n+="")[0]===va?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=da.length;r>e;++e){var u=da[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new l;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function S(){ta.event.preventDefault()}function k(){for(var n,t=ta.event;n=t.sourceEvent;)t=n;return t}function E(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=ta.event;u.target=n,ta.event=u,t[u.type].apply(e,r)}finally{ta.event=i}}},t}function A(n){return ya(n,_a),n}function N(n){return"function"==typeof n?n:function(){return Ma(n,this)}}function C(n){return"function"==typeof n?n:function(){return xa(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ta.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function q(n){return n.trim().replace(/\s+/g," ")}function L(n){return new RegExp("(?:^|\\s+)"+ta.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=T(n).map(D);var u=n.length;return"function"==typeof t?r:e}function D(n){var t=L(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",q(u+" "+n))):e.setAttribute("class",q(u.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e?t.createElementNS(e,n):t.createElement(n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ta.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return ba(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function Z(n){return ya(n,Sa),n}function V(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,ra(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+ta.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=$;a>0&&(n=n.slice(0,a));var l=ka.get(n);return l&&(n=l,c=B),a?t?u:r:t?b:i}function $(n,t){return function(e){var r=ta.event;ta.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ta.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Aa,u="click"+r,i=ta.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ea&&(Ea="onselectstart"in e?!1:x(e.style,"userSelect")),Ea){var o=n(e).style,a=o[Ea];o[Ea]="none"}return function(n){if(i.on(r,null),Ea&&(o[Ea]=a),n){var t=function(){i.on(u,null)};i.on(u,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var u=r.createSVGPoint();if(0>Na){var i=t(n);if(i.scrollX||i.scrollY){r=ta.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Na=!(o.f||o.e),r.remove()}}return Na?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ta.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nt(n){return n>1?0:-1>n?qa:Math.acos(n)}function tt(n){return n>1?Ra:-1>n?-Ra:Math.asin(n)}function et(n){return((n=Math.exp(n))-1/n)/2}function rt(n){return((n=Math.exp(n))+1/n)/2}function ut(n){return((n=Math.exp(2*n))-1)/(n+1)}function it(n){return(n=Math.sin(n/2))*n}function ot(){}function at(n,t,e){return this instanceof at?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof at?new at(n.h,n.s,n.l):bt(""+n,_t,at):new at(n,t,e)}function ct(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new mt(u(n+120),u(n),u(n-120))}function lt(n,t,e){return this instanceof lt?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof lt?new lt(n.h,n.c,n.l):n instanceof ft?gt(n.l,n.a,n.b):gt((n=wt((n=ta.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new lt(n,t,e)}function st(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new ft(e,Math.cos(n*=Da)*t,Math.sin(n)*t)}function ft(n,t,e){return this instanceof ft?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof ft?new ft(n.l,n.a,n.b):n instanceof lt?st(n.h,n.c,n.l):wt((n=mt(n)).r,n.g,n.b):new ft(n,t,e)}function ht(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=pt(u)*Xa,r=pt(r)*$a,i=pt(i)*Ba,new mt(dt(3.2404542*u-1.5371385*r-.4985314*i),dt(-.969266*u+1.8760108*r+.041556*i),dt(.0556434*u-.2040259*r+1.0572252*i))}function gt(n,t,e){return n>0?new lt(Math.atan2(e,t)*Pa,Math.sqrt(t*t+e*e),n):new lt(0/0,0/0,n)}function pt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function vt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function dt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mt(n,t,e){return this instanceof mt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mt?new mt(n.r,n.g,n.b):bt(""+n,mt,ct):new mt(n,t,e)}function yt(n){return new mt(n>>16,n>>8&255,255&n)}function Mt(n){return yt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(kt(u[0]),kt(u[1]),kt(u[2]))}return(i=Ga.get(n.toLowerCase()))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new at(r,u,c)}function wt(n,t,e){n=St(n),t=St(t),e=St(e);var r=vt((.4124564*n+.3575761*t+.1804375*e)/Xa),u=vt((.2126729*n+.7151522*t+.072175*e)/$a),i=vt((.0193339*n+.119192*t+.9503041*e)/Ba);return ft(116*u-16,500*(r-u),200*(u-i))}function St(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function kt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Et(n){return"function"==typeof n?n:function(){return n}}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Nt(t,e,n,r)}}function Nt(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return void o.error.call(i,r)}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=ta.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=ta.event;ta.event=n;try{o.progress.call(i,c)}finally{ta.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ra(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},ta.rebind(i,o,"on"),null==r?i:i.get(Ct(r))}function Ct(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qt(){var n=Lt(),t=Tt()-n;t>24?(isFinite(t)&&(clearTimeout(tc),tc=setTimeout(qt,t)),nc=0):(nc=1,rc(qt))}function Lt(){var n=Date.now();for(ec=Ka;ec;)n>=ec.t&&(ec.f=ec.c(n-ec.t)),ec=ec.n;return n}function Tt(){for(var n,t=Ka,e=1/0;t;)t.f?t=n?n.n=t.n:Ka=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Qa=n,e}function Rt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Dt(n,t){var e=Math.pow(10,3*ga(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=ic.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=oc.get(g)||Ut;var M=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=ta.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!l&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new cc(e-1)),1),e}function i(n,e){return t(n=new cc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{cc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{cc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{cc=jt;var r=new jt;return r._=t,n(r,e)._}finally{cc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(u=sc[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=N[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.slice(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&cc!==jt,o=new(i?jt:cc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=C[o in sc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,N.c.toString(),t,r)}function c(n,t,r){return e(n,N.x.toString(),t,r)}function l(n,t,r){return e(n,N.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{cc=jt;var t=new cc;return t._=n,r(t)}finally{cc=Date}}var r=t(n);return e.parse=function(n){try{cc=jt;var t=r.parse(n);return t&&t._}finally{cc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var M=ta.map(),x=Yt(v),b=Zt(v),_=Yt(d),w=Zt(d),S=Yt(m),k=Zt(m),E=Yt(y),A=Zt(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var N={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return It(n.getDate(),t,2)},e:function(n,t){return It(n.getDate(),t,2)},H:function(n,t){return It(n.getHours(),t,2)},I:function(n,t){return It(n.getHours()%12||12,t,2)},j:function(n,t){return It(1+ac.dayOfYear(n),t,3)},L:function(n,t){return It(n.getMilliseconds(),t,3)},m:function(n,t){return It(n.getMonth()+1,t,2)},M:function(n,t){return It(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return It(n.getSeconds(),t,2)},U:function(n,t){return It(ac.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return It(ac.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return It(n.getFullYear()%100,t,2)},Y:function(n,t){return It(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},C={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function It(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Yt(n){return new RegExp("^(?:"+n.map(ta.requote).join("|")+")","i")}function Zt(n){for(var t=new l,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Vt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Xt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function $t(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Bt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Wt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.y=Gt(+r[0]),e+r[0].length):-1}function Jt(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Gt(n){return n+(n>68?1900:2e3)}function Kt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=ga(t)/60|0,u=ga(t)%60;return e+It(r,"0",2)+It(u,"0",2)}function oe(n,t,e){hc.lastIndex=0;var r=hc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ce(){}function le(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function se(n,t){n&&dc.hasOwnProperty(n.type)&&dc[n.type](n,t)}function fe(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function he(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)fe(n[e],t,1);t.polygonEnd()}function ge(){function n(n,t){n*=Da,t=t*Da/2+qa/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);yc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;Mc.point=function(o,a){Mc.point=n,r=(t=o)*Da,u=Math.cos(a=(e=a)*Da/2+qa/4),i=Math.sin(a)},Mc.lineEnd=function(){n(t,e)}}function pe(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Me(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function xe(n){return[Math.atan2(n[1],n[0]),tt(n[2])]}function be(n,t){return ga(n[0]-t[0])<Ca&&ga(n[1]-t[1])<Ca}function _e(n,t){n*=Da;var e=Math.cos(t*=Da);we(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function we(n,t,e){++xc,_c+=(n-_c)/xc,wc+=(t-wc)/xc,Sc+=(e-Sc)/xc}function Se(){function n(n,u){n*=Da;var i=Math.cos(u*=Da),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);bc+=l,kc+=l*(t+(t=o)),Ec+=l*(e+(e=a)),Ac+=l*(r+(r=c)),we(t,e,r)}var t,e,r;qc.point=function(u,i){u*=Da;var o=Math.cos(i*=Da);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),qc.point=n,we(t,e,r)}}function ke(){qc.point=_e}function Ee(){function n(n,t){n*=Da;var e=Math.cos(t*=Da),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-nt(g)/h,v=Math.atan2(h,g);Nc+=p*l,Cc+=p*s,zc+=p*f,bc+=v,kc+=v*(r+(r=o)),Ec+=v*(u+(u=a)),Ac+=v*(i+(i=c)),we(r,u,i)}var t,e,r,u,i;qc.point=function(o,a){t=o,e=a,qc.point=n,o*=Da;var c=Math.cos(a*=Da);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),we(r,u,i)},qc.lineEnd=function(){n(t,e),qc.lineEnd=ke,qc.point=_e}}function Ae(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function Ne(){return!0}function Ce(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(be(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return void u.lineEnd()}var c=new qe(e,n,null,!0),l=new qe(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new qe(r,n,null,!1),l=new qe(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),ze(i),ze(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ze(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function qe(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Le(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function l(){y.point=o,d.lineEnd()}function s(n,t){v.push([n,t]);var e=u(n,t);x.point(e[0],e[1])}function f(){x.lineStart(),v=[]}function h(){s(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(b||(i.polygonStart(),b=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=ta.merge(g);var n=Fe(m,p);g.length?(b||(i.polygonStart(),b=!0),Ce(g,De,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Re(),x=t(M),b=!1;return y}}function Te(n){return n.length>1}function Re(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function De(n,t){return((n=n.x)[0]<0?n[1]-Ra-Ca:Ra-n[1])-((t=t.x)[0]<0?t[1]-Ra-Ca:Ra-t[1])}function Pe(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?qa:-qa,c=ga(i-e);ga(c-qa)<Ca?(n.point(e,r=(r+o)/2>0?Ra:-Ra),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=qa&&(ga(e-u)<Ca&&(e-=u*Ca),ga(i-a)<Ca&&(i-=a*Ca),r=Ue(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function Ue(n,t,e,r){var u,i,o=Math.sin(n-e);return ga(o)>Ca?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function je(n,t,e,r){var u;if(null==n)u=e*Ra,r.point(-qa,u),r.point(0,u),r.point(qa,u),r.point(qa,0),r.point(qa,-u),r.point(0,-u),r.point(-qa,-u),r.point(-qa,0),r.point(-qa,u);else if(ga(n[0]-t[0])>Ca){var i=n[0]<t[0]?qa:-qa;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function Fe(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;yc.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+qa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+qa/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>qa,k=p*M;if(yc.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*La:b,S^h>=e^m>=e){var E=de(pe(f),pe(n));Me(E);var A=de(u,E);Me(A);var N=(S^b>=0?-1:1)*tt(A[2]);(r>N||r===N&&(E[0]||E[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Ca>i||Ca>i&&0>yc)^1&o}function He(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?qa:-qa),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(be(e,g)||be(p,g))&&(p[0]+=Ca,p[1]+=Ca,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&be(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),M=m*m-y*(ve(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=ye(d,(-m-x)/y);if(me(b,p),b=xe(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=ga(A-qa)<Ca,C=N||Ca>A;if(!N&&k>E&&(_=k,k=E,E=_),C?N?k+E>0^b[1]<(ga(b[0]-w)<Ca?k:E):k<=b[1]&&b[1]<=E:A>qa^(w<=b[0]&&b[0]<=S)){var z=ye(d,(-m+x)/y);return me(z,p),[b,xe(z)]}}}function u(t,e){var r=o?n:qa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ga(i)>Ca,c=gr(n,6*Da);return Le(t,e,c,o?[0,-n]:[-qa,n-qa])}function Oe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Ie(n,t,e,r){function u(r,u){return ga(r[0]-n)<Ca?u>0?0:3:ga(r[0]-e)<Ca?u>0?2:1:ga(r[1]-t)<Ca?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&Q(l,i,n)>0&&++t:i[1]<=r&&Q(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=0/0}function g(){v&&(p(y,M),x&&w&&A.rejoin(),v.push(A.buffer())),C.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Tc,Math.min(Tc,n)),t=Math.max(-Tc,Math.min(Tc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};N(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,m,y,M,x,b,_,w,S,k,E=a,A=Re(),N=Oe(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=ta.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return C}}function Ye(n){var t=0,e=qa/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*qa/180,e=n[1]*qa/180):[t/qa*180,e/qa*180]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,tt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Dc+=u*n-r*t,r=n,u=t}var t,e,r,u;Hc.point=function(i,o){Hc.point=n,t=r=i,e=u=o},Hc.lineEnd=function(){n(t,e)}}function Xe(n,t){Pc>n&&(Pc=n),n>jc&&(jc=n),Uc>t&&(Uc=t),t>Fc&&(Fc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){_c+=n,wc+=t,++Sc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);kc+=o*(t+n)/2,Ec+=o*(e+r)/2,Ac+=o,We(t=n,e=r)}var t,e;Ic.point=function(r,u){Ic.point=n,We(t=r,e=u)}}function Ge(){Ic.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);kc+=o*(r+n)/2,Ec+=o*(u+t)/2,Ac+=o,o=u*n-r*t,Nc+=o*(r+n),Cc+=o*(u+t),zc+=3*o,We(r=n,u=t)}var t,e,r,u;Ic.point=function(i,o){Ic.point=n,We(t=r=i,e=u=o)},Ic.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,La)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(M,x,y,b,_,w,M=o[0],x=o[1],y=e,b=i[0],_=i[1],w=i[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c
+},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=a+g,_=c+p,w=l+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),E=ga(ga(w)-1)<Ca||ga(r-h)<Ca?(r+h)/2:Math.atan2(_,b),A=n(E,k),N=A[0],C=A[1],z=N-t,q=C-e,L=M*z-y*q;(L*L/x>i||ga((y*z+M*q)/x-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,N,C,E,b/=S,_/=S,w,d,m),m.point(N,C),u(N,C,E,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Da),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Pa,e*Pa])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*Da,n[1]*Da),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Pa,n[1]*Pa]}function r(){a=Ae(o=lr(m,M,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Lc,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(b(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Lc):He((w=+n)*Da),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Ie(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Da,d=n[1]%360*Da,r()):[v*Pa,d*Pa]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Da,M=n[1]%360*Da,x=n.length>2?n[2]%360*Da:0,r()):[m*Pa,M*Pa,x*Pa]},ta.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*Da,e*Da)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>qa?n-La:-qa>n?n+La:n,t]}function lr(n,t,e){return n?t||e?Ae(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>qa?t-La:-qa>t?t+La:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),tt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),tt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*La)):(u=n+o*La,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=xe([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,Me(e);var r=nt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Ca)%(2*Math.PI)}function vr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function Mr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(it(r-t)+u*o*it(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Pa,Math.atan2(o,Math.sqrt(r*r+u*u))*Pa]}:function(){return[n*Pa,t*Pa]};return p.distance=h,p}function xr(){function n(n,u){var i=Math.sin(u*=Da),o=Math.cos(u),a=ga((n*=Da)-t),c=Math.cos(a);Yc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Zc.point=function(u,i){t=u*Da,e=Math.sin(i*=Da),r=Math.cos(i),Zc.point=n},Zc.lineEnd=function(){Zc.point=Zc.lineEnd=b}}function br(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function _r(n,t){function e(n,t){o>0?-Ra+Ca>t&&(t=-Ra+Ca):t>Ra-Ca&&(t=Ra-Ca);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(qa/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ra]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ga(u)<Ca?ar:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-K(u)*Math.sqrt(n*n+e*e)]},e)}function Sr(n,t){return[n,Math.log(Math.tan(qa/4+t/2))]}function kr(n){var t,e=ur(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=qa*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qa/4+t/2)),-n]}function Ar(n){return n[0]}function Nr(n){return n[1]}function Cr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function qr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Lr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function Tr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=el.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Qc.remove(n),el.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ga(e-c.circle.x)<Ca&&ga(r-c.circle.cy)<Ca;)i=c.P,a.unshift(c),Pr(c),c=i;a.unshift(c),Xr(c);for(var l=o;l.circle&&ga(e-l.circle.x)<Ca&&ga(r-l.circle.cy)<Ca;)o=l.N,a.push(l),Pr(l),l=o;a.push(l),Xr(l);var s,f=a.length;for(s=1;f>s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Qc._;a;)if(r=Fr(a,o)-i,r>Ca)a=a.L;else{if(u=i-Hr(a,o),!(u>Ca)){r>-Ca?(t=a.P,e=a):u>-Ca?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Qc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Qc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),void Vr(e);if(!e)return void(c.edge=Jr(t.site,c.site));Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};Kr(e.edge,l,p,x),c.edge=Jr(l,n,null,x),e.edge=Jr(n,p,null,x),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Ir(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Kc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ga(r-t)>Ca||ga(u-e)>Ca)&&(a.splice(o,0,new Qr(Gr(i.site,s,ga(r-f)<Ca&&p-u>Ca?{x:f,y:ga(t-f)<Ca?e:p}:ga(u-p)<Ca&&h-r>Ca?{x:ga(e-p)<Ca?t:h,y:p}:ga(r-h)<Ca&&u-g>Ca?{x:h,y:ga(t-h)<Ca?e:g}:ga(u-g)<Ca&&r-f>Ca?{x:ga(e-g)<Ca?t:f,y:g}:null),i.site,null)),++c)}function Yr(n,t){return t.angle-n.angle}function Zr(){tu(this),this.x=this.y=this.arc=this.site=this.cy=null}function Vr(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,l=r.y-a,s=i.x-o,f=i.y-a,h=2*(c*f-l*s);if(!(h>=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=rl.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=tl._;M;)if(m.y<M.y||m.y===M.y&&m.x<=M.x){if(!M.L){y=M.P;break}M=M.L}else{if(!M.R){y=M;break}M=M.R}tl.insert(y,m),y||(nl=m)}}}}function Xr(n){var t=n.circle;t&&(t.P||(nl=t.N),tl.remove(t),rl.push(t),tu(t),n.circle=null)}function $r(n){for(var t,e=Gc,r=Oe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Br(t,n)||!r(t)||ga(t.a.x-t.b.x)<Ca&&ga(t.a.y-t.b.y)<Ca)&&(t.a=t.b=null,e.splice(u,1))}function Br(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],s=n.l,f=n.r,h=s.x,g=s.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.y<c)return}else i={x:d,y:l};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.y<c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Wr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Jr(n,t,e,r){var u=new Wr(n,t);return Gc.push(u),e&&Kr(u,n,t,e),r&&Kr(u,t,n,r),Kc[n.i].edges.push(new Qr(u,n,t)),Kc[t.i].edges.push(new Qr(u,t,n)),u}function Gr(n,t,e){var r=new Wr(n,null);return r.a=t,r.b=e,Gc.push(r),r}function Kr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Qr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function nu(){this._=null}function tu(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function eu(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ru(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function uu(n){for(;n.L;)n=n.L;return n}function iu(n,t){var e,r,u,i=n.sort(ou).pop();for(Gc=[],Kc=new Array(n.length),Qc=new nu,tl=new nu;;)if(u=nl,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Kc[i.i]=new Or(i),jr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;Ur(u.arc)}t&&($r(t),Ir(t));var o={cells:Kc,edges:Gc};return Qc=tl=Gc=Kc=null,o}function ou(n,t){return t.y-n.y||t.x-n.x}function au(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function cu(n){return n.x}function lu(n){return n.y}function su(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function fu(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&fu(n,c[0],e,r,o,a),c[1]&&fu(n,c[1],o,r,u,a),c[2]&&fu(n,c[2],e,a,o,i),c[3]&&fu(n,c[3],o,a,u,i)}}function hu(n,t,e,r,u,i,o){var a,c=1/0;return function l(n,s,f,h,g){if(!(s>i||f>o||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(c>m){var y=Math.sqrt(c=m);r=t-y,u=e-y,i=t+y,o=e+y,a=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:l(n,s,f,x,b);break;case 1:l(n,x,f,h,b);break;case 2:l(n,s,b,x,g);break;case 3:l(n,x,b,h,g)}}}(n,r,u,i,o),a}function gu(n,t){n=ta.rgb(n),t=ta.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function pu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=mu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function vu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function du(n,t){var e,r,u,i=il.lastIndex=ol.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=il.exec(n))&&(r=ol.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:vu(e,r)})),i=ol.lastIndex;return i<t.length&&(u=t.slice(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function mu(n,t){for(var e,r=ta.interpolators.length;--r>=0&&!(e=ta.interpolators[r](n,t)););return e}function yu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(mu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Mu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function bu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function wu(n){return n*n*n}function Su(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function ku(n){return function(t){return Math.pow(t,n)}}function Eu(n){return 1-Math.cos(n*Ra)}function Au(n){return Math.pow(2,10*(n-1))}function Nu(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/La*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*La/t)}}function zu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function qu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Lu(n,t){n=ta.hcl(n),t=ta.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return st(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=ta.hsl(n),t=ta.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){n=ta.lab(n),t=ta.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ht(e+i*n,r+o*n,u+a*n)+""}}function Du(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Pu(n){var t=[n.a,n.b],e=[n.c,n.d],r=ju(t),u=Uu(t,e),i=ju(Fu(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Pa,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Pa:0}function Uu(n,t){return n[0]*t[0]+n[1]*t[1]}function ju(n){var t=Math.sqrt(Uu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Fu(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Hu(n,t){var e,r=[],u=[],i=ta.transform(n),o=ta.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:vu(a[0],c[0])},{i:3,x:vu(a[1],c[1])})):r.push(c[0]||c[1]?"translate("+c+")":""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:vu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:vu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:vu(g[0],p[0])},{i:e-2,x:vu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Ou(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Iu(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Yu(n){for(var t=n.source,e=n.target,r=Vu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Zu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Vu(n,t){if(n===t)return n;for(var e=Zu(n),r=Zu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Xu(n){n.fixed|=2}function $u(n){n.fixed&=-7}function Bu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Wu(n){n.fixed&=-5}function Ju(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Ju(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Gu(n,t){return ta.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ri,n}function Ku(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Qu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function ni(n){return n.children}function ti(n){return n.value}function ei(n,t){return t.value-n.value}function ri(n){return ta.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function ui(n){return n.x}function ii(n){return n.y}function oi(n,t,e){n.y0=t,n.y=e}function ai(n){return ta.range(n.length)}function ci(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function li(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function si(n){return n.reduce(fi,0)}function fi(n,t){return n+t[1]}function hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function pi(n){return[ta.min(n),ta.max(n)]}function vi(n,t){return n.value-t.value}function di(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function mi(n,t){n._pack_next=t,t._pack_prev=n}function yi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Mi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],wi(r,u,i),t(i),di(r,i),r._pack_prev=i,di(i,u),u=r._pack_next,o=3;l>o;o++){wi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(yi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!yi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?mi(r,u=a):mi(r=c,u),o--):(di(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,M=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(bi)}}function xi(n){n._pack_next=n._pack_prev=n}function bi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)_i(u[i],t,e,r)}function wi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function Si(n,t){return n.parent==t.parent?1:2}function ki(n){var t=n.children;return t.length?t[0]:n.t}function Ei(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ai(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Ni(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function zi(n){return 1+ta.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function Ri(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Di(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Pi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return n.rangeExtent?n.rangeExtent():Pi(n.range())}function ji(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Fi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Hi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ml}function Oi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=ta.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ii(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Oi:ji,c=r?Iu:Ou;return o=u(n,t,c,e),a=u(t,n,c,mu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Du)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Xi(n,t)},i.tickFormat=function(t,e){return $i(n,t,e)},i.nice=function(t){return Zi(n,t),u()},i.copy=function(){return Ii(n,t,e,r)},u()}function Yi(n,t){return ta.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Zi(n,t){return Fi(n,Hi(Vi(n,t)[2]))}function Vi(n,t){null==t&&(t=10);var e=Pi(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Xi(n,t){return ta.range.apply(ta,Vi(n,t))}function $i(n,t,e){var r=Vi(n,t);if(e){var u=ic.exec(e);if(u.shift(),"s"===u[8]){var i=ta.formatPrefix(Math.max(ga(r[0]),ga(r[1])));return u[7]||(u[7]="."+Bi(i.scale(r[2]))),u[8]="f",e=ta.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Wi(u[8],r)),e=u.join("")}else e=",."+Bi(r[2])+"f";return ta.format(e)}function Bi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Wi(n,t){var e=Bi(t[2]);return n in yl?Math.abs(e-Bi(Math.max(ga(t[0]),ga(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Ji(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Fi(r.map(u),e?Math:xl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Pi(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Ml;arguments.length<2?t=Ml:"function"!=typeof t&&(t=ta.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Ji(n.copy(),t,e,r)},Yi(o,n)}function Gi(n,t,e){function r(t){return n(u(t))}var u=Ki(t),i=Ki(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Xi(e,n)},r.tickFormat=function(n,t){return $i(e,n,t)},r.nice=function(n){return r.domain(Zi(e,n))},r.exponent=function(o){return arguments.length?(u=Ki(t=o),i=Ki(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Gi(n.copy(),t,e)},Yi(r,n)}function Ki(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Qi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return ta.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new l;for(var i,o=-1,a=r.length;++o<a;)u.has(i=r[o])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,o=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return i=r(c+s*a/2,s),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return i=r(c+Math.round(s*a/2+(l-c-(n.length-1+a)*s)/2),s),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-a+2*c);return i=r(s+h*c,h),l&&i.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-a+2*c));return i=r(s+Math.round((f-s-(n.length-a)*h)/2),h),l&&i.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Pi(t.a[0])},e.copy=function(){return Qi(n,t)},e.domain(n)}function no(n,t){function i(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ta.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ta.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(u).sort(e),i()):n},o.range=function(n){return arguments.length?(t=n,i()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return no(n,t)},i()}function to(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return to(n,t,e)},u()}function eo(n,t){function e(e){return e>=e?t[ta.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return eo(n,t)},e}function ro(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Xi(n,t)},t.tickFormat=function(t,e){return $i(n,t,e)},t.copy=function(){return ro(n)},t}function uo(){return 0}function io(n){return n.innerRadius}function oo(n){return n.outerRadius}function ao(n){return n.startAngle}function co(n){return n.endAngle}function lo(n){return n&&n.padAngle}function so(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function fo(n,t,e,r,u){var i=n[0]-t[0],o=n[1]-t[1],a=(u?r:-r)/Math.sqrt(i*i+o*o),c=a*o,l=-a*i,s=n[0]+c,f=n[1]+l,h=t[0]+c,g=t[1]+l,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(M*M*y-x*x),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,E=_-p,A=w-v,N=S-p,C=k-v;return E*E+A*A>N*N+C*C&&(_=S,w=k),[[_-c,w-l],[_*e/M,w*e/M]]}function ho(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=Et(e),p=Et(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(""):null}var e=Ar,r=Nr,u=Ne,i=go,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=El.get(n)||go).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function go(n){return n.join("L")}function po(n){return go(n)+"Z"}function vo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function mo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function yo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function Mo(n,t){return n.length<4?go(n):n[1]+_o(n.slice(1,-1),wo(n,t))}function xo(n,t){return n.length<3?go(n):n[0]+_o((n.push(n[0]),n),wo([n[n.length-2]].concat(n,[n[1]]),t))}function bo(n,t){return n.length<3?go(n):n[0]+_o(n,wo(n,t))}function _o(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return go(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var s=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+s[0]+","+s[1]}return r}function wo(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function So(n){if(n.length<3)return go(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",No(Cl,o),",",No(Cl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Co(c,o,a);return n.pop(),c.push("L",r),c.join("")}function ko(n){if(n.length<4)return go(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(No(Cl,i)+","+No(Cl,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Co(e,i,o);return e.join("")}function Eo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[No(Cl,o),",",No(Cl,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Co(t,o,a);return t.join("")}function Ao(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return So(n)}function No(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Co(n,t,e){n.push("C",No(Al,t),",",No(Al,e),",",No(Nl,t),",",No(Nl,e),",",No(Cl,t),",",No(Cl,e))}function zo(n,t){return(t[1]-n[1])/(t[0]-n[0])}function qo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=zo(u,i);++t<e;)r[t]=(o+(o=zo(u=i,i=n[t+1])))/2;return r[t]=o,r}function Lo(n){for(var t,e,r,u,i=[],o=qo(n),a=-1,c=n.length-1;++a<c;)t=zo(n[a],n[a+1]),ga(t)<Ca?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function To(n){return n.length<3?go(n):n[0]+_o(n,Lo(n))}function Ro(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]-Ra,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Do(n){function t(t){function c(){v.push("M",a(n(m),f),s,l(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,M=t.length,x=Et(e),b=Et(u),_=e===r?function(){return g}:Et(r),w=u===i?function(){return p}:Et(i);++y<M;)o.call(this,h=t[y],y)?(d.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),m.push([+_.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=Ar,r=Ar,u=0,i=Nr,o=Ne,a=go,c=a.key,l=a,s="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r
+},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=El.get(n)||go).key,l=a.reverse||a,s=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Po(n){return n.radius}function Uo(n){return[n.x,n.y]}function jo(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Ra;return[e*Math.cos(r),e*Math.sin(r)]}}function Fo(){return 64}function Ho(){return"circle"}function Oo(n){var t=Math.sqrt(n/qa);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Io(n){return function(){var t,e;(t=this[n])&&(e=t[t.active])&&(--t.count?delete t[t.active]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Yo(n,t,e){return ya(n,Pl),n.namespace=t,n.id=e,n}function Zo(n,t,e,r){var u=n.id,i=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[i][u].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[i][u].tween.set(t,e)}))}function Vo(n){return null==n&&(n=""),function(){this.textContent=n}}function Xo(n){return null==n?"__transition__":"__transition_"+n+"__"}function $o(n,t,e,r,u){var i=n[e]||(n[e]={active:0,count:0}),o=i[r];if(!o){var a=u.time;o=i[r]={tween:new l,time:a,delay:u.delay,duration:u.duration,ease:u.ease,index:t},u=null,++i.count,ta.timer(function(u){function c(e){if(i.active>r)return s();var u=i[i.active];u&&(--i.count,delete i[i.active],u.event&&u.event.interrupt.call(n,n.__data__,u.index)),i.active=r,o.event&&o.event.start.call(n,n.__data__,t),o.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&v.push(r)}),h=o.ease,f=o.duration,ta.timer(function(){return p.c=l(e||1)?Ne:l,1},0,a)}function l(e){if(i.active!==r)return 1;for(var u=e/f,a=h(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,n.__data__,t),s()):void 0}function s(){return--i.count?delete i[r]:delete n[e],1}var f,h,g=o.delay,p=ec,v=[];return p.t=g+a,u>=g?c(u-g):void(p.c=c)},0,a)}}function Bo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Wo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Jo(n){return n.toISOString()}function Go(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=ta.bisect(Vl,u);return i==Vl.length?[t.year,Vi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Vl[i-1]<Vl[i]/u?i-1:i]:[Bl,Vi(n,e)[2]]}return r.invert=function(t){return Ko(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Ko)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Ko(+e+1),t).length}var i=r.domain(),o=Pi(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Fi(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Ko(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Ko(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Pi(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Ko(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Go(n.copy(),t,e)},Yi(r,n)}function Ko(n){return new Date(n)}function Qo(n){return JSON.parse(n.responseText)}function na(n){var t=ua.createRange();return t.selectNode(ua.body),t.createContextualFragment(n.responseText)}var ta={version:"3.5.5"},ea=[].slice,ra=function(n){return ea.call(n)},ua=this.document;if(ua)try{ra(ua.documentElement.childNodes)[0].nodeType}catch(ia){ra=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),ua)try{ua.createElement("DIV").style.setProperty("opacity",0,"")}catch(oa){var aa=this.Element.prototype,ca=aa.setAttribute,la=aa.setAttributeNS,sa=this.CSSStyleDeclaration.prototype,fa=sa.setProperty;aa.setAttribute=function(n,t){ca.call(this,n,t+"")},aa.setAttributeNS=function(n,t,e){la.call(this,n,t,e+"")},sa.setProperty=function(n,t,e){fa.call(this,n,t+"",e)}}ta.ascending=e,ta.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ta.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},ta.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},ta.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=n[i])&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},ta.sum=function(n,t){var e,r=0,i=n.length,o=-1;if(1===arguments.length)for(;++o<i;)u(e=+n[o])&&(r+=e);else for(;++o<i;)u(e=+t.call(n,n[o],o))&&(r+=e);return r},ta.mean=function(n,t){var e,i=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)u(e=r(n[a]))?i+=e:--c;else for(;++a<o;)u(e=r(t.call(n,n[a],a)))?i+=e:--c;return c?i/c:void 0},ta.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},ta.median=function(n,t){var i,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)u(i=r(n[c]))&&o.push(i);else for(;++c<a;)u(i=r(t.call(n,n[c],c)))&&o.push(i);return o.length?ta.quantile(o.sort(e),.5):void 0},ta.variance=function(n,t){var e,i,o=n.length,a=0,c=0,l=-1,s=0;if(1===arguments.length)for(;++l<o;)u(e=r(n[l]))&&(i=e-a,a+=i/++s,c+=i*(e-a));else for(;++l<o;)u(e=r(t.call(n,n[l],l)))&&(i=e-a,a+=i/++s,c+=i*(e-a));return s>1?c/(s-1):void 0},ta.deviation=function(){var n=ta.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ha=i(e);ta.bisectLeft=ha.left,ta.bisect=ta.bisectRight=ha.right,ta.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},ta.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},ta.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ta.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},ta.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=ta.min(arguments,o),e=new Array(t);++n<t;)for(var r,u=-1,i=e[n]=new Array(r);++u<r;)i[u]=arguments[u][n];return e},ta.transpose=function(n){return ta.zip.apply(ta,n)},ta.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ta.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ta.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ta.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ga=Math.abs;ta.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,u=[],i=a(ga(e)),o=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++o)>t;)u.push(r/i);else for(;(r=n+e*++o)<t;)u.push(r/i);return u},ta.map=function(n,t){var e=new l;if(n instanceof l)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,u=-1,i=n.length;if(1===arguments.length)for(;++u<i;)e.set(u,n[u]);else for(;++u<i;)e.set(t.call(n,r=n[u],u),r)}else for(var o in n)e.set(o,n[o]);return e};var pa="__proto__",va="\x00";c(l,{has:h,get:function(n){return this._[s(n)]},set:function(n,t){return this._[s(n)]=t},remove:g,keys:p,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:f(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t),this._[t])}}),ta.nest=function(){function n(t,o,a){if(a>=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var c,s,f,h,g=-1,p=o.length,v=i[a++],d=new l;++g<p;)(h=d.get(c=v(s=o[g])))?h.push(s):d.set(c,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,a))}):(s={},f=function(e,r){s[e]=n(t,r,a)}),d.forEach(f),s}function t(n,e){if(e>=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ta.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ta.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},c(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),ta.behavior={},ta.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=M(n,t,t[e]);return n};var da=["webkit","ms","moz","Moz","o","O"];ta.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ta.event=null,ta.requote=function(n){return n.replace(ma,"\\$&")};var ma=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ya={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ma=function(n,t){return t.querySelector(n)},xa=function(n,t){return t.querySelectorAll(n)},ba=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(ba=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ma=function(n,t){return Sizzle(n,t)[0]||null},xa=Sizzle,ba=Sizzle.matchesSelector),ta.selection=function(){return ta.select(ua.documentElement)};var _a=ta.selection.prototype=[];_a.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return A(i)},_a.selectAll=function(n){var t,e,r=[];n=C(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=ra(n.call(e,e.__data__,a,u))),t.parentNode=e);return A(r)};var wa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ta.ns={prefix:wa,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.slice(0,t),n=n.slice(t+1)),wa.hasOwnProperty(e)?{space:wa[e],local:n}:n}},_a.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ta.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},_a.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!L(n[u]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},_a.style=function(n,e,r){var u=arguments.length;if(3>u){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},_a.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},_a.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},_a.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},_a.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},_a.insert=function(n,t){return n=j(n),t=N(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},_a.remove=function(){return this.each(F)},_a.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new l,y=new Array(o);for(r=-1;++r<o;)m.has(d=t.call(u=n[r],u.__data__,r))?v[r]=u:m.set(d,u),y[r]=d;for(r=-1;++r<f;)(u=m.get(d=t.call(e,i=e[r],r)))?u!==!0&&(g[r]=u,u.__data__=i):p[r]=H(i),m.set(d,!0);for(r=-1;++r<o;)m.get(y[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=H(i);for(;f>r;++r)p[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,a.push(p),c.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++i<o;)(u=r[i])&&(n[i]=u.__data__);return n}var a=Z([]),c=A([]),s=A([]);if("function"==typeof n)for(;++i<o;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<o;)e(r=this[i],n);return c.enter=function(){return a},c.exit=function(){return s},c},_a.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},_a.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return A(u)},_a.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},_a.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},_a.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},_a.call=function(n){var t=ra(arguments);return n.apply(t[0]=this,t),this},_a.empty=function(){return!this.node()},_a.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},_a.size=function(){var n=0;return Y(this,function(){++n}),n};var Sa=[];ta.selection.enter=Z,ta.selection.enter.prototype=Sa,Sa.append=_a.append,Sa.empty=_a.empty,Sa.node=_a.node,Sa.call=_a.call,Sa.size=_a.size,Sa.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return A(o)},Sa.insert=function(n,t){return arguments.length<2&&(t=V(this)),_a.insert.call(this,n,t)},ta.select=function(t){var e;return"string"==typeof t?(e=[Ma(t,ua)],e.parentNode=ua.documentElement):(e=[t],e.parentNode=n(t)),A([e])},ta.selectAll=function(n){var t;return"string"==typeof n?(t=ra(xa(n,ua)),t.parentNode=ua.documentElement):(t=n,t.parentNode=null),A([t])},_a.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var ka=ta.map({mouseenter:"mouseover",mouseleave:"mouseout"});ua&&ka.forEach(function(n){"on"+n in ua&&ka.remove(n)});var Ea,Aa=0;ta.mouse=function(n){return J(n,k())};var Na=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ta.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},ta.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",o)}function e(n,t,e,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&ta.event.target===f),g({type:"dragend"}))}var l,s=this,f=ta.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=ta.select(e(f)).on(i+d,a).on(o+d,c),y=W(f),M=t(h,v);u?(l=u.apply(s,arguments),l=[l.x-M[0],l.y-M[1]]):l=[0,0],g({type:"dragstart"})}}var r=E(n,"drag","dragstart","dragend"),u=null,i=e(b,ta.mouse,t,"mousemove","mouseup"),o=e(G,ta.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ta.rebind(n,r,"on")},ta.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ra(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Ca=1e-6,za=Ca*Ca,qa=Math.PI,La=2*qa,Ta=La-Ca,Ra=qa/2,Da=qa/180,Pa=180/qa,Ua=Math.SQRT2,ja=2,Fa=4;ta.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=rt(v),o=i/(ja*h)*(e*ut(Ua*t+v)-et(v));return[r+o*l,u+o*s,i*e/rt(Ua*t+v)]}return[r+n*l,u+n*s,i*Math.exp(Ua*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Fa*f)/(2*i*ja*h),p=(c*c-i*i-Fa*f)/(2*c*ja*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Ua;return e.duration=1e3*y,e},ta.behavior.zoom=function(){function n(n){n.on(q,f).on(Oa+".zoom",g).on("dblclick.zoom",p).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function u(n){k.k=Math.max(N[0],Math.min(N[1],n))}function i(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},u(Math.pow(2,o)),i(d=e,r),t=ta.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function c(n){z++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||n({type:"zoomend"}),d=null}function f(){function n(){f=1,i(ta.mouse(u),g),l(a)}function r(){h.on(L,null).on(T,null),p(f&&ta.event.target===o),s(a)}var u=this,o=ta.event.target,a=D.of(u,arguments),f=0,h=ta.select(t(u)).on(L,n).on(T,r),g=e(ta.mouse(u)),p=W(u);Dl.call(u),c(a)}function h(){function n(){var n=ta.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ta.event.target;ta.select(t).on(x,r).on(b,a),_.push(t);for(var e=ta.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-M){var s=c[0];o(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=l}else if(c.length>1){var s=c[0],f=c[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,o=ta.touches(p);Dl.call(p);for(var a=0,c=o.length;c>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),l(v)}function a(){if(ta.event.touches.length){for(var t=ta.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}ta.selectAll(_).on(y,null),w.on(q,f).on(R,h),E(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+ta.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=ta.select(p),E=W(p);t(),c(v),w.on(q,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(v=e(d=m||ta.mouse(this)),Dl.call(this),c(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Ha())*k.k),i(d,v),l(n)}function p(){var n=ta.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ta.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},A=[960,500],N=Ia,C=250,z=0,q="mousedown.zoom",L="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=E(n,"zoomstart","zoom","zoomend");return Oa||(Oa="onwheel"in ua?(Ha=function(){return-ta.event.deltaY*(ta.event.deltaMode?120:1)},"wheel"):"onmousewheel"in ua?(Ha=function(){return ta.event.wheelDelta},"mousewheel"):(Ha=function(){return-ta.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Tl?ta.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var e=A[0],r=A[1],u=d?d[0]:e/2,i=d?d[1]:r/2,o=ta.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:u-r[0]*a,y:i-r[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,c(n),l(n),s(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:+t},a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(N=null==t?Ia:[+t[0],+t[1]],n):N},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(A=t&&[+t[0],+t[1]],n):A},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ta.rebind(n,D,"on")};var Ha,Oa,Ia=[0,1/0];ta.color=ot,ot.prototype.toString=function(){return this.rgb()+""},ta.hsl=at;var Ya=at.prototype=new ot;Ya.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,this.l/n)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,n*this.l)},Ya.rgb=function(){return ct(this.h,this.s,this.l)},ta.hcl=lt;var Za=lt.prototype=new ot;Za.brighter=function(n){return new lt(this.h,this.c,Math.min(100,this.l+Va*(arguments.length?n:1)))},Za.darker=function(n){return new lt(this.h,this.c,Math.max(0,this.l-Va*(arguments.length?n:1)))},Za.rgb=function(){return st(this.h,this.c,this.l).rgb()},ta.lab=ft;var Va=18,Xa=.95047,$a=1,Ba=1.08883,Wa=ft.prototype=new ot;Wa.brighter=function(n){return new ft(Math.min(100,this.l+Va*(arguments.length?n:1)),this.a,this.b)},Wa.darker=function(n){return new ft(Math.max(0,this.l-Va*(arguments.length?n:1)),this.a,this.b)},Wa.rgb=function(){return ht(this.l,this.a,this.b)},ta.rgb=mt;var Ja=mt.prototype=new ot;Ja.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new mt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mt(u,u,u)},Ja.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mt(n*this.r,n*this.g,n*this.b)},Ja.hsl=function(){return _t(this.r,this.g,this.b)},Ja.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var Ga=ta.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ga.forEach(function(n,t){Ga.set(n,yt(t))}),ta.functor=Et,ta.xhr=At(y),ta.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Nt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<l;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;l>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},ta.csv=ta.dsv(",","text/csv"),ta.tsv=ta.dsv("      ","text/tab-separated-values");var Ka,Qa,nc,tc,ec,rc=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ta.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Qa?Qa.n=i:Ka=i,Qa=i,nc||(tc=clearTimeout(tc),nc=1,rc(qt))},ta.timer.flush=function(){Lt(),Tt()},ta.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);ta.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ta.round(n,Rt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),uc[8+e/3]};var ic=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=ta.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ta.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),ac=ta.time={},cc=Date;jt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){lc.setUTCDate.apply(this._,arguments)},setDay:function(){lc.setUTCDay.apply(this._,arguments)},setFullYear:function(){lc.setUTCFullYear.apply(this._,arguments)},setHours:function(){lc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){lc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){lc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){lc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){lc.setUTCSeconds.apply(this._,arguments)},setTime:function(){lc.setTime.apply(this._,arguments)}};var lc=Date.prototype;ac.year=Ft(function(n){return n=ac.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ac.years=ac.year.range,ac.years.utc=ac.year.utc.range,ac.day=Ft(function(n){var t=new cc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ac.days=ac.day.range,ac.days.utc=ac.day.utc.range,ac.dayOfYear=function(n){var t=ac.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ac[n]=Ft(function(n){return(n=ac.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ac[n+"s"]=e.range,ac[n+"s"].utc=e.utc.range,ac[n+"OfYear"]=function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)}}),ac.week=ac.sunday,ac.weeks=ac.sunday.range,ac.weeks.utc=ac.sunday.utc.range,ac.weekOfYear=ac.sundayOfYear;var sc={"-":"",_:" ",0:"0"},fc=/^\s*\d+/,hc=/^%/;ta.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var gc=ta.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ta.format=gc.numberFormat,ta.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,pc),le(pc.s,this.s,this),this.s?this.t+=pc.t:this.s=pc.t
+},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var pc=new ce;ta.geo.stream=function(n,t){n&&vc.hasOwnProperty(n.type)?vc[n.type](n,t):se(n,t)};var vc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)se(e[r].geometry,t)}},dc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){fe(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)fe(e[r],t,0)},Polygon:function(n,t){he(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)he(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)se(e[r],t)}};ta.geo.area=function(n){return mc=0,ta.geo.stream(n,Mc),mc};var mc,yc=new ce,Mc={sphere:function(){mc+=4*qa},point:b,lineStart:b,lineEnd:b,polygonStart:function(){yc.reset(),Mc.lineStart=ge},polygonEnd:function(){var n=2*yc;mc+=0>n?4*qa+n:n,Mc.lineStart=Mc.lineEnd=Mc.point=b}};ta.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*Da,e*Da]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);Me(o),o=xe(o);var c=t-p,l=c>0?1:-1,v=o[0]*Pa*l,d=ga(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Pa;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Pa;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ga(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Mc.point(n,e),t(n,e)}function i(){Mc.lineStart()}function o(){u(v,d),Mc.lineEnd(),ga(y)>Ca&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,v,d,m,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=u,b.lineStart=i,b.lineEnd=o,y=0,Mc.polygonStart()},polygonEnd:function(){Mc.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>yc?(s=-(h=180),f=-(g=90)):y>Ca?g=90:-Ca>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ta.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ta.geo.centroid=function(n){xc=bc=_c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,qc);var t=Nc,e=Cc,r=zc,u=t*t+e*e+r*r;return za>u&&(t=kc,e=Ec,r=Ac,Ca>bc&&(t=_c,e=wc,r=Sc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Pa,tt(r/Math.sqrt(u))*Pa]};var xc,bc,_c,wc,Sc,kc,Ec,Ac,Nc,Cc,zc,qc={sphere:b,point:_e,lineStart:Se,lineEnd:ke,polygonStart:function(){qc.lineStart=Ee},polygonEnd:function(){qc.lineStart=Se}},Lc=Le(Ne,Pe,je,[-qa,-qa/2]),Tc=1e9;ta.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ie(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ta.geo.conicEqualArea=function(){return Ye(Ze)}).raw=Ze,ta.geo.albers=function(){return ta.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ta.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=ta.geo.albers(),o=ta.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ta.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Ca,f+.12*l+Ca],[s-.214*l-Ca,f+.234*l-Ca]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Ca,f+.166*l+Ca],[s-.115*l-Ca,f+.234*l-Ca]]).stream(c).point,n},n.scale(1070)};var Rc,Dc,Pc,Uc,jc,Fc,Hc={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Dc=0,Hc.lineStart=Ve},polygonEnd:function(){Hc.lineStart=Hc.lineEnd=Hc.point=b,Rc+=ga(Dc/2)}},Oc={point:Xe,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Ic={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){Ic.lineStart=Ke},polygonEnd:function(){Ic.point=We,Ic.lineStart=Je,Ic.lineEnd=Ge}};ta.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),ta.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Rc=0,ta.geo.stream(n,u(Hc)),Rc},n.centroid=function(n){return _c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,u(Ic)),zc?[Nc/zc,Cc/zc]:Ac?[kc/Ac,Ec/Ac]:Sc?[_c/Sc,wc/Sc]:[0/0,0/0]},n.bounds=function(n){return jc=Fc=-(Pc=Uc=1/0),ta.geo.stream(n,u(Oc)),[[Pc,Uc],[jc,Fc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(ta.geo.albersUsa()).context(null)},ta.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ta.geo.projection=ur,ta.geo.projectionMutator=ir,(ta.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,ta.geo.rotation=function(n){function t(t){return t=n(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t}return n=lr(n[0]%360*Da,n[1]*Da,n.length>2?n[2]*Da:0),t.invert=function(t){return t=n.invert(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t},t},cr.invert=ar,ta.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*Da,-n[1]*Da,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Pa,n[1]*=Pa}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*Da,u*Da),n):t},n.precision=function(r){return arguments.length?(e=gr(t*Da,(u=+r)*Da),n):u},n.angle(90)},ta.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Da,u=n[1]*Da,i=t[1]*Da,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},ta.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ta.range(Math.ceil(i/d)*d,u,d).map(h).concat(ta.range(Math.ceil(l/m)*m,c,m).map(g)).concat(ta.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ga(n%d)>Ca}).map(s)).concat(ta.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ga(n%m)>Ca}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Ca],[180,90-Ca]]).minorExtent([[-180,-80-Ca],[180,80+Ca]])},ta.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return ta.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},ta.geo.interpolate=function(n,t){return Mr(n[0]*Da,n[1]*Da,t[0]*Da,t[1]*Da)},ta.geo.length=function(n){return Yc=0,ta.geo.stream(n,Zc),Yc};var Yc,Zc={sphere:b,point:b,lineStart:xr,lineEnd:b,polygonStart:b,polygonEnd:b},Vc=br(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ta.geo.azimuthalEqualArea=function(){return ur(Vc)}).raw=Vc;var Xc=br(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(ta.geo.azimuthalEquidistant=function(){return ur(Xc)}).raw=Xc,(ta.geo.conicConformal=function(){return Ye(_r)}).raw=_r,(ta.geo.conicEquidistant=function(){return Ye(wr)}).raw=wr;var $c=br(function(n){return 1/n},Math.atan);(ta.geo.gnomonic=function(){return ur($c)}).raw=$c,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ra]},(ta.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Bc=br(function(){return 1},Math.asin);(ta.geo.orthographic=function(){return ur(Bc)}).raw=Bc;var Wc=br(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ta.geo.stereographic=function(){return ur(Wc)}).raw=Wc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ra]},(ta.geo.transverseMercator=function(){var n=kr(Er),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Er,ta.geom={},ta.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=Et(e),i=Et(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Cr(a),s=Cr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t<s.length-h;++t)g.push(n[a[s[t]][2]]);return g}var e=Ar,r=Nr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ta.geom.polygon=function(n){return ya(n,Jc),n};var Jc=ta.geom.polygon.prototype=[];Jc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Jc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Jc.clip=function(n){for(var t,e,r,u,i,o,a=Tr(n),c=-1,l=this.length-Tr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],qr(o,s,u)?(qr(i,s,u)||n.push(Lr(i,o,s,u)),n.push(o)):qr(i,s,u)&&n.push(Lr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n};var Gc,Kc,Qc,nl,tl,el=[],rl=[];Or.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Yr),t.length},Qr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},nu.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=uu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(eu(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ru(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(ru(this,e),n=e,e=n.U),e.C=!1,r.C=!0,eu(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?uu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,eu(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ru(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,eu(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,ru(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,eu(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,ru(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},ta.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return iu(e(n),a).cells.forEach(function(e,a){var c=e.edges,l=e.site,s=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Ca)*Ca,y:Math.round(o(n,t)/Ca)*Ca,i:t}})}var r=Ar,u=Nr,i=r,o=u,a=ul;return n?t(n):(t.links=function(n){return iu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Yr),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c<l;)u=s,i=f,s=a[c].edge,f=s.l===o?s.r:s.l,r<i.i&&r<f.i&&au(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=Et(r=n),t):r},t.y=function(n){return arguments.length?(o=Et(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?ul:n,t):a===ul?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===ul?null:a&&a[1]},t)};var ul=[[-1e6,-1e6],[1e6,1e6]];ta.geom.delaunay=function(n){return ta.geom.voronoi().triangles(n)},ta.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(ga(c-e)+ga(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,M=Et(a),x=Et(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<v&&(v=s.x),s.y<d&&(d=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=s=null,k}var o,a=Ar,c=Nr;return(o=arguments.length)?(a=cu,c=lu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},ta.interpolateRgb=gu,ta.interpolateObject=pu,ta.interpolateNumber=vu,ta.interpolateString=du;var il=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ol=new RegExp(il.source,"g");ta.interpolate=mu,ta.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ga.has(t)||/^(#|rgb\(|hsl\()/.test(t)?gu:du:t instanceof ot?gu:Array.isArray(t)?yu:"object"===e&&isNaN(t)?pu:vu)(n,t)}],ta.interpolateArray=yu;var al=function(){return y},cl=ta.map({linear:al,poly:ku,quad:function(){return _u},cubic:function(){return wu},sin:function(){return Eu},exp:function(){return Au},circle:function(){return Nu},elastic:Cu,back:zu,bounce:function(){return qu}}),ll=ta.map({"in":y,out:xu,"in-out":bu,"out-in":function(n){return bu(xu(n))}});ta.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Yu(n[e]));return t}},ta.layout.chord=function(){function n(){var n,l,f,h,g,p={},v=[],d=ta.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];v.push(l),m.push(ta.range(i)),n+=l}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(La-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=d[h],M=m[y][g],x=u[y][M],b=l,_=l+=x*n;p[y+"-"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},ta.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e<b;)a=m[e],a.x+=(y-a.x)*d,a.y+=(x-a.y)*d;if(g)for(Ju(t=ta.geom.quadtree(m),r,o),e=-1;++e<b;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<b;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(M=n,a):M},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++a<l;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,s=M.length,p=l[0],v=l[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=ta.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Gu(e,r)},ta.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(e,r){return+t.call(n,e,r)}),s=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof u?u.apply(this,arguments):u)-s,h=Math.min(Math.abs(f)/c,+("function"==typeof i?i.apply(this,arguments):i)),g=h*(0>f?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=ta.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Ri,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));
+return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ri(t):Di(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Di(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Ri:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Gu(i,a)},ta.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++a<c;){i.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(e=l[s])&&$o(e,s,u,r,o),t.push(e)}return Yo(i,u,r)},_a.interrupt=function(n){return this.each(null==n?Dl:Io(Xo(n)))};var Tl,Rl,Dl=Io(Xo()),Pl=[],Ul=0;Pl.call=_a.call,Pl.empty=_a.empty,Pl.node=_a.node,Pl.size=_a.size,ta.transition=function(n,t){return n&&n.transition?Tl?n.transition(t):n:ta.selection().transition(n)},ta.transition.prototype=Pl,Pl.select=function(n){var t,e,r,u=this.id,i=this.namespace,o=[];n=N(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(r=l[s])&&(e=n.call(r,r.__data__,s,a))?("__data__"in r&&(e.__data__=r.__data__),$o(e,s,i,u,r[i][u]),t.push(e)):t.push(null)}return Yo(o,i,u)},Pl.selectAll=function(n){var t,e,r,u,i,o=this.id,a=this.namespace,c=[];n=C(n);for(var l=-1,s=this.length;++l<s;)for(var f=this[l],h=-1,g=f.length;++h<g;)if(r=f[h]){i=r[a][o],e=n.call(r,r.__data__,h,l),c.push(t=[]);for(var p=-1,v=e.length;++p<v;)(u=e[p])&&$o(u,p,a,o,i),t.push(u)}return Yo(c,a,o)},Pl.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]<M[0])],q[1]=h[+(n[1]<M[1])]):M=null),A&&m(n,l,0)&&(r(k),t=!0),N&&m(n,s,1)&&(u(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function m(n,t,e){var r,u,i=Ui(t),c=i[0],l=i[1],s=q[e],v=e?h:f,d=v[1]-v[0];return C&&(c-=s,l-=d+s),r=(e?p:g)?Math.max(c,Math.min(l,n[e])):n[e],C?u=(r+=s)+d:(M&&(s=Math.max(c,Math.min(l,2*M[e]-r))),r>s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}();
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/lib/select2.full.min.js b/ovsdb-ui/module/src/main/resources/ovsdb/lib/select2.full.min.js
new file mode 100755 (executable)
index 0000000..59d8c1a
--- /dev/null
@@ -0,0 +1,3 @@
+/*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.concat(a),k=0;k<a.length;k+=1)if(m=a[k],"."===m)a.splice(k,1),k-=1;else if(".."===m){if(1===k&&(".."===a[2]||".."===a[0]))break;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){return n.apply(b,v.call(arguments,0).concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n<c.length;n+=1)if(m=o(c[n],f),k=m.f,"require"===k)u[n]=p.require(a);else if("exports"===k)u[n]=p.exports(a),s=!0;else if("module"===k)h=u[n]=p.module(a);else if(e(q,k)||e(r,k)||e(t,k))u[n]=j(k);else{if(!m.p)throw new Error(a+" missing "+k);m.p.load(m.n,g(f,!0),i(k),{}),u[n]=q[k]}l=d?d.apply(q[a],u):void 0,a&&(h&&h.exports!==b&&h.exports!==q[a]?q[a]=h.exports:l===b&&s||(q[a]=l))}else a&&(q[a]=d)},a=c=n=function(a,c,d,e,f){if("string"==typeof a)return p[a]?p[a](c):j(o(a,c).f);if(!a.splice){if(s=a,s.deps&&n(s.deps,s.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?m(b,a,c,d):setTimeout(function(){m(b,a,c,d)},4),n},n.config=function(a){return n(a)},a._defined=q,d=function(a,b,c){b.splice||(c=b,b=[]),e(q,a)||e(r,a)||(r[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){var e=b[d];"function"==typeof e&&"constructor"!==d&&c.push(d)}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){var a=Array.prototype.unshift;return a.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice;this.listeners=this.listeners||{},a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;d>c;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return e!==f||"hidden"!==f&&"visible"!==f?"scroll"===e||"scroll"===f?!0:d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth:!1},c.escapeMarkup=function(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),this.$results.append(d)},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){var c=b.find(".select2-results");c.append(a)},c.prototype.sort=function(a){var b=this.options.get("sorter");return b(a)},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")});var f=e.filter("[aria-selected=true]");f.length>0?f.first().trigger("mouseenter"):e.first().trigger("mouseenter")})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";{a(h)}this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b){var c=this,d=b.id+"-results";this.$results.attr("id",d),b.on("results:all",function(a){c.clear(),c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("results:append",function(a){c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("query",function(a){c.showLoading(a)}),b.on("select",function(){b.isOpen()&&c.setClasses()}),b.on("unselect",function(){b.isOpen()&&c.setClasses()}),b.on("open",function(){c.$results.attr("aria-expanded","true"),c.$results.attr("aria-hidden","false"),c.setClasses(),c.ensureHighlightVisible()}),b.on("close",function(){c.$results.attr("aria-expanded","false"),c.$results.attr("aria-hidden","true"),c.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=c.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=c.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?c.trigger("close"):c.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a);if(0!==d){var e=d-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top,h=f.offset().top,i=c.$results.scrollTop()+(h-g);0===e?c.$results.scrollTop(0):0>h-g&&c.$results.scrollTop(i)}}),b.on("results:next",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a),e=d+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top+c.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=c.$results.scrollTop()+h-g;0===e?c.$results.scrollTop(0):h>g&&c.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){c.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=c.$results.scrollTop(),d=c.$results.get(0).scrollHeight-c.$results.scrollTop()+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&d<=c.$results.height();e?(c.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(c.$results.scrollTop(c.$results.get(0).scrollHeight-c.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var d=a(this),e=d.data("data");return"true"===d.attr("aria-selected")?void(c.options.get("multiple")?c.trigger("unselect",{originalEvent:b,data:e}):c.trigger("close")):void c.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(){var b=a(this).data("data");c.getHighlightedResults().removeClass("select2-results__option--highlighted"),c.trigger("results:focus",{data:b,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a){var b=this,d=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){b.trigger("focus",a)}),this.$selection.on("blur",function(a){b.trigger("blur",a)}),this.$selection.on("keydown",function(a){b.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){b.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){b.update(a.data)}),a.on("open",function(){b.$selection.attr("aria-expanded","true"),b.$selection.attr("aria-owns",d),b._attachCloseHandler(a)}),a.on("close",function(){b.$selection.attr("aria-expanded","false"),b.$selection.removeAttr("aria-activedescendant"),b.$selection.removeAttr("aria-owns"),b.$selection.focus(),b._detachCloseHandler(a)}),a.on("enable",function(){b.$selection.attr("tabindex",b._tabindex)}),a.on("disable",function(){b.$selection.attr("tabindex","-1")})},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},d.prototype.bind=function(a){var b=this;d.__super__.bind.apply(this,arguments);var c=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",c),this.$selection.attr("aria-labelledby",c),this.$selection.on("mousedown",function(a){1===a.which&&b.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(){}),this.$selection.on("blur",function(){}),a.on("selection:update",function(a){b.update(a.data)})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){return a("<span></span>")},d.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.display(b),d=this.$selection.find(".select2-selection__rendered");d.empty().append(c),d.prop("title",b.title||b.text)},d}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(){var b=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){b.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(c){var d=a(this),e=d.parent(),f=e.data("data");b.trigger("unselect",{originalEvent:c,data:f})})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){var b=a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.display(e),g=this.selectionContainer();g.append(f),g.prop("title",e.title||e.text),g.data("data",e),b.push(g)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(){function a(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},a.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id,d=b.length>1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},a}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle")}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||(c.which==b.DELETE||c.which==b.BACKSPACE)&&this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">&times;</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus()}),b.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val(""),e.$search.focus()}),b.on("enable",function(){e.$search.prop("disabled",!1)}),b.on("disable",function(){e.$search.prop("disabled",!0)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e.trigger("blur",a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}}),this.$selection.on("input",".select2-search--inline",function(){e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input",".select2-search--inline",function(a){e.handleSearch(a)})},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.trigger("open"),this.$search.val(b.text+" ")},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){var b=this;if(this.$element.prop("multiple"))return a.selected=!1,c(a.element).is("option")?(a.element.selected=!1,void this.$element.trigger("change")):void this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})},d.prototype.bind=function(a){var b=this;this.container=a,a.on("select",function(a){b.select(a.data)}),a.on("unselect",function(a){b.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this,f=this.$element.children();f.each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};
+if(b=c.data(a[0],"data"),null!=b)return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){var c=this.options.get("matcher");return c(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=(c.extend(!0,{},l,j),this.option(l));k.replaceWith(m)}else{var n=this.option(j);if(j.children){var o=this.convertToOptions(j.children);b.appendMany(n,o)}h.push(n)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(b,c){this.ajaxOptions=this._applyDefaults(c.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),a.__super__.constructor.call(this,b,c)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return{q:a.term}},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url(a)),"function"==typeof f.data&&(f.data=f.data(a)),this.ajaxOptions.delay&&""!==a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");if(void 0!==f&&(this.createTag=f),b.call(this,c,d),a.isArray(e))for(var g=0;g<e.length;g++){var h=e[g],i=this._normalizeItem(h),j=this.option(i);this.$element.append(j)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0),k=i.text===b.term;if(k||j)return f?!1:(a.data=g,void c(a))}if(f)return!0;var l=e.createTag(b);if(null!=l){var m=e.option(l);m.attr("data-select2-tag",!0),e.addOptions([m]),e.insertTag(g,l)}a.results=g,c(a)}var e=this;return this._removeOldTags(),null==b.term||null!=b.page?void a.call(this,b,c):void a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(){var b=(this._lastTag,this.$element.find("option[data-select2-tag]"));b.each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(a,b,c){function d(a){e.select(a)}var e=this;b.term=b.term||"";var f=this.tokenizer(b,this.options,d);f.term!==b.term&&(this.$search.length&&(this.$search.val(f.term),this.$search.focus()),b.term=f.term),a.call(this,b,c)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);e(m),g=g.substr(h+1)||"",h=0}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",b.term.length<this.minimumInputLength?void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.position=function(){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a){function b(){}return b.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},b.prototype.handleSearch=function(){if(!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},b.prototype.showSearch=function(){return!0},b}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="option load-more" role="treeitem"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(a,b,c){this.$dropdownParent=c.get("dropdownParent")||document.body,a.call(this,b,c)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c){var d=this,e="scroll.select2."+c.id,f="resize.select2."+c.id,g="orientationchange.select2."+c.id,h=this.$container.parents().filter(b.hasScroll);h.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),h.on(e,function(){var b=a(this).data("select2-scroll-position");a(this).scrollTop(b.y)}),a(window).on(e+" "+f+" "+g,function(){d._positionDropdown(),d._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c){var d="scroll.select2."+c.id,e="resize.select2."+c.id,f="orientationchange.select2."+c.id,g=this.$container.parents().filter(b.hasScroll);g.off(d),a(window).off(d+" "+e+" "+f)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=(this.$container.position(),this.$container.offset());f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom};c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){this.$dropdownContainer.width();var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return a(c.data.results)<this.minimumResultsForSearch?!1:b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(){d._handleSelectOnClose()})},a.prototype._handleSelectOnClose=function(){var a=this.getHighlightedResults();a.length<1||this.trigger("select",{data:a.data("data")})},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close")},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){var b=a.minimum-a.input.length,c="Please enter "+b+" or more characters";return c},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C){function D(){this.reset()}D.prototype.apply=function(l){if(l=a.extend({},this.defaults,l),null==l.dataAdapter){if(l.dataAdapter=null!=l.ajax?o:null!=l.data?n:m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.selectionAdapter=l.multiple?e:d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(O){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(P){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var Q=k.loadPath(this.defaults.amdLanguageBase+"en"),R=new k(l.language);R.extend(Q),l.translations=R}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(this.options.dir=a.prop("dir")?a.prop("dir"):a.closest("[dir]").prop("dir")?a.closest("[dir]").prop("dir"):"ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this._sync=c.bind(this._syncAttributes,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._sync);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._sync)}),this._observer.observe(this.$element[0],{attributes:!0,subtree:!1})):this.$element[0].addEventListener&&this.$element[0].addEventListener("DOMAttrModified",b._sync,!1)},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("focus",function(){a.$container.addClass("select2-container--focus")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open"),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ENTER?(a.trigger("results:select"),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle"),b.preventDefault()):c===d.UP?(a.trigger("results:previous"),b.preventDefault()):c===d.DOWN?(a.trigger("results:next"),b.preventDefault()):(c===d.ESC||c===d.TAB)&&(a.close(),b.preventDefault()):(c===d.ENTER||c===d.SPACE||(c===d.DOWN||c===d.UP)&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable")):this.trigger("enable")},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||(this.trigger("query",{}),this.trigger("open"))},e.prototype.close=function(){this.isOpen()&&this.trigger("close")},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._sync),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&this.$element[0].removeEventListener("DOMAttrModified",this._sync,!1),this._sync=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("select2/compat/utils",["jquery"],function(a){function b(b,c,d){var e,f,g=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0===this.indexOf("select2-")&&g.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&(f=d(this),null!=f&&g.push(f))})),b.attr("class",g.join(" "))}return{syncCssClasses:b}}),b.define("select2/compat/containerCss",["jquery","./utils"],function(a,b){function c(){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("containerCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptContainerCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("containerCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/dropdownCss",["jquery","./utils"],function(a,b){function c(){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("dropdownCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptDropdownCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("dropdownCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/initSelection",["jquery"],function(a){function b(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=c.get("initSelection"),this._isInitialized=!1,a.call(this,b,c)}return b.prototype.current=function(b,c){var d=this;return this._isInitialized?void b.call(this,c):void this.initSelection.call(null,this.$element,function(b){d._isInitialized=!0,a.isArray(b)||(b=[b]),c(b)})},b}),b.define("select2/compat/inputData",["jquery"],function(a){function b(a,b,c){this._currentData=[],this._valueSeparator=c.get("valueSeparator")||",","hidden"===b.prop("type")&&c.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `<select>` element instead."),a.call(this,b,c)}return b.prototype.current=function(b,c){function d(b,c){var e=[];return b.selected||-1!==a.inArray(b.id,c)?(b.selected=!0,e.push(b)):b.selected=!1,b.children&&e.push.apply(e,d(b.children,c)),e}for(var e=[],f=0;f<this._currentData.length;f++){var g=this._currentData[f];e.push.apply(e,d(g,this.$element.val().split(this._valueSeparator)))}c(e)},b.prototype.select=function(b,c){if(this.options.get("multiple")){var d=this.$element.val();d+=this._valueSeparator+c.id,this.$element.val(d),this.$element.trigger("change")}else this.current(function(b){a.map(b,function(a){a.selected=!1})}),this.$element.val(c.id),this.$element.trigger("change")},b.prototype.unselect=function(a,b){var c=this;b.selected=!1,this.current(function(a){for(var d=[],e=0;e<a.length;e++){var f=a[e];
+b.id!=f.id&&d.push(f.id)}c.$element.val(d.join(c._valueSeparator)),c.$element.trigger("change")})},b.prototype.query=function(a,b,c){for(var d=[],e=0;e<this._currentData.length;e++){var f=this._currentData[e],g=this.matches(b,f);null!==g&&d.push(g)}c({results:d})},b.prototype.addOptions=function(b,c){var d=a.map(c,function(b){return a.data(b[0],"data")});this._currentData.push.apply(this._currentData,d)},b}),b.define("select2/compat/matcher",["jquery"],function(a){function b(b){function c(c,d){var e=a.extend(!0,{},d);if(null==c.term||""===a.trim(c.term))return e;if(d.children){for(var f=d.children.length-1;f>=0;f--){var g=d.children[f],h=b(c.term,g.text,g);h||e.children.splice(f,1)}if(e.children.length>0)return e}return b(c.term,d.text,d)?e:null}return c}return b}),b.define("select2/compat/query",[],function(){function a(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `query` option has been deprecated in favor of a custom data adapter that overrides the `query` method. Support will be removed for the `query` option in future versions of Select2."),a.call(this,b,c)}return a.prototype.query=function(a,b,c){b.callback=c;var d=this.options.get("query");d.call(null,b)},a}),b.define("select2/dropdown/attachContainer",[],function(){function a(a,b,c){a.call(this,b,c)}return a.prototype.position=function(a,b,c){var d=c.find(".dropdown-wrapper");d.append(b),b.addClass("select2-dropdown--below"),c.addClass("select2-container--below")},a}),b.define("select2/dropdown/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$dropdown.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("select2/selection/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$selection.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("jquery.select2",["jquery","require","./select2/core","./select2/defaults"],function(a,b,c,d){if(b("jquery.mousewheel"),null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){{var d=a.extend({},b,!0);new c(a(this),d)}}),this;if("string"==typeof b){var d=this.data("select2");null==d&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2.");var f=Array.prototype.slice.call(arguments,1),g=d[b](f);return a.inArray(b,e)>-1?this:g}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),function(c){"function"==typeof b.define&&b.define.amd?b.define("jquery.mousewheel",["jquery"],c):"object"==typeof exports?module.exports=c:c(a)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/lib/sylvester.js b/ovsdb-ui/module/src/main/resources/ovsdb/lib/sylvester.js
new file mode 100755 (executable)
index 0000000..3e83bee
--- /dev/null
@@ -0,0 +1 @@
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j<k;j++){o(M.4[j][i]!=0){1c=[];1s=1n;J{p=1n-1s;1c.19(M.4[i][p]+M.4[j][p])}H(--1s);M.4[i]=1c;1I}}}o(M.4[i][i]!=0){2e(j=i+1;j<k;j++){9 a=M.4[j][i]/M.4[i][i];1c=[];1s=1n;J{p=1n-1s;1c.19(p<=i?0:M.4[j][p]-M.4[i][p]*a)}H(--1s);M.4[j]=1c}}}H(--n);8 M},3h:l(){8 7.1K()},2z:l(){o(!7.1y()){8 w}9 M=7.1K();9 a=M.4[0][0],n=M.4.q-1,k=n,i;J{i=k-n+1;a=a*M.4[i][i]}H(--n);8 a},3f:l(){8 7.2z()},2y:l(){8(7.1y()&&7.2z()===0)},2Y:l(){o(!7.1y()){8 w}9 a=7.4[0][0],n=7.4.q-1,k=n,i;J{i=k-n+1;a+=7.4[i][i]}H(--n);8 a},3e:l(){8 7.2Y()},1Y:l(){9 M=7.1K(),1Y=0;9 a=7.4.q,15=a,i,G,10=7.4[0].q,j;J{i=15-a;G=10;J{j=10-G;o(F.13(M.4[i][j])>17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j<i;j++){1c=[];b=1n;J{p=1n-b;1c.19(M.4[j][p]-M.4[i][p]*M.4[j][i])}H(--b);M.4[j]=1c}}H(--a);8 S.u(c)},3c:l(){8 7.2w()},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(p){8(F.13(p-x)<=17.16)?x:p})},2n:l(){9 a=[];9 n=7.4.q,k=n,i;J{i=k-n;a.19(v.u(7.4[i]).2n())}H(--n);8 a.2K(\'\\n\')},26:l(a){9 i,4=a.4||a;o(1g(4[0][0])!=\'1f\'){9 b=4.q,15=b,G,10,j;7.4=[];J{i=15-b;G=4[i].q;10=G;7.4[i]=[];J{j=10-G;7.4[i][j]=4[i][j]}H(--G)}H(--b);8 7}9 n=4.q,k=n;7.4=[];J{i=k-n;7.4.19([4[i]])}H(--n);8 7}};S.u=l(a){9 M=25 S();8 M.26(a)};S.I=l(n){9 a=[],k=n,i,G,j;J{i=k-n;a[i]=[];G=k;J{j=k-G;a[i][j]=(i==j)?1:0}H(--G)}H(--n);8 S.u(a)};S.2X=l(a){9 n=a.q,k=n,i;9 M=S.I(n);J{i=k-n;M.4[i][i]=a[i]}H(--n);8 M};S.1R=l(b,a){o(!a){8 S.u([[F.1H(b),-F.1G(b)],[F.1G(b),F.1H(b)]])}9 d=a.1q();o(d.4.q!=3){8 w}9 e=d.1u();9 x=d.4[0]/e,y=d.4[1]/e,z=d.4[2]/e;9 s=F.1G(b),c=F.1H(b),t=1-c;8 S.u([[t*x*x+c,t*x*y-s*z,t*x*z+s*y],[t*x*y+s*z,t*y*y+c,t*y*z-s*x],[t*x*z-s*y,t*y*z+s*x,t*z*z+c]])};S.3b=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[1,0,0],[0,c,-s],[0,s,c]])};S.39=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,0,s],[0,1,0],[-s,0,c]])};S.38=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,-s,0],[s,c,0],[0,0,1]])};S.2J=l(n,m){8 S.1j(n,m).1b(l(){8 F.2F()})};S.1j=l(n,m){9 a=[],12=n,i,G,j;J{i=n-12;a[i]=[];G=m;J{j=m-G;a[i][j]=0}H(--G)}H(--12);8 S.u(a)};l 14(){}14.23={24:l(a){8(7.1m(a)&&7.1h(a.K))},1q:l(){8 14.u(7.K,7.U)},2U:l(a){9 V=a.4||a;8 14.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.U)},1m:l(a){o(a.W){8 a.1m(7)}9 b=7.U.1C(a.U);8(F.13(b)<=17.16||F.13(b-F.1A)<=17.16)},1o:l(a){o(a.W){8 a.1o(7)}o(a.U){o(7.1m(a)){8 7.1o(a.K)}9 N=7.U.2f(a.U).2q().4;9 A=7.K.4,B=a.K.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,D=7.U.4;9 b=P[0]-A[0],2a=P[1]-A[1],29=(P[2]||0)-A[2];9 c=F.1x(b*b+2a*2a+29*29);o(c===0)8 0;9 d=(b*D[0]+2a*D[1]+29*D[2])/c;9 e=1-d*d;8 F.13(c*F.1x(e<0?0:e))}},1h:l(a){9 b=7.1o(a);8(b!==w&&b<=17.16)},2T:l(a){8 a.1h(7)},1v:l(a){o(a.W){8 a.1v(7)}8(!7.1m(a)&&7.1o(a)<=17.16)},1U:l(a){o(a.W){8 a.1U(7)}o(!7.1v(a)){8 w}9 P=7.K.4,X=7.U.4,Q=a.K.4,Y=a.U.4;9 b=X[0],1z=X[1],1B=X[2],1T=Y[0],1S=Y[1],1M=Y[2];9 c=P[0]-Q[0],2s=P[1]-Q[1],2r=P[2]-Q[2];9 d=-b*c-1z*2s-1B*2r;9 e=1T*c+1S*2s+1M*2r;9 f=b*b+1z*1z+1B*1B;9 g=1T*1T+1S*1S+1M*1M;9 h=b*1T+1z*1S+1B*1M;9 k=(d*g/f+h*e)/(g-h*h);8 v.u([P[0]+k*b,P[1]+k*1z,P[2]+k*1B])},1r:l(a){o(a.U){o(7.1v(a)){8 7.1U(a)}o(7.1m(a)){8 w}9 D=7.U.4,E=a.U.4;9 b=D[0],1l=D[1],1k=D[2],1P=E[0],1O=E[1],1Q=E[2];9 x=(1k*1P-b*1Q),y=(b*1O-1l*1P),z=(1l*1Q-1k*1O);9 N=v.u([x*1Q-y*1O,y*1P-z*1Q,z*1O-x*1P]);9 P=11.u(a.K,N);8 P.1U(7)}1d{9 P=a.4||a;o(7.1h(P)){8 v.u(P)}9 A=7.K.4,D=7.U.4;9 b=D[0],1l=D[1],1k=D[2],1w=A[0],18=A[1],1a=A[2];9 x=b*(P[1]-18)-1l*(P[0]-1w),y=1l*((P[2]||0)-1a)-1k*(P[1]-18),z=1k*(P[0]-1w)-b*((P[2]||0)-1a);9 V=v.u([1l*x-1k*z,1k*y-b*x,b*z-1l*y]);9 k=7.1o(P)/V.1u();8 v.u([P[0]+V.4[0]*k,P[1]+V.4[1]*k,(P[2]||0)+V.4[2]*k])}},1V:l(t,a){o(1g(a.U)==\'1f\'){a=14.u(a.1N(),v.k)}9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,D=7.U.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 14.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*D[0]+R[0][1]*D[1]+R[0][2]*D[2],R[1][0]*D[0]+R[1][1]*D[1]+R[1][2]*D[2],R[2][0]*D[0]+R[2][1]*D[1]+R[2][2]*D[2]])},1t:l(a){o(a.W){9 A=7.K.4,D=7.U.4;9 b=A[0],18=A[1],1a=A[2],2N=D[0],1l=D[1],1k=D[2];9 c=7.K.1t(a).4;9 d=b+2N,2h=18+1l,2o=1a+1k;9 Q=a.1r([d,2h,2o]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2h)-c[1],Q[2]+(Q[2]-2o)-c[2]];8 14.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 14.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.U)}},1Z:l(a,b){a=v.u(a);b=v.u(b);o(a.4.q==2){a.4.19(0)}o(b.4.q==2){b.4.19(0)}o(a.4.q>3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{}))
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/matrix.js b/ovsdb-ui/module/src/main/resources/ovsdb/matrix.js
new file mode 100644 (file)
index 0000000..97e82f6
--- /dev/null
@@ -0,0 +1,72 @@
+define(['app/ovsdb/lib/sylvester'], function() {
+  function Transform(a, b, c, d , e, f) {
+    if (a)
+    this.transform = $M([
+      [a, b, c],
+      [d, e, f],
+      [0, 0, 1]
+    ]);
+    else
+      this.transform = Matrix.I(3);
+  }
+
+  Transform.fromString = function(string) {
+    if(!string) {
+      return new Transform();
+    }
+    var g = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+    g.setAttribute('transform', string);
+    var t = g.transform.baseVal.consolidate();
+    var m = t.matrix;
+    return new Transform(m.a, m.b, m.c, m.d, m.e, m.f);
+  }
+
+  Transform.combine = function(ma, mb) {
+    var t = new Transform();
+    t.transform = ma.transform.x(mb.transform);
+    return t;
+  }
+
+  Transform.prototype.translate = function(tx, ty) {
+    this.transform = $M([[1, 0, tx], [0, 1, ty], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.rotate = function(deg) {
+    var rad = parseFloat(deg) * (Math.PI/180),
+    cos = Math.cos(rad),
+    sin = Math.sin(rad);
+
+    this.transform = $M([[cos, -sin, 0], [sin, cos, 0], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.scale = function(x, y) {
+    var x = x,
+    y = y || x;
+
+    this.transform = $M([[x, 0, 0], [0, y, 0], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.skew = function(x, y) {
+    var alpha = Math.tan(parseFloat(x) * (Math.PI/180)),
+     betha = Math.tan(parseFloat(y) * (Math.PI/180));
+
+    this.transform = $M([[1, alpha, 0], [betha, 1, 0], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.transformPoint = function(x, y) {
+    var v = $V([x, y, 1]);
+    return this.transform.x(v);
+  };
+
+  Transform.prototype.toString = function() {
+    return this.transform.inspect();
+  }
+
+  return {
+    Matrix: Transform // Matrix function name already used by Sylvester
+  };
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.constant.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.constant.js
new file mode 100644 (file)
index 0000000..cc07e73
--- /dev/null
@@ -0,0 +1,72 @@
+define(['app/ovsdb/ovsdb.module'], function (ovsdb) {
+
+  ovsdb.register.constant('nodeIdentifier', {
+    IP: 'ip',
+    ID: 'node-id',
+    REMOTE_PORT: 'remote-port',
+    SRC_NODE: 'source-node',
+    DEST_NODE: 'dest-node',
+    SRC_TP: 'source-tp',
+    DEST_TP: 'dest-tp',
+    ADDRESSES: 'addresses'
+  });
+
+  ovsdb.register.constant('ovsNodeKeys', {
+    NODE_ID: 'node-id',
+    CONNECTION_INFO: 'ovsdb:connection-info',
+    OVS_VERSION: 'ovsdb:ovs-version',
+    LOCAL_IP: 'local-ip',
+    LOCAL_PORT: 'local-port',
+    REMOTE_IP: 'remote-ip',
+    REMOTE_PORT: 'remote-port',
+    OTHER_CONFIG: 'ovsdb:openvswitch-other-configs',
+    OTHER_CONFIG_KEY: 'other-config-key',
+    OTHER_CONFIG_VALUE: 'other-config-value'
+  });
+
+  ovsdb.register.constant('bridgeNodeKeys', {
+    NODE_ID: 'node-id',
+    CONTROLLER_ENTRY: 'ovsdb:controller-entry',
+    TARGET: 'target',
+    IS_CONNECTED: 'is-connected',
+    DATA_PATH: 'ovsdb:datapath-id',
+    BRIDGE_NAME: 'ovsdb:bridge-name',
+    TP: 'termination-point'
+  });
+
+  ovsdb.register.constant('tpKeys', {
+    NAME: 'ovsdb:name',
+    OF_PORT: 'ovsdb:ofport',
+    INTERFACE_TYPE: 'ovsdb:interface-type',
+    ATTACHED_MAC: 'attached-mac',
+    IFACE_ID: 'iface-id',
+    EXTERNAL_KEY_ID: 'external-id-key',
+    EXTERNAL_KEY_VALUE: 'external-id-value'
+  });
+
+  ovsdb.register.constant('flowInfoKeys', {
+    FEATURE: 'flow-node-inventory:switch-features',
+    SOFTWARE: 'flow-node-inventory:software',
+    HARDWARE: 'flow-node-inventory:hardware',
+    MANUFACTURER: 'flow-node-inventory:manufacturer',
+    IP: 'flow-node-inventory:ip-address',
+    TABLE: 'flow-node-inventory:table'
+  });
+
+  ovsdb.register.constant('linkIdentifier', {
+    SRC: 'source',
+    l3_unicast: 'l3-unicast-igp-topology:igp-link-attributes',
+    overlay_tunnel_type: 'overlay:tunnel-type',
+    supported_link: 'supporting-link',
+    ID: 'link-id',
+    DEST: 'destination'
+  });
+
+  ovsdb.register.constant('OVSConstant', {
+    TP_TYPE: {
+      INTERNAL: 'ovsdb:interface-type-internal',
+      VXLAN: 'ovsdb:interface-type-vxlan'
+    }
+  })
+
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.controller.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.controller.js
new file mode 100644 (file)
index 0000000..95a8c9b
--- /dev/null
@@ -0,0 +1,181 @@
+/*\r
+ * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+define(['jquery', 'underscore', 'app/ovsdb/ovsdb.module', 'app/ovsdb/OvsCore', 'app/ovsdb/ovsdb.directives', 'app/ovsdb/ovsdb.services', 'app/ovsdb/lib/select2.full.min'], function ($, _, ovsdb, OvsCore) {\r
+  'use strict';\r
+\r
+  var RootOvsdbCtrl = function ($rootScope, cssInjector) {\r
+    // transparent 1px gif picture\r
+    $rootScope['section_logo'] = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';\r
+\r
+    cssInjector.add('src/app/ovsdb/css/select2.min.css');\r
+    cssInjector.add('src/app/ovsdb/css/toggle-switch.css');\r
+\r
+    cssInjector.add('src/app/ovsdb/css/ovsdb.css');\r
+  };\r
+  RootOvsdbCtrl.$inject = ['$rootScope', 'cssInjector'];\r
+\r
+  var BaseOvsdbCtrl = function ($scope) {\r
+    $scope.err = {\r
+      "message": "",\r
+      "tag": "",\r
+      "type": ""\r
+    };\r
+    $scope.showError = function () {\r
+      $('#errorMessage').fadeIn().delay(3000).fadeOut();\r
+    };\r
+  };\r
+  BaseOvsdbCtrl.$inject = ['$scope'];\r
+\r
+  var OvsdbCtrl = function ($q, $scope, TopologySvc, NeutronSvc, OvsUtil) {\r
+    BaseOvsdbCtrl.call(this, $scope);\r
+    var lgraphDataDefer = $q.defer(),\r
+      physDataDefer = $q.defer(),\r
+      filterTenant = {\r
+        bridgeIds : [''],\r
+        ovsdbIds : ['']\r
+      },\r
+      filterSubnet = {\r
+        bridgeIds : [''],\r
+        ovsdbIds : ['']\r
+      };\r
+\r
+    $scope.dataPromise = physDataDefer.promise;\r
+    $scope.lgraphIsReadyPromise = lgraphDataDefer.promise;\r
+    $scope.canvasWidth = $('#tabs').width();\r
+    $scope.canvasHeight = 580;\r
+\r
+    $scope.dialogData = ['d'];\r
+\r
+    $scope.tenants = [];\r
+    $scope.subnets = [];\r
+    $scope.selectedTenant = '';\r
+    $scope.selectedSubnet = '';\r
+\r
+    $scope.toggleLayer = function () {\r
+      $scope.rotateGraph($scope.opt.layer);\r
+    };\r
+\r
+    $scope.resizeGraph = function () {\r
+      var $row = $('#ovsdb_contain > div.row:first');\r
+      var h = $row.height();\r
+      $row.data('ph', h);\r
+      $row.fadeOut();\r
+      $('#nv_graph > svg').animate({\r
+        height: '+=' + h\r
+      });\r
+    };\r
+\r
+    $scope.minimizeGraph = function () {\r
+      var $row = $('#ovsdb_contain > div.row:first');\r
+      var h = $row.data('ph');\r
+      $row.fadeIn();\r
+      $('#nv_graph > svg').animate({\r
+        height: '-=' + h\r
+      });\r
+    };\r
+\r
+    function applyFilter(inverse) {\r
+      var bridgeIds = _.uniq(filterTenant.bridgeIds.concat(filterSubnet.bridgeIds));\r
+      var ovsdbIds = _.uniq(filterTenant.ovsdbIds.concat(filterSubnet.ovsdbIds));\r
+      $scope.filterNode(bridgeIds, '.bridge');\r
+      $scope.filterNode(ovsdbIds, '.switch');\r
+      $scope.filterLink();\r
+    }\r
+\r
+    function removeFilter() {\r
+      $scope.filterNode([''], '.bridge', false);\r
+      $scope.filterNode([''], '.switch', false);\r
+      $scope.filterLink();\r
+    }\r
+\r
+    $scope.fiterByTenant = function() {\r
+      if ($scope.selectedTenant) {\r
+        var tenant = $scope.selectedTenant;\r
+        OvsUtil.extractLogicalByTenant(tenant.id).then(function(result) {\r
+          var bridgeId = result[0],\r
+            ovsdbId = result[1];\r
+\r
+          filterTenant.bridgeIds = _.uniq(filterTenant.bridgeIds.concat(bridgeId));\r
+          filterTenant.ovsdbIds = _.uniq(filterTenant.ovsdbIds.concat(ovsdbId));\r
+          applyFilter();\r
+        });\r
+      } else {\r
+        filterTenant.bridgeIds = [''];\r
+        filterTenant.ovsdbIds = [''];\r
+        applyFilter();\r
+      }\r
+    };\r
+\r
+    $scope.filterBySubnet = function() {\r
+      if (!_.isEmpty($scope.selectedSubnet)) {\r
+        var subnets = _.map($scope.selectedSubnet, function(d) {\r
+          return d.id;\r
+        });\r
+        OvsUtil.extractLogicalBySubnet(subnets).then(function(result) {\r
+          var bridgeId = result[0],\r
+            ovsdbId = result[1];\r
+            filterSubnet.bridgeIds = _.uniq(filterSubnet.bridgeIds.concat(bridgeId));\r
+            filterSubnet.ovsdbIds = _.uniq(filterSubnet.ovsdbIds.concat(ovsdbId));\r
+            applyFilter();\r
+        });\r
+      } else {\r
+        filterSubnet.bridgeIds = [''];\r
+        filterSubnet.ovsdbIds = [''];\r
+        applyFilter();\r
+      }\r
+    };\r
+\r
+    $scope.onNodeClick = function (d, nodes, links) {\r
+      $scope.pDialogData = d.node.pretty();\r
+      $scope.$apply();\r
+    };\r
+\r
+    $('#tenantSelect').select2({\r
+      width: "200",\r
+      minimumResultsForSearch: Infinity\r
+    }).next().children('span').children('span').css('width', '200'); //hack to have the arrow with the same background\r
+\r
+    $("#tagPicker").select2({\r
+      width: "230",\r
+    });\r
+\r
+    var $tabs = $('#tabs').tabs({selected: 0});\r
+\r
+    $scope.goToPhysicalView = function(d) {\r
+      $tabs.tabs("option", "active", 1);\r
+      $('#tenantSelect').val(d.tenantId).change();\r
+\r
+      if ( d instanceof OvsCore.Neutron.Network) {\r
+        $('#tagPicker').val(d.subnets.map(function(d){return d.id;})).change();\r
+      }\r
+    };\r
+\r
+    OvsUtil.getLogicalTopology().then(function(networks) {\r
+      var tenantList = NeutronSvc.getAllTenants();\r
+      _.each(tenantList, function(t) {\r
+        $scope.tenants.push({id : t, name: t});\r
+      });\r
+      NeutronSvc.getSubNets().then(function(subHash) {\r
+        $scope.subnets = _.values(subHash).map(function(n) { return n[0]; });\r
+      });\r
+\r
+      lgraphDataDefer.resolve(networks);\r
+    });\r
+\r
+    TopologySvc.getTopologies().then(function(d) {\r
+      physDataDefer.resolve(d);\r
+    });\r
+\r
+  };\r
+\r
+  OvsdbCtrl.$inject = ['$q', '$scope', 'TopologySvc', 'NeutronSvc', 'OvsUtil'];\r
+  OvsdbCtrl.prototype = Object.create(BaseOvsdbCtrl.prototype);\r
+\r
+  ovsdb.register.controller('RootOvsdbCtrl', RootOvsdbCtrl);\r
+  ovsdb.register.controller('OvsdbCtrl', OvsdbCtrl);\r
+});\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.directives.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.directives.js
new file mode 100644 (file)
index 0000000..b929eb9
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+define(['app/ovsdb/ovsdb.module', 'app/ovsdb/lib/d3.min', 'app/ovsdb/Graph', 'app/ovsdb/LogicalGraph', 'app/ovsdb/OvsCore', 'underscore', 'jquery', 'jquery-ui'], function (ovsdb, d3, Graph, LogicalGraph, OvsCore, _, $) {
+  'use strict';
+
+  ovsdb.register.directive('logicalGraph', function () {
+    return {
+      restrict: 'EA',
+      scope: false,
+      link: function (scope, elem, attr) {
+        var lgraph = null,
+          tabCreated = false,
+          width = scope.canvasWidth, //ele[0].clientWidth,
+          height = scope.canvasHeight;
+
+        scope.lDialogData = {};
+
+        scope.lgraphIsReadyPromise.then(function (ltopo) {
+          if (!lgraph) {
+            lgraph = new LogicalGraph(elem[0], width, height);
+          }
+
+          lgraph.networks = ltopo;
+
+          lgraph.start();
+
+          lgraph.onClick = function (d) {
+            var dialogId = '#lDialog';
+            scope.lDialogData = d.pretty();
+            scope.$apply();
+
+            if (!tabCreated) {
+              $(dialogId).tabs();
+              $(dialogId).draggable({
+                containment: 'parent',
+                cancel: '.window_content'
+              });
+              tabCreated = true;
+            } else {
+              $(dialogId).tabs('refresh');
+            }
+
+            var $dia = $(dialogId),
+              left = $dia.css('left'),
+              top = $dia.css('top') || e.top + 35;
+            $dia.css('left', left !== 'auto' ? left : 10);
+            $dia.css('top', top !== 'auto' ? top : 10);
+            $dia.show();
+
+          };
+
+          lgraph.dblClick = function (d) {
+            scope.goToPhysicalView(d);
+          };
+        });
+        scope.hideLogicalDialog = function () {
+          $('#lDialog').tabs("option", "active", 0)
+            .hide();
+        };
+        elem.on('$destroy', function () {
+          if (lgraph) {
+            lgraph.freeDOM();
+          }
+        });
+      }
+    };
+  });
+
+  ovsdb.register.directive('physicalGraph', function (CacheFactory) {
+    return {
+      restrict: 'EA',
+      scope: false,
+      //templateUrl: 'src/app/ovsdb/views/graph_header.tpl.html',
+      link: function (scope, ele, attr) {
+
+        var graph = null,
+          tabCreated = false,
+          width = scope.canvasWidth,
+          height = scope.canvasHeight;
+
+        scope.reset = function () {
+          var transform = d3.transform(vis.attr('transform')),
+            ix = d3.interpolate(x.domain(), [-width / 2, width / 2]),
+            iy = d3.interpolate(y.domain(), [-height / 2, height / 2]),
+            px = x.domain(ix(1)),
+            py = y.domain(iy(1));
+
+          vis.transition().duration(750).call(zoom.x(px).y(py).scale(1).event);
+        };
+
+        scope.dataPromise.then(function (topo) {
+          if (!graph) {
+            console.log('physical graph created');
+            graph = new Graph(ele[0], width, height);
+          }
+          var nodes = _.clone(topo.nodes);
+          var links = _.clone(topo.links);
+
+          graph.setPosCache(CacheFactory.getCacheObj('nodePos'));
+
+          graph.links = _.values(links);
+          graph.nodes = _.map(nodes, function (value) {
+            return {
+              node: value
+            };
+          });
+          graph.start();
+
+          scope.nbOpenFlowSwitch = _.size(topo.bridgeNodes);
+          scope.nbOvsNode = _.size(topo.ovsdbNodes);
+
+          var linkedByIndex = {};
+          _.each(topo.flowLinks, function (d) {
+            linkedByIndex[d.source + ',' + d.target] = true;
+          });
+
+          function isConnected(a, b) {
+            return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
+          }
+
+          function hasConnections(a) {
+            for (var property in linkedByIndex) {
+              var s = property.split(",");
+              if ((s[0] == a.index || s[1] == a.index) && linkedByIndex[property])
+                return true;
+            }
+            return false;
+          }
+
+          graph.onNodeOver = function (d, nodes, links) {
+            nodes.selectAll('.switch > rect').style("stroke", function (o) {
+              return isConnected(d, o) ? "blue" : "black";
+            });
+
+            links.style("stroke", function (o) {
+              return ((o.source.index == d.index || o.target.index == d.index) && o.linkType != 'tunnel') ? "blue" : o.color;
+            });
+          };
+
+          graph.onNodeOut = function (d, nodes, links) {
+            nodes.selectAll('.switch > rect').style("stroke", "black");
+            links.style("stroke", function (o) {
+              return o.color;
+            });
+          };
+
+          graph.onNodeClick = function (d, nodes, links, ctx) {
+            /*var node = d3.select(ctx);
+            d3.select('.node_selected').classed('node_selected', false).attr('filter', 'none');
+            node.classed('node_selected', true).attr('filter', 'url(#selectNode)');*/
+            scope.onNodeClick(d);
+            var dialogId = '#pDialog',
+              $dia = $(dialogId);
+
+            if (!tabCreated) {
+              $(dialogId).tabs();
+              $(dialogId).draggable({
+                containment: 'parent',
+                cancel: '.window_content'
+              });
+              tabCreated = true;
+            } else {
+              $(dialogId).tabs('refresh');
+            }
+
+            $dia.css('left', /*e.left + */ 30);
+            $dia.css('top', /*e.top + */ 35);
+            $dia.show();
+          };
+
+        });
+
+        ele.on('$destroy', function () {
+          graph.freeDOM();
+        });
+
+        scope.hidePhysicalDialog = function () {
+          $('#pDialog').tabs("option", "active", 0)
+            .hide();
+        };
+
+        scope.rotateGraph = function (value) {
+          var b = value ? 1 : -1;
+          graphs.applyPerspective(value);
+          graphs.update();
+          $('path.tunnel').toggle();
+        };
+
+        scope.filterNode = function (nodeIds, tags, exclude) {
+          exclude = (exclude === null) ? true : exclude;
+          var nodes = d3.selectAll(tags);
+          nodes.each(function (d) {
+            if (nodeIds.indexOf(d.node.nodeId) < 0) {
+              d.hidden = exclude;
+            } else {
+              d.hidden = !exclude;
+            }
+          });
+          nodes.transition().duration(200).style('opacity', function (d) {
+            return d.hidden ? '0.3' : '1';
+          });
+
+        };
+
+        scope.filterLink = function () {
+          var links = d3.selectAll(".tunnel, .link, .bridgeOvsLink");
+
+          links.each(function (d, i) {
+            d.hidden = d.source.hidden || d.target.hidden;
+          });
+          links.transition().duration(200).style('opacity', function (d) {
+            return d.hidden ? '0.3' : '1';
+          });
+        };
+      }
+    };
+  });
+
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.module.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.module.js
new file mode 100644 (file)
index 0000000..4bad2bb
--- /dev/null
@@ -0,0 +1,85 @@
+/*\r
+ * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+define(['angularAMD', 'app/routingConfig', 'Restangular', 'angular-translate', 'angular-translate-loader-static-files', 'app/core/core.services', 'common/config/env.module'], function(ng) {\r
+  'use strict';\r
+\r
+  var ovsdb = angular.module('app.ovsdb', ['app.core', 'pascalprecht.translate', 'ui.router.state', 'restangular', 'config']);\r
+  ovsdb.register = ovsdb; // for unit test\r
+\r
+  // Filter to access neutron opendaylight.\r
+  // This factory need to be to avoid circular dependencies.\r
+  ovsdb.factory('NeutronInterceptor', ['$q', '$window', 'Base64', function($q, $window, Base64) {\r
+    return {\r
+      request : function(config) {\r
+          // Use AAA basic authentication\r
+        if (config.url.indexOf('controller/nb/v2') != -1) {\r
+          config.headers = config.headers || {};\r
+          if ($window.sessionStorage.odlUser && $window.sessionStorage.odlPass) {\r
+            var encoded = Base64.encode('admin' + ':' + 'admin');\r
+            config.headers.Authorization = 'Basic ' + encoded;\r
+          }\r
+        }\r
+        return config;\r
+      },\r
+      response : function(response) {\r
+        return response || $q.when(response);\r
+      }\r
+    };\r
+  }]);\r
+\r
+  ovsdb.config(function($stateProvider, $compileProvider, $controllerProvider, $provide, $httpProvider, NavHelperProvider) {\r
+    ovsdb.register = {\r
+      controller : $controllerProvider.register,\r
+      directive : $compileProvider.directive,\r
+      factory : $provide.factory,\r
+      service : $provide.service,\r
+      constant: $provide.constant\r
+\r
+    };\r
+\r
+    NavHelperProvider.addControllerUrl('src/app/ovsdb/ovsdb.controller.js');\r
+    NavHelperProvider.addToMenu('Ovsdb', {\r
+     "link" : "#/ovsdb/index",\r
+     "active" : "main.ovsdb.*",\r
+     "title" : "Network Virtualization",\r
+     "icon" : "icon-sitemap",\r
+     "page" : {\r
+        "title" : "NetWork Virtualization",\r
+        "description" : "OVSDB"\r
+     }\r
+    });\r
+\r
+    var access = routingConfig.accessLevels;\r
+    $stateProvider.state('main.ovsdb', {\r
+      url: 'ovsdb',\r
+      abstract: true,\r
+      views : {\r
+        'content' : {\r
+          templateUrl: 'src/app/ovsdb/views/root.tpl.html',\r
+          controller: 'RootOvsdbCtrl'\r
+        }\r
+      }\r
+    });\r
+\r
+    $stateProvider.state('main.ovsdb.index', {\r
+      url: '/index',\r
+      access: access.admin,\r
+      views: {\r
+        '': {\r
+          templateUrl: 'src/app/ovsdb/views/index.tpl.html',\r
+          controller: 'OvsdbCtrl'\r
+        }\r
+      }\r
+    });\r
+\r
+    $httpProvider.interceptors.push('NeutronInterceptor');\r
+  });\r
+\r
+  return ovsdb;\r
+});\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.services.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.services.js
new file mode 100644 (file)
index 0000000..d3e2806
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+define(['app/ovsdb/ovsdb.module', 'app/ovsdb/OvsCore', 'underscore', 'app/ovsdb/ovsdb.constant'], function (ovsdb, OvsCore, _) {
+  'use strict';
+
+  ovsdb.register.factory('OvsdbRestangular', ['Restangular', 'ENV', function (Restangular, ENV) {
+    return Restangular.withConfig(function (RestangularConfig) {
+      RestangularConfig.setBaseUrl(ENV.getBaseURL("MD_SAL"));
+    });
+  }]);
+
+  // nbv2 support depricated in dlux
+  ovsdb.register.factory('NeutronRestangular', ['Restangular', function (Restangular) {
+    return Restangular.withConfig(function (RestangularConfig) {
+      var baseUrl = window.location.protocol + '//' + window.location.hostname;
+      RestangularConfig.setBaseUrl(baseUrl + ':8080/controller/nb/v2/neutron');
+    });
+  }]);
+
+  ovsdb.register.factory('CacheFactory', function ($q) {
+    var svc = {},
+      ovsCache = {};
+    /*BUG : Using the persistant cache make the physical
+     * graph links to stop reacting with the force layout
+     * algorithm. The current behavior is to use the cache
+     * only the pile up the datas.
+     */
+    svc.obtainDataFromCache = function (key, fn, ctx) {
+      var cacheDefer = $q.defer();
+
+      if (angular.isUndefined(ovsCache[key])) {
+        fn.call(ctx, function (data) {
+          ovsCache[key] = {
+            obj: data,
+            timestamp: Date.now() + 2000 //300000 // 5 mintues
+          };
+          cacheDefer.resolve(data);
+        });
+      } else {
+        var cacheObj = ovsCache[key];
+        if (cacheObj.timestamp < Date.now() || _.isEmpty(cacheObj.obj)) {
+          fn.call(ctx, function (data) {
+            ovsCache[key] = {
+              obj: data,
+              timestamp: Date.now() + 2000 //300000 // 5 mintues
+            };
+            cacheDefer.resolve(data);
+          });
+        } else {
+          cacheDefer.resolve(cacheObj.obj);
+        }
+      }
+
+      return cacheDefer.promise;
+    };
+
+    svc.getCacheObj = function (key) {
+      if (angular.isUndefined(ovsCache[key])) {
+        ovsCache[key] = {};
+      }
+      return ovsCache[key];
+    };
+
+    return svc;
+  });
+
+  var TopologySvc = function (OvsdbRestangular, nodeIdentifier, ovsNodeKeys, bridgeNodeKeys, tpKeys, flowInfoKeys, linkIdentifier, OVSConstant, $q, $http, CacheFactory) {
+    var svc = {
+      base: function (type) {
+        return OvsdbRestangular.one('restconf').one(type);
+      }
+    };
+
+    function parseOvsdbNode(node) {
+      var inetMgr = '',
+        inetNode = '',
+        otherLocalIp = '',
+        otherInfo = null,
+        connectionInfo = null;
+
+      connectionInfo = node[ovsNodeKeys.CONNECTION_INFO];
+      otherInfo = node[ovsNodeKeys.OTHER_CONFIG];
+
+      if (_.isObject(connectionInfo)) {
+        inetMgr = connectionInfo[ovsNodeKeys.LOCAL_IP] + ':' + connectionInfo[ovsNodeKeys.LOCAL_PORT];
+        inetNode = connectionInfo[ovsNodeKeys.REMOTE_IP] + ':' + connectionInfo[ovsNodeKeys.REMOTE_PORT];
+      }
+
+      if (_.isArray(otherInfo)) {
+        _.each(otherInfo, function (value) {
+          if (value[ovsNodeKeys.OTHER_CONFIG_KEY] === 'local_ip') {
+            otherLocalIp = value[ovsNodeKeys.OTHER_CONFIG_VALUE];
+          }
+        });
+      }
+
+      return new OvsCore.OvsNode(node[ovsNodeKeys.NODE_ID], inetMgr, inetNode, otherLocalIp, node[ovsNodeKeys.OVS_VERSION]);
+    }
+
+    function parseBridgeNode(node) {
+      var bridgeNode = null,
+        controllerTarget = '',
+        controllerConnected = false,
+        tp = node[bridgeNodeKeys.TP],
+        controllerEntries = node[bridgeNodeKeys.CONTROLLER_ENTRY];
+
+      _.each(controllerEntries, function (value) {
+        controllerTarget = value[bridgeNodeKeys.TARGET];
+        controllerEntries = value[bridgeNodeKeys.IS_CONNECTED];
+        return false; // break the anonymus function
+      });
+
+      bridgeNode = new OvsCore.BridgeNode(node[bridgeNodeKeys.NODE_ID], node[bridgeNodeKeys.DATA_PATH], node[bridgeNodeKeys.BRIDGE_NAME], controllerTarget, controllerConnected);
+
+      _.each(tp, function (value) {
+        var tp = parseBridgeTP(value);
+
+        if (tp.ofPort == '65534' && (tp.name === 'br-ex' || tp.name === 'br-int')) {
+          return;
+        } else {
+          bridgeNode.addTerminationPoint(tp);
+        }
+
+      });
+
+      return bridgeNode;
+    }
+
+    function parseBridgeTP(tp) {
+      var mac = '',
+        ifaceId = '',
+        extInfo = tp['ovsdb:port-external-ids'] || tp['ovsdb:interface-external-ids'],
+        type = tp[tpKeys.INTERFACE_TYPE];
+
+      _.each(extInfo, function (ext) {
+        if (ext[tpKeys.EXTERNAL_KEY_ID] === tpKeys.ATTACHED_MAC) {
+          mac = ext[tpKeys.EXTERNAL_KEY_VALUE];
+        }
+        if (ext[tpKeys.EXTERNAL_KEY_ID] === tpKeys.IFACE_ID) {
+          ifaceId = ext[tpKeys.EXTERNAL_KEY_VALUE] || '';
+        }
+      });
+      if (type === OVSConstant.TP_TYPE.VXLAN) {
+        var localIp = null,
+          remoteIp = null;
+        _.each(tp['ovsdb:options'], function (option) {
+          switch (option.option) {
+            case 'local_ip':
+              localIp = option.value;
+              break;
+            case 'remote_ip':
+              remoteIp = option.value;
+              break;
+          }
+        });
+        return new OvsCore.Tunnel(tp[tpKeys.NAME], tp[tpKeys.OF_PORT], type, mac, ifaceId, localIp, remoteIp);
+      }
+      return new OvsCore.TerminationPoint(tp[tpKeys.NAME], tp[tpKeys.OF_PORT], type, mac, ifaceId);
+
+    }
+
+    function fetchTopology(cb) {
+      var invNodeDefer = this.base('operational').one('opendaylight-inventory:nodes').getList();
+      var netTopoDefer = this.base('operational').one('network-topology:network-topology').getList();
+
+      // be sure all data are loaded
+      $q.all([invNodeDefer, netTopoDefer]).then(function (values) {
+          var invNode = values[0],
+            netTopo = values[1],
+            index_hash = [],
+            i = 0;
+
+          // check if the data look fine in network topology
+          if (!netTopo || !netTopo['network-topology'] || !netTopo['network-topology'].topology) {
+            throw new Error('Invalid json format while parsing network-topology');
+          }
+
+          // check if the data look fine in inventory node
+          if (!invNode || !invNode.nodes || !invNode.nodes.node) {
+            throw new Error('Invalid JSON format while parsing inventory-node');
+          }
+
+          // get all topologies and start looping
+          var topologies = netTopo['network-topology'].topology,
+            nodes = invNode.nodes.node,
+            topo = new OvsCore.Topology();
+
+          _.each(topologies, function (topology, topo_index) {
+            if (!topology.hasOwnProperty('topology-id')) {
+              throw new Error('Invalide JSON format, no topology-id for the topology [' + topo_index + ']');
+            }
+
+            // if there no node it will be an empty array so noop
+            (topology.node || []).forEach(function (node) {
+              if (!node[nodeIdentifier.ID]) {
+                throw new Error('Unexpected node : undefined ' + nodeIdentifier.ID + ' key');
+              }
+              index_hash[node[nodeIdentifier.ID]] = i++;
+
+              if (node['ovsdb:bridge-name']) {
+                //bridge Node
+                topo.registerBridgeNode(parseBridgeNode(node));
+              } else if (node['ovsdb:connection-info']) {
+                // obsvdb Node
+                topo.registerOvsdbNode(parseOvsdbNode(node));
+              }
+            });
+
+            // if there no link it will be an empty array so noop
+            (topology.link || []).forEach(function (link) {
+
+              var source = link[linkIdentifier.SRC]['source-node'],
+                dest = link[linkIdentifier.DEST]['dest-node'];
+
+              topo.registerLink(new OvsCore.Link(link[linkIdentifier.ID], source, dest));
+            });
+
+          });
+
+          _.each(nodes, function (node, index) {
+            if (!node.id) {
+              return;
+            }
+
+            var bridgeId = node.id;
+
+            var bridgeNode = _.filter(topo.bridgeNodes, function (bridgeNode) {
+              return bridgeNode.getFLowName() === bridgeId;
+            })[0];
+
+            // match info for bridge node
+            if (bridgeNode) {
+              bridgeNode.flowInfo.features = node[flowInfoKeys.FEATURE];
+              bridgeNode.flowInfo.software = node[flowInfoKeys.SOFTWARE];
+              bridgeNode.flowInfo.hardware = node[flowInfoKeys.HARDWARE];
+              bridgeNode.flowInfo.manufacturer = node[flowInfoKeys.MANUFACTURER];
+              bridgeNode.flowInfo.ip = node[flowInfoKeys.IP];
+
+              _.each(node[flowInfoKeys.TABLE], function (entry) {
+                if (!_.isUndefined(entry.id)) {
+                  _.each(entry.flow, function (flow) {
+                    bridgeNode.addFlowTableInfo({
+                      key: flow.table_id,
+                      value: flow.id
+                    });
+                  });
+                }
+              });
+            }
+          });
+
+          // show relation between ovsNode and switch with a link
+          _.each(topo.ovsdbNodes, function (node, index) {
+            var bridges = _.filter(topo.bridgeNodes, function (bnode) {
+              return bnode.nodeId.indexOf(node.nodeId) > -1;
+            });
+            _.each(bridges, function (bridge) {
+              var size = _.size(topo.links),
+                link = new OvsCore.BridgeOvsLink(++size, node.nodeId, bridge.nodeId);
+              topo.registerLink(link);
+            });
+          });
+
+          function findVxlan(bridgeNode) {
+            var tunnels = [];
+
+            _.each(bridgeNode, function (node) {
+              var ovsdbNode = _.find(topo.ovsdbNodes, function (oNode) {
+                return node.nodeId.indexOf(oNode.nodeId) > -1;
+              });
+              if (!ovsdbNode) {
+                return false;
+              }
+              _.each(node.tPs, function (tp, index) {
+                if (tp instanceof OvsCore.Tunnel) {
+                  tunnels.push({
+                    port: tp,
+                    bridge: node
+                  });
+                }
+              });
+            });
+
+            return tunnels;
+          }
+
+          // extract all tunnel paired with their bridge
+          var tunnels = findVxlan(topo.bridgeNodes);
+          // loop over all pairs
+          for (var index = 0; index < tunnels.length; ++index) {
+            var tunnel = tunnels[index],
+              currIp = tunnel.port.localIp,
+              destIp = tunnel.port.remoteIp,
+              pairIndex = 0,
+              linkedBridge = _.find(tunnels, function (t, i) {
+                pairIndex = i;
+                return t.port.remoteIp === currIp && t.port.localIp == destIp;
+              });
+
+            if (linkedBridge) {
+              tunnels.splice(pairIndex, 1);
+              topo.registerLink(new OvsCore.TunnelLink(tunnel.port.name + linkedBridge.port.name, tunnel.bridge.nodeId, linkedBridge.bridge.nodeId));
+            }
+          }
+
+          topo.updateLink();
+          cb(topo);
+        },
+        function (err) {
+          throw err;
+        }
+      );
+    }
+
+    svc.getTopologies = function () {
+      return CacheFactory.obtainDataFromCache('topologies', fetchTopology, this);
+    };
+
+    return svc;
+  };
+  TopologySvc.$inject = ['OvsdbRestangular', 'nodeIdentifier', 'ovsNodeKeys', 'bridgeNodeKeys', 'tpKeys', 'flowInfoKeys', 'linkIdentifier', 'OVSConstant', '$q', '$http', 'CacheFactory'];
+
+  var NeutronSvc = function (NeutronRestangular, CacheFactory, $q, $http) {
+    var svc = {
+        base: function (type) {
+          return NeutronRestangular.one(type);
+        }
+      },
+      tenant_hash = {};
+
+    function fetchSubNetworks(cb) {
+      var subnetskDefer = svc.base('subnets').getList();
+      subnetskDefer.then(function (data) {
+        var subnets = data,
+          subnetHash = {};
+
+        if (!subnets || !subnets.subnets) {
+          throw new Error('Invalid format from neutron subnets');
+        }
+
+        _.each(subnets.subnets, function (subnet) {
+          if (!subnetHash[subnet.network_id]) {
+            subnetHash[subnet.network_id] = [];
+          }
+          tenant_hash[subnet.tenant_id] = {};
+          subnetHash[subnet.network_id].push(new OvsCore.Neutron.SubNet(
+            subnet.id,
+            subnet.network_id,
+            subnet.name,
+            subnet.ip_version,
+            subnet.cidr,
+            subnet.gateway_ip,
+            subnet.tenant_id
+          ));
+        });
+        cb(subnetHash);
+      });
+    }
+
+    function fetchNetworks(cb) {
+      var networkDefer = svc.base('networks').getList();
+      var subnetskDefer = svc.getSubNets();
+
+      $q.all([subnetskDefer, networkDefer]).then(function (datas) {
+        var subnetsHash = datas[0],
+          networks = datas[1],
+          networkArray = [];
+
+        if (!networks || !networks.networks) {
+          throw new Error('Invalid format from neutron networks');
+        }
+
+        _.each(networks.networks, function (network) {
+          var net = new OvsCore.Neutron.Network(
+            network.id,
+            network.name,
+            network.shared,
+            network.status,
+            network['router:external'],
+            network.tenant_id
+          );
+          tenant_hash[net.tenantId] = {};
+          net.addSubNets(subnetsHash[net.id]);
+          networkArray.push(net);
+        });
+        cb(networkArray);
+      });
+    }
+
+    function fetchRouters(cb) {
+      var routerDefer = svc.base('routers').getList();
+      routerDefer.then(function (data) {
+        var routers = data.routers,
+          routerArray = [];
+
+        if (!routers) {
+          throw new Error('Invalid format from neutron routers');
+        }
+        _.each(routers, function (router) {
+          var id = router.id,
+            name = router.name,
+            status = router.status,
+            tenantId = router.tenant_id,
+            extGateWayInfo = router.external_gateway_info;
+          tenant_hash[tenantId] = {};
+          routerArray.push(new OvsCore.Neutron.Router(
+            id, name, status, tenantId, extGateWayInfo
+          ));
+        });
+        cb(routerArray);
+      });
+    }
+
+    function fetchPorts(cb) {
+      var portDefer = svc.base('ports').getList();
+      portDefer.then(function (data) {
+        var ports = data.ports,
+          portArray = [];
+
+        if (!ports) {
+          throw new Error('Invalid format from neutron ports');
+        }
+        _.each(ports, function (port) {
+          tenant_hash[port.tenant_id] = {};
+          portArray.push(new OvsCore.Neutron.Port(
+            port.id,
+            port.network_id,
+            port.name,
+            port.tenant_id,
+            port.device_id,
+            port.device_owner,
+            port.fixed_ips,
+            port.mac_address
+          ));
+        });
+        cb(portArray);
+      });
+    }
+
+    function fetchFloatingIps(cb) {
+      var floatingIpDefer = svc.base('floatingips').getList();
+      floatingIpDefer.then(function (data) {
+        var floatingIps = data.floatingips,
+          floatingIpArray = [];
+
+        if (!floatingIps) {
+          throw new Error('Invalid format from neutron floatingIps');
+        }
+
+        _.each(floatingIps, function (fIp) {
+          tenant_hash[fIp.tenant_id] = {};
+          floatingIpArray.push(new OvsCore.Neutron.FloatingIp(
+            fIp.id,
+            fIp.floating_network_id,
+            fIp.port_id,
+            fIp.fixed_ip_address,
+            fIp.floating_ip_address,
+            fIp.tenant_id,
+            fIp.status
+          ));
+        });
+
+        cb(floatingIpArray);
+      });
+    }
+
+    svc.getNetworks = function () {
+      return CacheFactory.obtainDataFromCache('networks', fetchNetworks, this);
+    };
+
+    svc.getSubNets = function () {
+      return CacheFactory.obtainDataFromCache('subnet', fetchSubNetworks, this);
+    };
+
+    svc.getPorts = function () {
+      return CacheFactory.obtainDataFromCache('ports', fetchPorts, this);
+    };
+
+    svc.getRouters = function () {
+      return CacheFactory.obtainDataFromCache('routers', fetchRouters, this);
+    };
+
+    svc.getFloatingIps = function () {
+      return CacheFactory.obtainDataFromCache('floatingips', fetchFloatingIps, this);
+    };
+
+    svc.getAllTenants = function () {
+      return Object.keys(tenant_hash);
+    };
+
+    return svc;
+  };
+  NeutronSvc.$inject = ['NeutronRestangular', 'CacheFactory', '$q', '$http'];
+
+  var OvsUtil = function (NeutronSvc, TopologySvc, CacheFactory, $q) {
+    var svc = {};
+
+    function findOvsdbNodeForBridge(ovsdbNodes, bridge) {
+      return _.find(ovsdbNodes, function (node) {
+        return bridge.nodeId.indexOf(node.nodeId) > -1;
+      });
+    }
+
+    function pileUpTopologyData(cb) {
+      var networksDefer = NeutronSvc.getNetworks(),
+        routersDefer = NeutronSvc.getRouters(),
+        portsDefer = NeutronSvc.getPorts(),
+        floatingDefer = NeutronSvc.getFloatingIps(),
+        netTopoDefer = TopologySvc.getTopologies();
+
+      $q.all([networksDefer, routersDefer, portsDefer, floatingDefer, netTopoDefer]).then(function (datas) {
+        var networks = datas[0],
+          routers = datas[1],
+          ports = datas[2],
+          floatingIps = datas[3],
+          topo = datas[4];
+
+        // match ports with elements
+        _.each(ports, function (port) {
+          port.topoInfo = [];
+          // corelate port.topoInfo data with network topology termination point
+          _.each(topo.bridgeNodes, function (bridge) {
+            _.each(bridge.tPs, function (tp) {
+              if (tp.ifaceId === port.id) {
+                port.topoInfo.push({
+                  name: tp.name,
+                  ofPort: tp.ofPort,
+                  mac: bridge.dpIp,
+                  bridge: bridge,
+                  ovsNode: findOvsdbNodeForBridge(topo.ovsdbNodes, bridge)
+                });
+              }
+            });
+          });
+
+          switch (port.deviceOwner) {
+            case 'network:router_gateway':
+            case 'network:router_interface':
+              var router = _.find(routers, function (r) {
+                return r.id === port.deviceId;
+              });
+              if (router) {
+                router.interfaces.push({
+                  id: port.id,
+                  networkId: port.networkId,
+                  ip: port.fixed_ips[0],
+                  mac: port.mac,
+                  type: port.deviceOwner.replace('network:', ''),
+                  tenantId: port.tenantId,
+                  topoInfo: port.topoInfo
+                });
+              }
+              break;
+            case 'compute:None':
+            case 'compute:nova':
+            case 'network:dhcp':
+              var network = _.find(networks, function (n) {
+                  return n.id === port.networkId;
+                }),
+                inst = null;
+
+              if (network) {
+                inst = new OvsCore.Neutron.Instance(port.id, port.networkId,
+                  port.name, port.fixed_ips[0].ip_address, port.mac,
+                  port.deviceOwner, port.tenantId, port.topoInfo);
+
+                inst.extractFloatingIps(floatingIps);
+                network.instances.push(inst);
+              }
+              break;
+          }
+
+        });
+
+        // find all routers for a specific network
+        _.each(networks, function (network) {
+          network.routers = _.filter(routers, function (router) {
+            return network.id === router.externalGateway.network_id;
+          });
+
+          // order instance by ip
+          network.instances.sort(function (a, b) {
+            var ipA = a.ip.slice(a.ip.lastIndexOf('.') + 1),
+              ipB = b.ip.slice(b.ip.lastIndexOf('.') + 1);
+            return ipA - ipB;
+          });
+        });
+
+        cb(networks);
+      });
+    }
+
+    svc.getLogicalTopology = function () {
+      return CacheFactory.obtainDataFromCache('logicalTopology', pileUpTopologyData, this);
+    };
+
+    svc.extractLogicalByTenant = function (tenantId, subSet) {
+      var lTopoDefer = svc.getLogicalTopology(),
+        resultDefer = $q.defer();
+      lTopoDefer.then(function () {
+        var ports = CacheFactory.getCacheObj('ports').obj,
+          filteredPorts = _.filter(ports, function (p) {
+            return p.tenantId === tenantId;
+          });
+
+        if (!_.isEmpty(filteredPorts)) {
+          var bridgeHash = {};
+          _.each(filteredPorts, function (p) {
+            if (!_.isEmpty(p.topoInfo) && !bridgeHash[p.topoInfo[0].bridge.nodeId]) {
+              bridgeHash[p.topoInfo[0].bridge.nodeId] = {};
+            }
+          });
+          var ovsdbHash = {};
+          _.each(filteredPorts, function (p) {
+            if (!_.isEmpty(p.topoInfo) && !ovsdbHash[p.topoInfo[0].ovsNode.nodeId]) {
+              ovsdbHash[p.topoInfo[0].ovsNode.nodeId] = {};
+            }
+          });
+
+          resultDefer.resolve([Object.keys(bridgeHash), Object.keys(ovsdbHash)]);
+        } else {
+          resultDefer.resolve([], []);
+        }
+      });
+      return resultDefer.promise;
+    };
+
+    svc.extractLogicalBySubnet = function (subnets, subSet) {
+      var lTopoDefer = svc.getLogicalTopology(),
+        resultDefer = $q.defer();
+      lTopoDefer.then(function () {
+        var ports = CacheFactory.getCacheObj('ports').obj,
+          networks = CacheFactory.getCacheObj('networks').obj;
+
+        var filteredPorts = _.filter(ports, function (p) {
+          var net = _.find(networks, function (d) {
+            return d.id === p.networkId;
+          });
+
+          return net.asSubnet(subnets);
+        });
+        if (!_.isEmpty(filteredPorts)) {
+          var bridgeHash = {};
+          _.each(filteredPorts, function (p) {
+            if (!_.isEmpty(p.topoInfo) && !bridgeHash[p.topoInfo[0].bridge.nodeId]) {
+              bridgeHash[p.topoInfo[0].bridge.nodeId] = {};
+            }
+          });
+          var ovsdbHash = {};
+          _.each(filteredPorts, function (p) {
+            if (!_.isEmpty(p.topoInfo) && !ovsdbHash[p.topoInfo[0].ovsNode.nodeId]) {
+              ovsdbHash[p.topoInfo[0].ovsNode.nodeId] = {};
+            }
+          });
+          resultDefer.resolve([Object.keys(bridgeHash), Object.keys(ovsdbHash)]);
+        } else {
+          resultDefer.resolve([], []);
+        }
+      });
+      return resultDefer.promise;
+    };
+
+    return svc;
+  };
+
+  OvsUtil.$inject = ['NeutronSvc', 'TopologySvc', 'CacheFactory', '$q'];
+
+  ovsdb.register.factory('TopologySvc', TopologySvc);
+  ovsdb.register.factory('NeutronSvc', NeutronSvc);
+  ovsdb.register.factory('OvsUtil', OvsUtil);
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/views/graph_header.tpl.html b/ovsdb-ui/module/src/main/resources/ovsdb/views/graph_header.tpl.html
new file mode 100644 (file)
index 0000000..93a7b6e
--- /dev/null
@@ -0,0 +1,11 @@
+<!-- <div id="graph_header">
+  <span style="color:black; margin-left:15px;">Network Visualizer</span>
+  <i class="icon-fullscreen" style="float:right;" ng-click="resizeGraph()"></i>
+  <i class="icon-resize-small icon-2" style="float:right" ng-click="minimizeGraph()"></i>
+</div>
+-->
+
+<div id="graph_summary" data-option="false" data-title="Network Summary" nv-window style="text-align:center;">
+  <p style="font-style:italic;">{{nbOpenFlowSwitch}} brides
+    <br/> {{nbOvsNode}} switch</p>
+</div>
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/views/index.tpl.html b/ovsdb-ui/module/src/main/resources/ovsdb/views/index.tpl.html
new file mode 100644 (file)
index 0000000..8cb2a5f
--- /dev/null
@@ -0,0 +1,123 @@
+<!--\r
+ * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<div id="ovsdb_contain">\r
+  <!--\r
+<div class="row">\r
+  <div class="col-md-2 form-inline">\r
+    <label class="switch-light well">\r
+      <input type="checkbox" ng-model="opt.layer" ng-change="toggleLayer();">\r
+      <span>\r
+        Layer 3\r
+        <span>Off</span>\r
+        <span>On</span>\r
+      </span>\r
+\r
+      <a  class="btn btn-orange"></a>\r
+    </label>\r
+  </div>\r
+  <div class="col-md-2 form-inline">\r
+    <label class="switch-light well">\r
+      <input type="checkbox" ng-model="opt.underlay" ng-change="toggleUnderlay();">\r
+      <span>\r
+        Underlay\r
+        <span>Off</span>\r
+        <span>On</span>\r
+      </span>\r
+\r
+      <a class="btn btn-orange"></a>\r
+    </label>\r
+  </div>\r
+</div>\r
+-->\r
+  <div class="row">\r
+    <div class="col-md-12">\r
+      <div id="tabs">\r
+        <ul class="nav nav-tabs tabsHeader" style="margin-bottom:15px;">\r
+          <li><a href="#logical_view">Logical View</a></li>\r
+          <li><a href="#2d_view">2D View</a></li>\r
+        </ul>\r
+        <div id="logical_view" style="background-color:white; position:relative;">\r
+          <div id="l_graph" style="position:relative; height:580px;" logical-graph></div>\r
+\r
+          <div id="lDialog" class="ovsDialog arrow-left">\r
+            <div style="height:10px;">\r
+              <i data-ng-click="hideLogicalDialog()" class="window-icon icon-remove"></i>\r
+            </div>\r
+            <div class="window_content">\r
+              <ul class="nav nav-tabs tabsHeader">\r
+                <li ng-repeat="tab in lDialogData.tabs track by $index">\r
+                  <a href="#lDialogTab_{{$index}}" class="active">{{tab}}</a>\r
+                </li>\r
+              </ul>\r
+              <div ng-repeat="tabContaint in lDialogData.containts track by $index" id="lDialogTab_{{$index}}">\r
+                <table ng-if="!tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                  <tr ng-repeat="info in tabContaint.datas track by $index">\r
+                    <td> {{info.key}} </td>\r
+                    <td> {{ info.value }} </td>\r
+                  </tr>\r
+                </table>\r
+                <table ng-if="tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                  <tr>\r
+                    <th ng-repeat=" h in tabContaint.header track by $index">{{h}}</th>\r
+                  </tr>\r
+                  <tr ng-repeat="item in tabContaint.datas track by $index">\r
+                    <td ng-repeat="value in item track by $index"> {{ value }} </td>\r
+                  </tr>\r
+                </table>\r
+              </div>\r
+            </div>\r
+          </div>\r
+\r
+        </div>\r
+        <div id="2d_view">\r
+          <div class="row">\r
+            <div class="col-md-4 col-md-offset-1 form-inline">\r
+              <span>Tenant</span>\r
+              <select id="tenantSelect" ng-model="selectedTenant" ng-change="fiterByTenant()" ng-options="tenant.name for tenant in tenants track by tenant.id">\r
+                <option value="">---All---</option>\r
+              </select>\r
+            </div>\r
+            <div class="col-md-4 form-inline">\r
+              <span>Subnet</span>\r
+              <select id="tagPicker" multiple="multiple" ng-model="selectedSubnet" ng-change="filterBySubnet()" ng-options="subnet.name for subnet in subnets track by subnet.id">\r
+              </select>\r
+            </div>\r
+          </div>\r
+          <div id="nv_graph" style="position:relative; height:580px;" physical-graph></div>\r
+          <div id="pDialog" class="ovsDialog arrow-left">\r
+            <div style="height:10px">\r
+              <i data-ng-click="hidePhysicalDialog()" class="window-icon icon-remove"></i>\r
+            </div>\r
+            <div class="window_content">\r
+              <ul class="nav nav-tabs tabsHeader">\r
+                <li ng-repeat="tab in pDialogData.tabs track by $index">\r
+                  <a href="#pDialogTab_{{$index}}" class="active">{{tab}}</a>\r
+                </li>\r
+              </ul>\r
+              <div ng-repeat="tabContaint in pDialogData.containts track by $index" id="pDialogTab_{{$index}}">\r
+                <table ng-if="!tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                  <tr ng-repeat="info in tabContaint.datas track by $index">\r
+                    <td> {{info.key}} </td>\r
+                    <td> {{ info.value }} </td>\r
+                  </tr>\r
+                </table>\r
+                <table ng-if="tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                  <tr>\r
+                    <th ng-repeat=" h in tabContaint.header track by $index">{{h}}</th>\r
+                  </tr>\r
+                  <tr ng-repeat="item in tabContaint.datas track by $index">\r
+                    <td ng-repeat="value in item track by $index"> {{ value }} </td>\r
+                  </tr>\r
+                </table>\r
+              </div>\r
+            </div>\r
+          </div>\r
+        </div>\r
+      </div>\r
+      <!-- tab -->\r
+    </div>\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/views/root.tpl.html b/ovsdb-ui/module/src/main/resources/ovsdb/views/root.tpl.html
new file mode 100644 (file)
index 0000000..9e3cf15
--- /dev/null
@@ -0,0 +1,8 @@
+<!--\r
+* Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+*\r
+* This program and the accompanying materials are made available under the\r
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+* and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<div class="main" ui-view></div>\r
diff --git a/ovsdb-ui/pom.xml b/ovsdb-ui/pom.xml
new file mode 100644 (file)
index 0000000..da5c76a
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 Inocybe Technologies, 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>ovsdb-ui</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>ovsdb-ui</name>
+  <packaging>pom</packaging>
+  <prerequisites>
+    <maven>3.0</maven>
+  </prerequisites>
+  <modules>
+    <module>module</module>
+    <module>bundle</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/pom.xml b/pom.xml
index f24a35b9f8928b311beb05de7200578a39244f76..a49e45a35386a2022ab0bf9e1473f5227933d215 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -1,43 +1,63 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+Copyright (C) 2014 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 INTERNAL
---><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <groupId>org.opendaylight.vpnservice</groupId>
-  <artifactId>vpnservice</artifactId>
-  <version>0.3.0-SNAPSHOT</version>
-  <name>${project.artifactId}</name>
-  <packaging>pom</packaging>
+and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>netvirt</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name> <!-- Used by Sonar to set project name -->
+  <packaging>pom</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
   <prerequisites>
     <maven>3.1.1</maven>
   </prerequisites>
+
   <modules>
-    <module>commons/binding-parent</module>
-    <module>commons/config-parent</module>
-    <module>model-bgp</module>
-    <module>mdsalutil</module>
-    <module>lockmanager</module>
-    <module>idmanager</module>
-    <module>arputil</module>
-    <module>vpnmanager</module>
-    <module>interfacemgr</module>
-    <module>alivenessmonitor</module>
-    <module>elanmanager</module>
-    <module>fibmanager</module>
-    <module>bgpmanager</module>
-    <module>neutronvpn</module>
-    <module>dhcpservice</module>
-    <module>itm</module>
-    <module>natservice</module>
-    <module>distribution/karaf</module>
+    <module>commons</module>
     <module>features</module>
-    <module>vpnservice-artifacts</module>
-    <module>vpnintent</module>
-    <module>fcapsmanager</module>
-    <module>fcapsapplication</module>
+    <module>karaf</module>
+    <module>netvirt</module>
+    <module>openstack</module>
+    <module>netvirt-artifacts</module>
+    <module>ovsdb-ui</module>
+    <module>utils</module>
   </modules>
 
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
@@ -59,10 +79,4 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       </plugin>
     </plugins>
   </build>
-  <scm>
-    <connection>scm:git:ssh://git.opendaylight.org:29418/vpnservice.git</connection>
-    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/vpnservice.git</developerConnection>
-    <url>https://wiki.opendaylight.org/view/VPNService:Main</url>
-    <tag>HEAD</tag>
-  </scm>
 </project>
\ No newline at end of file
diff --git a/resources/README b/resources/README
new file mode 100644 (file)
index 0000000..93db5e6
--- /dev/null
@@ -0,0 +1,6 @@
+
+The resources/ directory contains all the associated scripts and configuration files that can be used by 
+developers and administrators under various use-cases.
+
+It is subdivided into multiple directories addressing each of the deployment scenarios.
+Each of these sub-directories contains its own README.
diff --git a/resources/commons/3-Node-Cluster-Setup-Environment-Variables.postman_environment b/resources/commons/3-Node-Cluster-Setup-Environment-Variables.postman_environment
new file mode 100644 (file)
index 0000000..dc824a0
--- /dev/null
@@ -0,0 +1,58 @@
+{
+       "id": "61b7453f-15f4-39e5-8470-980d0805f9fb",
+       "name": "3 Node Cluster Setup Environment Variables",
+       "values": [
+               {
+                       "key": "NODE-1-IP",
+                       "value": "192.168.201.2",
+                       "type": "text",
+                       "name": "NODE-1-IP",
+                       "enabled": true
+               },
+               {
+                       "key": "NODE-2-IP",
+                       "value": "192.168.201.3",
+                       "type": "text",
+                       "name": "NODE-2-IP",
+                       "enabled": true
+               },
+               {
+                       "key": "NODE-3-IP",
+                       "value": "192.168.201.4",
+                       "type": "text",
+                       "name": "NODE-3-IP",
+                       "enabled": true
+               },
+               {
+                       "key": "HYPERVISOR-IP",
+                       "value": "192.168.201.128",
+                       "type": "text",
+                       "name": "HYPERVISOR-IP",
+                       "enabled": true
+               },
+               {
+                       "key": "HYPERVISOR-OVSDB-PORT",
+                       "value": "16640",
+                       "type": "text",
+                       "name": "HYPERVISOR-OVSDB-PORT",
+                       "enabled": true
+               },
+               {
+                       "key": "JOLOKIA-NODE-IP",
+                       "value": "192.168.201.2",
+                       "type": "text",
+                       "name": "JOLOKIA-NODE-IP",
+                       "enabled": true
+               },
+               {
+                       "key": "HYPERVISOR-NODE-ID",
+                       "value": "192.168.201.128:16640",
+                       "type": "text",
+                       "name": "HYPERVISOR-NODE-ID",
+                       "enabled": true
+               }
+       ],
+       "timestamp": 1443834815417,
+       "synced": false,
+       "syncedFilename": ""
+}
\ No newline at end of file
diff --git a/resources/commons/L2Gateway.json.postman_collection b/resources/commons/L2Gateway.json.postman_collection
new file mode 100644 (file)
index 0000000..0217f8a
--- /dev/null
@@ -0,0 +1,455 @@
+{
+       "id": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+       "name": "L2 Gateway",
+       "description": "",
+       "order": [],
+       "folders": [
+               {
+                       "id": "c7e3f572-cbc4-93cb-6050-b97b67850e31",
+                       "name": "L2 Gateway",
+                       "description": "",
+                       "order": [
+                               "fba3ec18-97b5-6a84-0b8f-8a41ca1bd075",
+                               "d1522560-e286-4c16-635d-239d935ffcbe",
+                               "9e399879-8048-7435-b3af-a6e715f246c3",
+                               "d8b975eb-8fb6-9ec9-8abb-b73322410b7d",
+                               "d56f7137-9ea3-136f-c237-ee9a583c1bb6"
+                       ],
+                       "owner": 0,
+                       "collectionId": "8ed3570d-1ce1-06a1-e720-1192b852a411"
+               },
+               {
+                       "id": "5733d57d-90b7-6926-12ce-709b81ac492f",
+                       "name": "L2 Gateway Connection",
+                       "description": "",
+                       "order": [
+                               "1f37f9a9-c644-83e0-ea01-c0ea9234ac13",
+                               "9cbb9282-f4fd-d8dc-107a-a12a8c5119b7",
+                               "9a6da9e9-8fb9-4d5e-821d-2b12da2af9dd"
+                       ],
+                       "owner": 0
+               },
+               {
+                       "id": "d2c53196-d8f7-ccef-48d4-b5999c943fe0",
+                       "name": "Neutron",
+                       "description": "",
+                       "order": [
+                               "5fff0085-3e2b-d8d9-f706-7f24e907258f",
+                               "9c323185-f2f9-1c5d-c6e3-aa42a1d40302",
+                               "c12b0610-73d2-9529-e2d8-21771e6f5a87",
+                               "5568645c-4629-74f0-622b-d5211a62ccbf",
+                               "c8e5c92e-c0f5-f7b4-b121-bb7021d49a30",
+                               "d03c715b-c817-cf9c-6c82-2a21b3b3d59c",
+                               "6925af47-8f78-57b4-ed09-1691dc8e6441",
+                               "1dc716ce-bd83-a6fd-046c-e6b7e34a519c",
+                               "fbfd7afd-05c9-937a-4e18-25f37a2cb99f",
+                               "761e694c-c493-92cb-039a-e7a278b369de",
+                               "314e62ca-26a2-2e91-9d0e-c118e4288b13"
+                       ],
+                       "owner": 0,
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93"
+               }
+       ],
+       "timestamp": 1453438450886,
+       "owner": 0,
+       "remoteLink": "",
+       "public": false,
+       "requests": [
+               {
+                       "id": "1dc716ce-bd83-a6fd-046c-e6b7e34a519c",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/ports",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1456928762606,
+                       "name": "Neutron Port Create - 2",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \"port\": \r\n    {\r\n        \"mac_address\": \"00:00:00:00:00:02\",\r\n        \"name\": \"tap23701c04-76\",\r\n        \"network_id\": \"9227c228-6bba-4bbe-bdb8-6942768ff0f1\",\r\n        \"id\": \"23701c04-7668-4c65-9425-78a80d49a219\",\r\n        \"tenant_id\": \"de0a7495-05c4-4be0-b796-1412835c6820\",\r\n        \"admin_state_up\": \"true\",\r\n        \"device_id\": \"\",\r\n        \"device_owner\": \"test\", \r\n        \"fixed_ips\": \r\n        [\r\n            {\r\n                \"subnet_id\": \"9b09f1a7-250f-4562-8093-e6018aeceaf6\",\r\n                \"ip_address\": \"10.0.0.2\"\r\n            } \r\n        ]\r\n     }\r\n}",
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "1f37f9a9-c644-83e0-ea01-c0ea9234ac13",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2gateway-connections",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1454644623496,
+                       "name": "L2GW Connection Create",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \"l2gateway_connection\": \r\n    {\r\n        \"tenant_id\":\"de0a7495-05c4-4be0-b796-1412835c6820\",\r\n        \"id\":\"5227c228-6bba-4bbe-bdb8-6942768ff0e1\",\r\n        \"port_id\": \"9ea656c7c9b8447494f33b0bc741d9a9\",\r\n        \"network_id\": \"9227c228-6bba-4bbe-bdb8-6942768ff0f1\",\r\n        \"default_segmentation_id\": 100,\r\n        \"gateway_id\": \"5227c228-6bba-4bbe-bdb8-6942768ff0f1\"\r\n    }\r\n}",
+                       "folder": "5733d57d-90b7-6926-12ce-709b81ac492f"
+               },
+               {
+                       "id": "314e62ca-26a2-2e91-9d0e-c118e4288b13",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/ports/23701c04-7668-4c65-9425-78a80d49a219",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "DELETE",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "data": [],
+                       "dataMode": "raw",
+                       "name": "Neutron Port Delete - 2",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1453441723388,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0",
+                       "rawModeData": "{\n    \"port\": {\n        \"admin_state_up\": true,\n        \"device_id\": \"d6b4d3a5-c700-476f-b609-1493dd9dadc0\",\n        \"name\": \"port2\",\n        \"network_id\": \"2775510e-4c75-4f94-92bf-6743a43c7002\",\n        \"tenant_id\":\"38470401580249029f5b811e841e16a4\",\n        \"mac_address\": \"fa:16:3e:70:d2:8c\"\n        \n    }\n}"
+               },
+               {
+                       "id": "5568645c-4629-74f0-622b-d5211a62ccbf",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/subnets",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1456487331767,
+                       "name": "Neutron Subnet Create",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{ \r\n    \"subnet\" :\r\n    {\r\n        \"enable_dhcp\": \"false\",\r\n        \"name\": \"Substring\",\r\n        \"network_id\": \"9227c228-6bba-4bbe-bdb8-6942768ff0f1\",\r\n        \"id\": \"9b09f1a7-250f-4562-8093-e6018aeceaf6\",\r\n        \"tenant_id\": \"de0a7495-05c4-4be0-b796-1412835c6820\",\r\n        \"ip_version\": 4,\r\n        \"cidr\": \"10.0.0.0/24\"\r\n    }\r\n}",
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "5fff0085-3e2b-d8d9-f706-7f24e907258f",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/networks",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1455768028805,
+                       "name": "Neutron Network Create",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{  \n   \"network\":{  \n      \"status\":\"ACTIVE\",\n      \"subnets\":[  \n          \"9b09f1a7-250f-4562-8093-e6018aeceaf6\"\n      ],\n      \"name\":\"net1\",\n      \"router:external\":false,\n      \"tenant_id\":\"de0a7495-05c4-4be0-b796-1412835c6820\",\n      \"admin_state_up\":true,\n      \"shared\":false,\n      \"id\":\"9227c228-6bba-4bbe-bdb8-6942768ff0f1\",\n      \"provider:segmentation_id\": \"100\",\n      \"provider:physical_network\": \"8bab8453-1bc9-45af-8c70-f83aa9b50450\",\n      \"provider:network_type\": \"vxlan\"\n   }\n}",
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "6925af47-8f78-57b4-ed09-1691dc8e6441",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/ports",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1456928750206,
+                       "name": "Neutron Port Create - 1",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \"port\": \r\n     {\r\n        \"mac_address\": \"00:00:00:00:00:01\",\r\n        \"name\": \"tap23701c04-75\",\r\n        \"network_id\": \"9227c228-6bba-4bbe-bdb8-6942768ff0f1\",\r\n        \"id\": \"23701c04-7558-4c65-9425-78a80d49a218\",\r\n        \"tenant_id\": \"de0a7495-05c4-4be0-b796-1412835c6820\",\r\n        \"admin_state_up\": \"true\",\r\n        \"device_id\": \"\",\r\n        \"device_owner\": \"test\", \r\n        \"fixed_ips\": \r\n        [\r\n            {\r\n                \"subnet_id\": \"9b09f1a7-250f-4562-8093-e6018aeceaf6\",\r\n                \"ip_address\": \"10.0.0.1\"\r\n            } \r\n        ]\r\n     }\r\n}",
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "761e694c-c493-92cb-039a-e7a278b369de",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/ports/23701c04-7558-4c65-9425-78a80d49a218",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "DELETE",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "data": [],
+                       "dataMode": "raw",
+                       "name": "Neutron Port Delete - 1",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1453441716290,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0",
+                       "rawModeData": "{\n    \"port\": {\n        \"admin_state_up\": true,\n        \"device_id\": \"d6b4d3a5-c700-476f-b609-1493dd9dadc0\",\n        \"name\": \"port1\",\n        \"network_id\": \"2775510e-4c75-4f94-92bf-6743a43c7002\",\n        \"tenant_id\":\"38470401580249029f5b811e841e16a4\",\n        \"mac_address\": \"fa:16:3e:70:d2:8c\"\n        \n    }\n}"
+               },
+               {
+                       "id": "9a6da9e9-8fb9-4d5e-821d-2b12da2af9dd",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2gateway-connections/5227c228-6bba-4bbe-bdb8-6942768ff0e1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1453446976189,
+                       "name": "L2GW Connection Delete",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "folder": "5733d57d-90b7-6926-12ce-709b81ac492f"
+               },
+               {
+                       "id": "9c323185-f2f9-1c5d-c6e3-aa42a1d40302",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/networks",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Neutron Network Get",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1453441666005,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "9cbb9282-f4fd-d8dc-107a-a12a8c5119b7",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2gateway-connections",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1453446923466,
+                       "name": "L2GW Connection Get",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "folder": "5733d57d-90b7-6926-12ce-709b81ac492f"
+               },
+               {
+                       "id": "9e399879-8048-7435-b3af-a6e715f246c3",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2-gateways",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1453440994169,
+                       "name": "L2GWs Get",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "folder": "c7e3f572-cbc4-93cb-6050-b97b67850e31"
+               },
+               {
+                       "id": "c12b0610-73d2-9529-e2d8-21771e6f5a87",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/networks/9227c228-6bba-4bbe-bdb8-6942768ff0f1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1453441856431,
+                       "name": "Neutron Network Delete",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{  \n   \"network\":{  \n      \"status\":\"ACTIVE\",\n      \"subnets\":[  \n\n      ],\n      \"name\":\"net1\",\n      \"router:external\":false,\n      \"tenant_id\":\"38470401580249029f5b811e841e16a4\",\n      \"admin_state_up\":true,\n      \"mtu\":0,\n      \"shared\":false,\n      \"id\":\"2775510e-4c75-4f94-92bf-6743a43c7002\"\n   }\n}",
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "c8e5c92e-c0f5-f7b4-b121-bb7021d49a30",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/subnets",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Neutron Subnet Get",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1453441742471,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "d03c715b-c817-cf9c-6c82-2a21b3b3d59c",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/subnets/9b09f1a7-250f-4562-8093-e6018aeceaf6",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "DELETE",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Neutron Subnet Delete",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1453441748540,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               },
+               {
+                       "id": "d1522560-e286-4c16-635d-239d935ffcbe",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2-gateways",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1456120958967,
+                       "name": "L2GW Create - 2",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \"l2_gateway\": \r\n    {\r\n        \"tenant_id\":\"de0a7495-05c4-4be0-b796-1412835c6820\",\r\n        \"id\":\"5227c228-6bba-4bbe-bdb8-6942768ff0f2\",\r\n        \"name\": \"<gateway-name>\",\r\n        \"devices\": \r\n        [\r\n            {\r\n                \"device_name\": \"s2\",\r\n                \"interfaces\": \r\n                [\r\n                    {\r\n                        \"name\":\"s2-eth1\",\r\n                        \"segmentation_id\":103\r\n                    },\r\n                    {\r\n                        \"name\":\"s2-eth1\",\r\n                        \"segmentation_id\":[154,155]\r\n                        \r\n                    }\r\n                ]\r\n            }\r\n        ]\r\n    }\r\n}",
+                       "folder": "c7e3f572-cbc4-93cb-6050-b97b67850e31"
+               },
+               {
+                       "id": "d56f7137-9ea3-136f-c237-ee9a583c1bb6",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2-gateways/5227c228-6bba-4bbe-bdb8-6942768ff0f2",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1453873711216,
+                       "name": "L2GW Delete - 2",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "folder": "c7e3f572-cbc4-93cb-6050-b97b67850e31"
+               },
+               {
+                       "id": "d8b975eb-8fb6-9ec9-8abb-b73322410b7d",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2-gateways/5227c228-6bba-4bbe-bdb8-6942768ff0f1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1453441271022,
+                       "name": "L2GW Delete - 1",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "folder": "c7e3f572-cbc4-93cb-6050-b97b67850e31"
+               },
+               {
+                       "id": "fba3ec18-97b5-6a84-0b8f-8a41ca1bd075",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/l2-gateways",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1456487197833,
+                       "name": "L2GW Create - 1",
+                       "description": "",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \"l2_gateway\": \r\n    {\r\n        \"tenant_id\":\"de0a7495-05c4-4be0-b796-1412835c6820\",\r\n        \"id\":\"5227c228-6bba-4bbe-bdb8-6942768ff0f1\",\r\n        \"name\": \"<gateway-name>\",\r\n        \"devices\": \r\n        [\r\n            {\r\n                \"device_name\": \"s2\",\r\n                \"interfaces\": \r\n                [\r\n                    {\r\n                        \"name\":\"s2-eth1\",\r\n                        \"segmentation_id\":0\r\n                    },\r\n                    {\r\n                        \"name\":\"s2-eth1\",\r\n                        \"segmentation_id\":[0,152]\r\n                        \r\n                    }\r\n                ]\r\n            },\r\n            {\r\n                \"device_name\": \"s2\",\r\n                \"interfaces\": \r\n                [\r\n                    {\r\n                        \"name\":\"s2-eth1\",\r\n                        \"segmentation_id\":101\r\n                    },\r\n                    {\r\n                        \"name\":\"s2-eth1\",\r\n                        \"segmentation_id\":[153]\r\n                        \r\n                    }\r\n                ]\r\n            }            \r\n        ]\r\n    }\r\n}",
+                       "folder": "c7e3f572-cbc4-93cb-6050-b97b67850e31"
+               },
+               {
+                       "id": "fbfd7afd-05c9-937a-4e18-25f37a2cb99f",
+                       "headers": "Content-Type: application/json\nCache-Control: no-cache\nAccept: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://localhost:8080/controller/nb/v2/neutron/ports",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "collectionId": "a0aa0801-64e9-6ac6-63bf-113a98143e93",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Neutron Ports Get",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1453441707144,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "d2c53196-d8f7-ccef-48d4-b5999c943fe0"
+               }
+       ]
+}
\ No newline at end of file
diff --git a/resources/commons/Mininet_Demo_OVSDB_OF.json.postman_collection b/resources/commons/Mininet_Demo_OVSDB_OF.json.postman_collection
new file mode 100644 (file)
index 0000000..8067a15
--- /dev/null
@@ -0,0 +1 @@
+{"id":"434c1a79-a99d-2159-7559-95cb9dce794e","name":"Mininet Demo : OVSDB + OF","description":"This POSTMAN script was used for the Mininet demonstration : http://www.youtube.com/watch?v=8iWhMVlflwE","order":["60dc9930-7948-b34e-ecfe-7ab7130f6037","da8d3367-47f7-8217-57cf-bc921ebda497","9143419b-af64-4647-905c-831461ead25d","ed66771a-dc23-a958-440f-0bc3792ecf1c","462c7d0a-e885-8a21-7a0e-ea4f6086d621","f1f89972-61f9-e39c-f572-d6470d201b0e","61ae4830-c124-84f0-92f2-05b46809cfb1","bb05ca74-5c47-ca39-e058-9a5b900db749","3c4fd25b-6c2c-0dcf-695f-c27a0d78632b","6dec1ff1-4bae-0566-70ec-ed17ae3905f3","360de20d-5b76-2b34-e436-4199ccb3b0fb","e84507bc-e7f0-efce-02d1-74ea28fb32de","54ccad58-669b-9889-c6ed-af328c59c947","4a332eca-b7b7-6d7a-8029-33d7da714698"],"folders":[],"timestamp":1383819127794,"synced":false,"requests":[{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"360de20d-5b76-2b34-e436-4199ccb3b0fb","name":"Delete s1-eth2","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/s1/s1-eth2","method":"DELETE","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"3c4fd25b-6c2c-0dcf-695f-c27a0d78632b","name":"Add a port - br2-veth1 (with patch to br1-veth1) to br2","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/br2/br2-veth1","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"br1-veth1\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"462c7d0a-e885-8a21-7a0e-ea4f6086d621","name":"Create a Bridge : br1","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/bridge/OVS/HOST1/br1","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"4a332eca-b7b7-6d7a-8029-33d7da714698","name":"s2-eth3 -> br2-eth3","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/s2/s2-veth3","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"br2-veth3\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"54ccad58-669b-9889-c6ed-af328c59c947","name":"Delete s2-eth2","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/s2/s2-eth2","method":"DELETE","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"60dc9930-7948-b34e-ecfe-7ab7130f6037","name":"Delete Bridge br1","description":"Delete Bridge br1","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/bridge/OVS/HOST1/br1","method":"DELETE","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"61ae4830-c124-84f0-92f2-05b46809cfb1","name":"Add a port - br1-veth1 (with patch to br2-veth1) to br1","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/br1/br1-veth1","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"br2-veth1\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"6dec1ff1-4bae-0566-70ec-ed17ae3905f3","name":"br2-eth3 -> s2-eth3","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/br2/br2-veth3","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"s2-veth3\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"9143419b-af64-4647-905c-831461ead25d","name":"Connect to the OVSDB-SERVER","description":"Connect to the OVSDB-SERVER","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/connectionmanager/node/HOST1/address/192.168.56.101/port/6640/","method":"PUT","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\n","data":[],"dataMode":"params","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"bb05ca74-5c47-ca39-e058-9a5b900db749","name":"br1-eth3 -> s1-eth3","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/br1/br1-veth3","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"s1-veth3\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"da8d3367-47f7-8217-57cf-bc921ebda497","name":"Delete Bridge br2","description":"Delete Bridge br2","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/bridge/OVS/HOST1/br2","method":"DELETE","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"e84507bc-e7f0-efce-02d1-74ea28fb32de","name":"s1-eth3 -> br1-eth3","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/port/OVS/HOST1/s1/s1-veth3","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"br1-veth3\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"ed66771a-dc23-a958-440f-0bc3792ecf1c","name":"Get all existing connections","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/connectionmanager/nodes","method":"GET","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{\"type\":\"patch\", \"CUSTOM\":{\"peer\":\"br1-veth1\"}}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"434c1a79-a99d-2159-7559-95cb9dce794e","id":"f1f89972-61f9-e39c-f572-d6470d201b0e","name":"Create another bridge : br2","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/networkconfig/bridgedomain/bridge/OVS/HOST1/br2","method":"POST","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n","data":"{}","dataMode":"raw","timestamp":0,"responses":[],"version":2,"synced":false}]}
\ No newline at end of file
diff --git a/resources/commons/NetvirtSfc.json.postman_collection b/resources/commons/NetvirtSfc.json.postman_collection
new file mode 100644 (file)
index 0000000..f73f0cb
--- /dev/null
@@ -0,0 +1,189 @@
+{
+    "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
new file mode 100644 (file)
index 0000000..25b967a
--- /dev/null
@@ -0,0 +1,449 @@
+{
+    "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/Neutron-v2.0-LBaaS-API-Examples_July15.json.postman_collection.txt b/resources/commons/Neutron-v2.0-LBaaS-API-Examples_July15.json.postman_collection.txt
new file mode 100644 (file)
index 0000000..ae623ab
--- /dev/null
@@ -0,0 +1,247 @@
+{
+       "id": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+       "name": "Neutron-v2.0-LBaaS-API-Examples",
+       "description": "A collection of OpenStack Neutron v2.0 REST API calls for Postman. Import these into Postman and use to validate the OpenDaylight Neutron NB-API interfaces.\n\nResources:\n- Postman http://www.getpostman.com\n- Neutron v2.0 https://wiki.openstack.org/wiki/Neutron/APIv2-specification",
+       "order": [
+               "80b2233e-3c0c-1eda-ee31-c78abad32f8f",
+               "e9e80a59-0898-4429-81fb-8e9a85eec77f",
+               "976a426e-c8ec-efae-c80a-f23cb4d0d404",
+               "a6a09c93-a701-3381-9560-7d6b4f12083d",
+               "647ecd26-a5f9-9f6e-c2ed-bbb2881c57ab",
+               "261535f5-37c0-8358-8f26-0a76ea169c54",
+               "e5230742-6966-2fd3-5ba9-a5c6784b5fd5",
+               "92ecc186-f3ff-c6cf-4a12-f66e0ba41c44",
+               "4df70c66-4d47-a1eb-ea3c-3a53021b59a6",
+               "e489ca9e-82c3-b988-0c69-3e29ef08f689",
+               "8c9eba41-f49d-3cb3-4a36-b7e743ac4e80",
+               "c06c3e2e-80b4-9673-3ad2-dba02eee7ab0",
+               "37c50edc-99e0-6256-ef49-e26bcdce00ce"
+       ],
+       "folders": [],
+       "timestamp": 1394529177458,
+       "owner": "79838",
+       "remoteLink": "",
+       "public": false,
+       "requests": [
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "261535f5-37c0-8358-8f26-0a76ea169c54",
+                       "name": "Get Neutron Load Balancer  Pool",
+                       "description": "Return a Neutron v2.0  Load Balancer Pool.",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/pools/",
+                       "method": "GET",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436369062511,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": ""
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "37c50edc-99e0-6256-ef49-e26bcdce00ce",
+                       "name": "Delete Neutron Load Balancer Pool Member",
+                       "description": "",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/pools/332abe93-f488-41ba-870b-2ac66be7f853/members/a183a8b3-bddb-dc04-ae73-3beb11af4d06",
+                       "method": "DELETE",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436380297165,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": ""
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "4df70c66-4d47-a1eb-ea3c-3a53021b59a6",
+                       "name": "Post Add Neutron Load Balancer",
+                       "description": "Example posting of a Neutron v2.0  Load Balancer (LBaaS).",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/loadbalancers/",
+                       "method": "POST",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436380013197,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n  \"loadbalancer\": {\n    \"id\": \"8992a43f-83af-4b49-9afd-c2bfbd82d7d7\",\n    \"name\": \"Example LB\",\n    \"description\": \"A very simple example load balancer.\",\n    \"vip_address\": \"10.0.0.5\",\n    \"vip_subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n    \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n    \"status\": \"PENDING_CREATE\"\n  }\n}"
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "647ecd26-a5f9-9f6e-c2ed-bbb2881c57ab",
+                       "name": "Post Add Neutron Load Balancer Pool",
+                       "description": "Example posting of a Neutron v2.0  Load Balancer Pool.",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/pools/",
+                       "method": "POST",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436380885465,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n    \"pool\": {\n        \"id\": \"332abe93-f488-41ba-870b-2ac66be7f853\",\n        \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n        \"name\": \"Example pool\",\n        \"description\": \"\",\n        \"protocol\": \"http\",\n        \"lb_algorithm\": \"ROUND_ROBIN\",\n        \"session_persistence\": {},\n        \"healthmonitor_id\": null,\n        \"members\": [\n            {\n                \"id\": \"a183a8b3-bddb-dc04-ae73-3beb11af4d04\",\n                \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n                \"address\": \"10.0.0.7\",\n                \"protocol_port\": 80,\n                \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n                \"admin_state_up\": true\n            }\n        ],\n        \"admin_state_up\": true,\n        \"status\": \"ACTIVE\"\n    }\n}"
+               },
+               {
+                       "id": "80b2233e-3c0c-1eda-ee31-c78abad32f8f",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/networks/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Post Add Neutron Network",
+                       "description": "",
+                       "descriptionFormat": "html",
+                       "time": 1436388271366,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {}
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "8c9eba41-f49d-3cb3-4a36-b7e743ac4e80",
+                       "name": "Post Add LoadBalancer Pool Member",
+                       "description": "",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/pools/332abe93-f488-41ba-870b-2ac66be7f853/members/",
+                       "method": "PUT",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436379833081,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n    \"member\": {\n        \"id\": \"a183a8b3-bddb-dc04-ae73-3beb11af4d06\",\n        \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n        \"address\": \"10.0.0.1\",\n        \"protocol_port\": 80,\n        \"subnet_id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\",\n        \"admin_state_up\": true,\n        \"weight\": 1,\n        \"status\": \"UP\"\n    }\n}"
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "92ecc186-f3ff-c6cf-4a12-f66e0ba41c44",
+                       "name": "Get Neutron Load Balancers",
+                       "description": "Return a Neutron v2.0  Load Balancer (LBaaS).",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/loadbalancers/",
+                       "method": "GET",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436369027509,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n  \"pool\": {\n    \"id\": \"332abe93-f488-41ba-870b-2ac66be7f853\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"name\": \"Example pool\",\n    \"description\": \"\",\n    \"protocol\": \"http\",\n    \"lb_algorithm\": \"ROUND_ROBIN\",\n    \"session_persistence\": {\n    },\n    \"healthmonitor_id\": null,\n    \"members\": [{\n      \"id\": \"a183a8b3-bddb-dc04-ae73-3beb11af4d04\",\n \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n \"address\": \"10.0.0.7\",\n \"protocol_port\":80,\n \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n      \"admin_state_up\": true\n }],\n    \"admin_state_up\": true,\n    \"status\": \"ACTIVE\"\n  }\n}"
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "976a426e-c8ec-efae-c80a-f23cb4d0d404",
+                       "name": "Post Add Neutron Network Port",
+                       "description": "Post a list of Neutron v2.0 Port",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+                       "method": "POST",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n  \"port\": {\n    \"status\": \"UP\",\n    \"binding:host_id\": \"\",\n    \"name\": \"private-port\",\n    \"allowed_address_pairs\": [\n    ],\n    \"admin_state_up\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"binding:vif_details\": {\n    },\n    \"binding:vnic_type\": \"normal\",\n    \"binding:vif_type\": \"unbound\",\n    \"device_owner\": \"\",\n    \"mac_address\": \"fa:16:3e:c9:cb:f0\",\n    \"binding:profile\": {\n    },\n    \"fixed_ips\": [\n      {\n        \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n        \"ip_address\": \"10.0.0.7\"\n      }\n    ],\n    \"id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\",\n    \"security_groups\": [\n      \"f0ac4394-7e4a-4409-9701-ba8be283dbc3\"\n    ],\n    \"device_id\": \"\"\n  }\n}"
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "a6a09c93-a701-3381-9560-7d6b4f12083d",
+                       "name": "Post Add Neutron Network Port 2",
+                       "description": "",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+                       "method": "POST",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n  \"port\": {\n    \"status\": \"UP\",\n    \"binding:host_id\": \"\",\n    \"name\": \"private-port\",\n    \"allowed_address_pairs\": [\n    ],\n    \"admin_state_up\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"binding:vif_details\": {\n    },\n    \"binding:vnic_type\": \"normal\",\n    \"binding:vif_type\": \"unbound\",\n    \"device_owner\": \"\",\n    \"mac_address\": \"fa:16:3e:c9:cb:f4\",\n    \"binding:profile\": {\n    },\n    \"fixed_ips\": [\n      {\n        \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n        \"ip_address\": \"10.0.0.8\"\n      }\n    ],\n    \"id\": \"65c0ee9f-d634-4522-8954-51021b570b0e\",\n    \"security_groups\": [\n      \"f0ac4394-7e4a-4409-9701-ba8be283dbc3\"\n    ],\n    \"device_id\": \"\"\n  }\n}"
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "c06c3e2e-80b4-9673-3ad2-dba02eee7ab0",
+                       "name": "Get Neutron Load Balancer Pool Members",
+                       "description": "Return Neutron v2.0  Load Balancer (LBaaS). pool members",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/pools/332abe93-f488-41ba-870b-2ac66be7f853/members",
+                       "method": "GET",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436369134571,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n  \"member\": {\n      \"id\": \"a183a8b3-bddb-dc04-ae73-3beb11af4d05\",\n \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n \"address\": \"10.0.0.8\",\n \"protocol_port\":80,\n \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n      \"admin_state_up\": true,\n    \"weight\": 1,\n    \"status\": \"UP\"\n }\n}"
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "e489ca9e-82c3-b988-0c69-3e29ef08f689",
+                       "name": "Delete Neutron Load Balancer",
+                       "description": "",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/loadbalancers/8992a43f-83af-4b49-9afd-c2bfbd82d7d7",
+                       "method": "DELETE",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "params",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436378718919,
+                       "preRequestScript": "",
+                       "tests": ""
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "e5230742-6966-2fd3-5ba9-a5c6784b5fd5",
+                       "name": "Delete Neutron Load Balancer Pool",
+                       "description": "",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/lbaas/pools/332abe93-f488-41ba-870b-2ac66be7f853",
+                       "method": "DELETE",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1436376334648,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": ""
+               },
+               {
+                       "collectionId": "1ad8d425-4d48-1f4d-9659-f8dab30861e6",
+                       "id": "e9e80a59-0898-4429-81fb-8e9a85eec77f",
+                       "name": "Post Add Neutron Subnet",
+                       "description": "",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+                       "method": "POST",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": [],
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "preRequestScript": "",
+                       "tests": "",
+                       "rawModeData": "{\n  \"subnet\": {\n    \"name\": \"\",\n    \"enable_dhcp\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"dns_nameservers\": [\n    ],\n    \"allocation_pools\": [\n      {\n        \"start\": \"10.0.0.2\",\n        \"end\": \"10.0.0.254\"\n      }\n    ],\n    \"host_routes\": [\n    ],\n    \"ip_version\": 4,\n    \"gateway_ip\": \"10.0.0.1\",\n    \"cidr\": \"10.0.0.0/24\",\n    \"id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\"\n  }\n}"
+               }
+       ]
+}
\ No newline at end of file
diff --git a/resources/commons/ODL-Clustering.json.postman_collection b/resources/commons/ODL-Clustering.json.postman_collection
new file mode 100644 (file)
index 0000000..f25bdc7
--- /dev/null
@@ -0,0 +1,74 @@
+{
+       "id": "429efdb8-6763-c457-43d3-0cae196dbe53",
+       "name": "ODL Clustering",
+       "description": "This collection contains request that fetch data related to clustering services, to check if cluster is up and running and topology/inventory shard related details.\n\nThis collection usage postman variables and it's defined in `3 Node Cluster Setup Environment Variables' file.",
+       "order": [
+               "95f3ebe4-dd38-9ef5-8822-f657c8d5cd4b",
+               "3d8fb5eb-7de9-022a-8cb0-943826c468ff",
+               "7fb9aad2-f55f-97d0-5ee1-74724f161f7d"
+       ],
+       "folders": [],
+       "timestamp": 0,
+       "owner": "128022",
+       "remoteLink": "https://www.getpostman.com/collections/d1e5b3ce64a3d58710ec",
+       "public": false,
+       "requests": [
+               {
+                       "folder": null,
+                       "id": "3d8fb5eb-7de9-022a-8cb0-943826c468ff",
+                       "name": "Inventory Shard Details",
+                       "dataMode": "params",
+                       "data": [],
+                       "rawModeData": null,
+                       "descriptionFormat": "html",
+                       "description": "This restconf request will fetch data about `Inventory Shard` from the clustering service.\nUser should direct this request to the controller where jolokia agent is installed.\n\nJOLOKIA-NODE-IP is defined in `3 Node Cluster Setup Environment Variables` file.",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "method": "GET",
+                       "pathVariables": {},
+                       "url": "http://{{JOLOKIA-NODE-IP}}:8181/jolokia/read/org.opendaylight.controller:Category=Shards,name=member-1-shard-inventory-config,type=DistributedConfigDatastore",
+                       "preRequestScript": "",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "collectionId": "429efdb8-6763-c457-43d3-0cae196dbe53"
+               },
+               {
+                       "folder": null,
+                       "id": "7fb9aad2-f55f-97d0-5ee1-74724f161f7d",
+                       "name": "Topology Shard Details",
+                       "dataMode": "params",
+                       "data": [],
+                       "rawModeData": null,
+                       "descriptionFormat": "html",
+                       "description": "This restconf request will fetch data about `Topology Shard` from the clustering service.\nUser should direct this request to the controller where jolokia agent is installed.\n\nJOLOKIA-NODE-IP is defined in `3 Node Cluster Setup Environment Variables` file.",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "method": "GET",
+                       "pathVariables": {},
+                       "url": "http://{{JOLOKIA-NODE-IP}}:8181/jolokia/read/org.opendaylight.controller:Category=Shards,name=member-1-shard-topology-config,type=DistributedConfigDatastore",
+                       "preRequestScript": "",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "collectionId": "429efdb8-6763-c457-43d3-0cae196dbe53"
+               },
+               {
+                       "folder": null,
+                       "id": "95f3ebe4-dd38-9ef5-8822-f657c8d5cd4b",
+                       "name": "Cluster details",
+                       "dataMode": "params",
+                       "data": [],
+                       "rawModeData": null,
+                       "descriptionFormat": "html",
+                       "description": "Fetch clustering related data and look for following details to make sure that cluster is up and running.\nMembers field should list all the cluster nodes added to the cluster.\nAlso the Unreachable fields should be empty.\nJOLOKIA-NODE-IP is defined in `3 Node Cluster Setup Environment Variables` file.\n",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "method": "GET",
+                       "pathVariables": {},
+                       "url": "http://{{JOLOKIA-NODE-IP}}:8181/jolokia/read/akka:type=Cluster",
+                       "preRequestScript": "",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "collectionId": "429efdb8-6763-c457-43d3-0cae196dbe53"
+               }
+       ]
+}
\ No newline at end of file
diff --git a/resources/commons/Ovsdb-HwvtepSouthbound-Collection.json.postman_collection b/resources/commons/Ovsdb-HwvtepSouthbound-Collection.json.postman_collection
new file mode 100755 (executable)
index 0000000..d72f240
--- /dev/null
@@ -0,0 +1,828 @@
+{
+    "id":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+    "name":"Ovsdb HwvtepSouthbound",
+    "timestamp":1424977469540,
+    "order":[
+        "e9ff6957-4dc2-9257-c0c6-21560bfd5de2",
+        "ee151670-85a0-30ec-b22b-5defe7b66e0b",
+        "6de1ede7-817c-ccbb-3df9-ef510bdaf583",
+        "6e7c88e4-485d-ab9f-4c3a-cc235e022905",
+        "92ee7422-5b08-6d63-2b95-961ec0e18ffa",
+        "e92ac963-daaf-0899-c3e8-a00d897be0e2",
+        "88789ac9-9de9-bab3-565b-307774e49f4d",
+        "e25f67e4-3a3f-5da7-f7c8-41b371156719",
+        "f7d33d50-7c8e-69e2-6d60-5c6155c5d210",
+        "233b5ab5-8177-4416-6912-2477520a0654",
+        "567d7827-628d-07a4-3b95-5a208a244c43",
+        "f906c48b-ba3c-a3da-36e8-34c453538e2e",
+        "5d0c4d49-44f7-4165-ca5f-00cf2a9fca8b",
+        "34167a78-7de4-91a9-ef40-7592b28ead5c",
+        "9bc22ca7-049c-af51-7c12-6bf71044b2ec",
+        "f6d300f7-380a-d090-0d4a-2b2ddefe5104",
+        "f9f71d74-a49d-b190-d929-b6772ce0ba73",
+        "18032e93-3bc5-9976-4525-fe1e77e98207",
+        "6f6addb7-6d48-e1ef-8cc2-c5841d71c2e5",
+        "20e8b57b-a5e7-a52f-01d6-7b66ea551078",
+        "7714d521-baf0-2dc2-e8ca-4f6228270099",
+        "92bb5645-1804-8174-5e73-2b0780feecfa",
+        "3c387234-5ae9-e589-2fe0-11666b00fec9",
+        "d01abaee-9f84-d625-4dc8-56da031255a1",
+        "6329fb56-9e3b-647f-141a-dad277c303fd",
+        "51384eb0-05f8-7636-90d8-6d55605f80e6",
+        "dd1cd03e-ab78-b6da-5cd8-271e1c6f9c75",
+        "0dba0439-6a45-88cf-802e-cd678f8541a8",
+        "63b2a578-04fd-803c-8327-2809cdf3fb6d",
+        "950426a5-e1e5-b907-a927-8ba96727232e",
+        "950b4c53-a6ab-7479-4fd8-7edb7a113c34",
+        "29d99111-06d1-3bb7-b482-2c492f072b31",
+        "112f40f9-05b8-d6f0-fcb2-7b9d50fb8fdc",
+        "14fbdff8-1255-5c24-7483-fba3d217d51c",
+        "daafe0e1-62d7-8040-b6b1-0956b937a233",
+        "22354294-1d01-cebf-180c-d609747be9bc",
+        "c8e8f3fd-3bfb-aafa-e3ec-a671a942f426",
+        "d362ddc4-1c5f-67d5-e354-c2a8d2ba9d79",
+        "538c71b3-e3e6-f01b-cc4c-d2b686686aa8",
+        "a13e6877-997e-84e1-c8e8-e83ef5e9a002",
+        "3c86ab7c-a7ee-6b71-3ec1-da7d20f97d1a",
+        "4602c331-5850-0813-c276-d4ec3ae7b3d6",
+        "3b8a86df-fe33-5104-2da7-5e0cbdb7a881",
+        "4e706a35-365a-13e4-f2ec-eee027148450",
+        "06025ed3-7251-5ee4-3d6b-c01557eb3dd2"
+    ],
+    "owner":0,
+    "sharedWithTeam":false,
+    "synced":false,
+    "subscribed":false,
+    "hasRequests":true,
+    "requests":[
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"18032e93-3bc5-9976-4525-fe1e77e98207",
+            "name":"Delete Specific Config Logical Switch",
+            "description":"This restconf request delete specific logical switch from the config data store.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/logical-switches/ls0",
+            "method":"DELETE",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"params",
+            "timestamp":0,
+            "version":2,
+            "time":1447335528744
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"22354294-1d01-cebf-180c-d609747be9bc",
+            "name":"Get All Operational Topology",
+            "description":"This restconf request will fetch the operational topology. Operational topology details are fetch by hwvtepsouthbound plugin from all the connected hwvtep node.",
+            "url":"http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"params",
+            "timestamp":0,
+            "version":2
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"538c71b3-e3e6-f01b-cc4c-d2b686686aa8",
+            "name":"Get Specific Operational Logical Switch",
+            "description":"This restconf request fetch the operational for specific Logical Switch",
+            "url":"http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/logical-switches/ls0",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335701900
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"6de1ede7-817c-ccbb-3df9-ef510bdaf583",
+            "name":"Create Specific Config HwvtepNode",
+            "description":"Fire this Restconf request if you want to initiate the connection to hwvtep node from controller. It assumes that hwvtep node is listening for tcp connection in passive mode.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/",
+            "method":"POST",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640\",\n            \"connection-info\": {\n              \"hwvtep:remote-port\": 6640,\n              \"hwvtep:remote-ip\": \"{{hwvtepNodeIp}}\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447334840814
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"6e7c88e4-485d-ab9f-4c3a-cc235e022905",
+            "name":"Update Specific Config HwvtepNode",
+            "description":"Fire this Restconf request if you want to update the connection to Hwvtep node from controller.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "method":"PUT",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640\",\n            \"connection-info\": {\n              \"hwvtep:remote-port\": 6640,\n              \"hwvtep:remote-ip\": \"{{hwvtepNodeIp}}\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447334483164
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"92ee7422-5b08-6d63-2b95-961ec0e18ffa",
+            "name":"Get Specific Config HwvtepNode",
+            "description":"This restconf request fetch the configration for specific hwvtep node.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640\",\n            \"connection-info\": {\n              \"hwvtep:remote-port\": 6640,\n              \"hwvtep:remote-ip\": \"{{hwvtepNodeIp}}\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447334914971
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"9bc22ca7-049c-af51-7c12-6bf71044b2ec",
+            "name":"Create Specific Config Logical Switch",
+            "description":"Fire this Restconf request if you want to create a logical switch.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "method":"POST",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"logical-switches\": [\n        {\n            \"hwvtep-node-name\": \"ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"tunnel-key\": \"10000\"\n         }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447340822378
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"c8e8f3fd-3bfb-aafa-e3ec-a671a942f426",
+            "name":"Get Operational Hwvtep Topology",
+            "description":"",
+            "url":"http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640\",\n            \"connection-info\": {\n              \"hwvtep:remote-port\": 6640,\n              \"hwvtep:remote-ip\": \"{{hwvtepNodeIp}}\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335830695
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"d362ddc4-1c5f-67d5-e354-c2a8d2ba9d79",
+            "name":"Get Specific Operational HwvtepNode",
+            "description":"This restconf request fetch the operational for specific HwvtepNode",
+            "url":"http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335686540
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"e92ac963-daaf-0899-c3e8-a00d897be0e2",
+            "name":"Delete Specific Config HwvtepNode",
+            "description":"This restconf request delete any node (ovsdb node or bridge node) from the config data store. You can use the same request to delete the ovsdb node by using the following URI: http://localhost:8080/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F10.10.10.10:22222",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "method":"DELETE",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"params",
+            "timestamp":0,
+            "version":2
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"e9ff6957-4dc2-9257-c0c6-21560bfd5de2",
+            "name":"Get All Config Topology",
+            "description":"Fetch all the config topology from configuration data store.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640\",\n            \"connection-info\": {\n              \"hwvtep:remote-port\": 6640,\n              \"hwvtep:remote-ip\": \"{{hwvtepNodeIp}}\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447311894927
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"ee151670-85a0-30ec-b22b-5defe7b66e0b",
+            "name":"Get Config  Hwvtep Topology",
+            "description":"Fetch the config hwvtep topology from configuration data store.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640\",\n            \"connection-info\": {\n              \"hwvtep:remote-port\": 6640,\n              \"hwvtep:remote-ip\": \"{{hwvtepNodeIp}}\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335823182
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"f6d300f7-380a-d090-0d4a-2b2ddefe5104",
+            "name":"Update Specific Config Logical Switch",
+            "description":"Fire this request if you want to update specific logical switch.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/logical-switches/ls0",
+            "method":"PUT",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"logical-switches\": [\n        {\n            \"hwvtep-node-name\": \"ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"tunnel-key\": \"10000\"\n         }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447340847211
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"f9f71d74-a49d-b190-d929-b6772ce0ba73",
+            "name":"Get Specific Config Logical Switch",
+            "description":"This restconf request fetch configuration for specific logical switch.",
+            "url":"http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/logical-switches/ls0",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335408595
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "88789ac9-9de9-bab3-565b-307774e49f4d",
+            "name": "Create Specific Config Physical Switch",
+            "description": "Fire this Restconf request if you want to create a physical switch.",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/",
+            "method": "POST",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data": [],
+            "dataMode": "raw",
+            "timestamp": 0,
+            "version": 2,
+            "time": 1447909152443,
+            "preRequestScript": "",
+            "tests": "",
+            "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640/physicalswitch/br0\",\n            \"hwvtep-node-name\": \"br0\",\n            \"hwvtep-node-description\": \"\",\n            \"management-ips\": [\n              {\n                \"management-ips-key\": \"{{managementIp}}\"\n              }\n            ],\n            \"tunnel-ips\": [\n              {\n                \"tunnel-ips-key\": \"{{tunnelIp}}\"\n              }\n            ],\n            \"managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']\"             \n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "e25f67e4-3a3f-5da7-f7c8-41b371156719",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448552632013,
+            "name": "Update Specific Config Physical Switch",
+            "description": "Fire this Restconf request if you want to update a exsiting physical switch.",
+            "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://{{hwvtepNodeIp}}:6640/physicalswitch/br0\",\n            \"hwvtep-node-name\": \"br0\",\n            \"hwvtep-node-description\": \"\",\n            \"management-ips\": [\n              {\n                \"management-ips-key\": \"{{managementIp}}\"\n              }\n            ],\n            \"tunnel-ips\": [\n              {\n                \"tunnel-ips-key\": \"{{tunnelIp}}\"\n              }\n            ],\n            \"managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']\"             \n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "f7d33d50-7c8e-69e2-6d60-5c6155c5d210",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448548819543,
+            "name": "Get Specific Config Physical Switch",
+            "description": "Fire this Restconf request if you want to get a exsiting physical switch."
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "233b5ab5-8177-4416-6912-2477520a0654",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448552707318,
+            "name": "Delete Specific Config Physical Switch",
+            "description": "Fire this Restconf request if you want to delete a physical switch.",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "a13e6877-997e-84e1-c8e8-e83ef5e9a002",
+            "name": "Get Specific Operational Physical Switch",
+            "description": "",
+            "url": "http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0",
+            "method": "GET",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data": [],
+            "dataMode": "raw",
+            "timestamp": 0,
+            "responses": [],
+            "version": 2,
+            "preRequestScript": "",
+            "tests": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "567d7827-628d-07a4-3b95-5a208a244c43",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448641495086,
+            "name": "Create Specific Config Physical Port",
+            "description": "",
+            "rawModeData": "{\n  \"network-topology:termination-point\": [\n        {\n            \"tp-id\": \"port0\",\n          \t\"hwvtep-node-name\": \"port0\",\n            \"hwvtep-node-description\": \"\",\n            \"vlan-bindings\": [\n          \t\t{\n                  \"vlan-id-key\": \"100\",\n                  \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\"\n            \t}\n          \t]\n\t\t}\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "f906c48b-ba3c-a3da-36e8-34c453538e2e",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0/termination-point/port0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448643757985,
+            "name": "Update Specific Config Physical Port",
+            "description": "",
+            "rawModeData": "{\n  \"network-topology:termination-point\": [\n        {\n            \"tp-id\": \"port0\",\n          \t\"hwvtep-node-name\": \"port0\",\n            \"hwvtep-node-description\": \"\",\n            \"vlan-bindings\": [\n          \t\t{\n                  \"vlan-id-key\": \"100\",\n                  \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\"\n            \t}\n          \t]\n\t\t}\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "5d0c4d49-44f7-4165-ca5f-00cf2a9fca8b",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0/termination-point/port0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448643846609,
+            "name": "Get Specific Config Physical Port",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "34167a78-7de4-91a9-ef40-7592b28ead5c",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0/termination-point/port0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448643860663,
+            "name": "Delete Specific Config Physical Port",
+            "description": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "3c86ab7c-a7ee-6b71-3ec1-da7d20f97d1a",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640%2Fphysicalswitch%2Fbr0/termination-point/port0",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448718837283,
+            "name": "Get Specific Operational Physical Port",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "20e8b57b-a5e7-a52f-01d6-7b66ea551078",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449132978312,
+            "name": "Create Specific Config UcastMacRemote",
+            "description": "",
+            "rawModeData": "{\n  \"remote-ucast-macs\": [\n        {\n            \"mac-entry-key\": \"11:11:11:11:11:11\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"1.1.1.1\",\n            \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{LocatorIp}}']\"             \n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "7714d521-baf0-2dc2-e8ca-4f6228270099",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-ucast-macs/11:11:11:11:11:11",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449310821724,
+            "name": "Update Specific Config UcastMacRemote",
+            "description": "",
+            "rawModeData": "{\n  \"remote-ucast-macs\": [\n        {\n            \"mac-entry-key\": \"11:11:11:11:11:11\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"1.1.1.1\",\n            \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{LocatorIp}}']\"\n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "92bb5645-1804-8174-5e73-2b0780feecfa",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-ucast-macs/11:11:11:11:11:11",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449311389212,
+            "name": "Get Specific Config UcastMacRemote",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "3c387234-5ae9-e589-2fe0-11666b00fec9",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-ucast-macs/11:11:11:11:11:11",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449311417267,
+            "name": "Delete Specific Config UcastMacRemote",
+            "description": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "4602c331-5850-0813-c276-d4ec3ae7b3d6",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/operational/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-ucast-macs/11:11:11:11:11:11",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449314879742,
+            "name": "Get Specific Operational UcastMacRemote",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "6f6addb7-6d48-e1ef-8cc2-c5841d71c2e5",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1448972198808,
+            "name": "Create Specific Config Locator",
+            "description": "",
+            "rawModeData": "{\n  \"termination-point\": [\n        {\n            \"tp-id\": \"vxlan_over_ipv4:{{LocatorIp}}\",\n            \"encapsulation-type\": \"encapsulation-type-vxlan-over-ipv4\",\n          \t\"dst-ip\": \"{{LocatorIp}}\"\n\t\t}\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "d01abaee-9f84-d625-4dc8-56da031255a1",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449286080233,
+            "name": "Create Specific Config UcastMacLocal",
+            "description": "",
+            "rawModeData": "{\n  \"local-ucast-macs\": [\n        {\n            \"mac-entry-key\": \"22:22:22:22:22:22\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"2.2.2.2\",\n            \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{LocatorIp}}']\"             \n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "6329fb56-9e3b-647f-141a-dad277c303fd",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-ucast-macs/22:11:11:11:11:11",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449310498424,
+            "name": "Update Specific Config UcastMacLocal",
+            "description": "",
+            "rawModeData": "{\n  \"local-ucast-macs\": [\n        {\n            \"mac-entry-key\": \"22:22:22:22:22:22\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"2.2.2.2\",\n            \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{LocatorIp}}']\"\n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "51384eb0-05f8-7636-90d8-6d55605f80e6",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-ucast-macs/22:22:22:22:22:22",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449311223998,
+            "name": "Get Specific Config UcastMacLocal ",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "dd1cd03e-ab78-b6da-5cd8-271e1c6f9c75",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-ucast-macs/22:22:22:22:22:22",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449311421493,
+            "name": "Delete Specific Config UcastMacLocal",
+            "description": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "3b8a86df-fe33-5104-2da7-5e0cbdb7a881",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-ucast-macs/22:22:22:22:22:22",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449315928725,
+            "name": "Get Specific Operational UcastMacLocal ",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "0dba0439-6a45-88cf-802e-cd678f8541a8",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449468092415,
+            "name": "Create Specific Config McastMacRemote",
+            "description": "",
+            "rawModeData": "{\n  \"remote-mcast-macs\": [\n        {\n            \"mac-entry-key\": \"33:33:33:33:33:55\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"3.3.3.5\",\n            \"locator-set\": [\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-1}}']\"\n                },\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-2}}']\"\n                }\n            ]\n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "63b2a578-04fd-803c-8327-2809cdf3fb6d",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-mcast-macs/33:33:33:33:33:33",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449468318065,
+            "name": "Update Specific Config McastMacRemote ",
+            "description": "",
+            "rawModeData": "{\n  \"remote-mcast-macs\": [\n        {\n            \"mac-entry-key\": \"33:33:33:33:33:33\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"3.3.3.3\",\n            \"locator-set\": [\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-1}}']\"\n                },\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-2}}']\"\n                }\n            ]\n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "950426a5-e1e5-b907-a927-8ba96727232e",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-mcast-macs/33:33:33:33:33:33",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449553538252,
+            "name": "Get Specific Config McastMacRemote ",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "950b4c53-a6ab-7479-4fd8-7edb7a113c34",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-mcast-macs/33:33:33:33:33:33",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449553525974,
+            "name": "delete Specific Config McastMacRemote ",
+            "description": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "4e706a35-365a-13e4-f2ec-eee027148450",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/remote-mcast-macs/33:33:33:33:33:33",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449553579687,
+            "name": "Get Specific Operational McastMacRemote ",
+            "description": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "29d99111-06d1-3bb7-b482-2c492f072b31",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449468010690,
+            "name": "Create Specific Config McastMacLocal",
+            "description": "",
+            "rawModeData": "{\n  \"local-mcast-macs\": [\n        {\n            \"mac-entry-key\": \"44:44:44:44:44:66\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"4.4.4.6\",\n            \"locator-set\": [\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-1}}']\"\n                },\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-2}}']\"\n                }\n            ]\n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "112f40f9-05b8-d6f0-fcb2-7b9d50fb8fdc",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-mcast-macs/44:44:44:44:44:44",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449468504628,
+            "name": "Update Specific Config McastMacLocal",
+            "description": "",
+            "rawModeData": "{\n  \"local-mcast-macs\": [\n        {\n            \"mac-entry-key\": \"44:44:44:44:44:44\",\n            \"logical-switch-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/hwvtep:logical-switches[hwvtep:hwvtep-node-name='ls0']\",\n            \"ipaddr\": \"4.4.4.4\",\n            \"locator-set\": [\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-1}}']\"\n                },\n                {\n                    \"locator-ref\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://{{hwvtepNodeIp}}:6640']/network-topology:termination-point[network-topology:tp-id='vxlan_over_ipv4:{{locatorIp-2}}']\"\n                }\n            ]\n        }\n    ]\n}"
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "14fbdff8-1255-5c24-7483-fba3d217d51c",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-mcast-macs/44:44:44:44:44:44",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449553697904,
+            "name": "Get Specific Config McastMacLocal ",
+            "description": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "daafe0e1-62d7-8040-b6b1-0956b937a233",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-mcast-macs/44:44:44:44:44:44",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449553714791,
+            "name": "Delete Specific Config McastMacLocal ",
+            "description": "",
+            "rawModeData": ""
+        },
+        {
+            "collectionId": "19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id": "06025ed3-7251-5ee4-3d6b-c01557eb3dd2",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{controllerHost}}:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F{{hwvtepNodeIp}}:6640/local-mcast-macs/44:44:44:44:44:44",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1449553741834,
+            "name": "Get Specific Operational McastMacLocal ",
+            "description": ""
+        }
+    ]
+}
diff --git a/resources/commons/Ovsdb-Southbound-Collection-for-3-Node-Cluster.json.postman_collection b/resources/commons/Ovsdb-Southbound-Collection-for-3-Node-Cluster.json.postman_collection
new file mode 100644 (file)
index 0000000..a79dd4f
--- /dev/null
@@ -0,0 +1,821 @@
+{
+       "id": "4cd83ae0-a164-c12a-a872-c2205817594a",
+       "name": "Ovsdb Southbound Collection for 3 Node Cluster",
+       "description": "All the rest conf request present in this collection depends on the \"3 Node Cluster Setup Environment Variables\" file.\n\nYou need to import this file, using the \"Manager Environment\" option present in the right top cornor of the postman window.",
+       "order": [
+               "be720a0e-5a69-91e2-93fb-5ffc4efe7f8c",
+               "4980abaf-b36a-42c7-4cde-cdc3d0ef594d",
+               "783d6e22-bfb0-9bec-bc24-da5d75b82123",
+               "2be310a1-3741-8881-fca1-b8bbc7daae7e",
+               "843e0282-c43e-4754-d415-f2a59b3eeb65",
+               "001d0bb8-5918-db89-e360-2fa5d5747cf3",
+               "a51f9d53-7917-7d2a-655c-d7f772045122",
+               "87269c7c-4a76-6dc1-036a-91be949477b0",
+               "24afe1e9-d235-0eec-2b3d-465168b30242",
+               "47fa5fbe-2b71-aae5-1859-fb42090efd24",
+               "319fede8-b756-8c67-b0b2-bf1cf6a4070b",
+               "dcafada2-2452-3701-f26c-c189e18f3ab0",
+               "9ff5feea-b08d-b0b7-2934-1cf6c10ab643",
+               "821cc80a-d417-a2ea-36e5-6138252a8ecb",
+               "3f4c1bd6-8b5e-9e0c-577f-7e0dcfa84cdd",
+               "d7e5948a-cab1-a6eb-32bd-a9220691a6d6",
+               "b9748414-6b9d-4fcc-2f43-b6be86a4e4be",
+               "c9430389-323d-452f-a204-c8c0ef12dcf6",
+               "35c25342-e126-393b-f74b-d3f828983ba1",
+               "c60b33eb-c776-06fc-1f28-551c429ad196",
+               "01cdfc13-82a8-5989-12d0-0e029609f1b8",
+               "b0592ca5-7d6a-ebd4-6f98-c431d1c11ce7",
+               "d9b65865-d54b-408b-f868-3e71fee53593",
+               "5e628d2c-cadf-4ca8-1800-6517c07cb917",
+               "cef78015-fff6-62f0-698b-76f26505e6df",
+               "f42c21e0-116d-5428-1dfb-9b01e8ad72fa",
+               "b592f176-36a7-6830-f3a9-0547f18bcd2d",
+               "499c888c-0868-3241-603e-5c775f9cd678",
+               "c24aebbf-bb85-3201-f605-21e7fef17ae1",
+               "7ee803d2-3326-5f61-8fc0-5ebd8ac2c56c",
+               "11dd55f7-7f0c-f6ce-8377-4b08919b073e",
+               "bd270450-ee6a-6ebb-f7f1-8e0461ee4f56",
+               "c01d85a0-5f9a-54ef-f2ff-3aefef8c465e",
+               "38b350e8-4349-f5a0-5d42-61ef885a4d9d",
+               "92688f6e-dd8b-5b2f-4525-ecfccf4d6248",
+               "ff01de93-1b51-200a-87d0-443091fdfb78",
+               "6cf9fe58-77ca-fac5-bf9a-b5294254a9ef",
+               "b4f9dbc2-ab25-e45b-302f-cd058367d8a9",
+               "36fe5adc-41a9-859d-6986-205685fc832d",
+               "70f19c4e-9c96-7774-36ec-424566c24597",
+               "a110b75d-6445-2618-09e6-2f4ff0ab387d",
+               "939becd9-43d9-be67-0cec-49caf45aaef8"
+       ],
+       "folders": [],
+       "timestamp": 1443832335637,
+       "owner": "128022",
+       "remoteLink": "",
+       "public": false,
+       "requests": [
+               {
+                       "id": "001d0bb8-5918-db89-e360-2fa5d5747cf3",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834393294,
+                       "name": "Node-3-OVSDB Operational Topology",
+                       "description": "This restconf request fetches the topology details from the `Operational` data store that contains details about all the connected hypervisor, bridges present on the hypervisor and termination point connected to each bridge.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "01cdfc13-82a8-5989-12d0-0e029609f1b8",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834419934,
+                       "name": "Node-3-OVSDB Bridge Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for specific bridge (`brtest`) present on the given ovsdb server/hypervisor(`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "11dd55f7-7f0c-f6ce-8377-4b08919b073e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834274756,
+                       "name": "Node-1-Termination Point Configuration Data",
+                       "description": "This restconf request fetch data from `Configuration` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "24afe1e9-d235-0eec-2b3d-465168b30242",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834401766,
+                       "name": "Node-3-OVSDB Server Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "2be310a1-3741-8881-fca1-b8bbc7daae7e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834214050,
+                       "name": "Node-1-OVSDB Operational Topology",
+                       "description": "This restconf request fetches the topology details from the `Operational` data store that contains details about all the connected hypervisor, bridges present on the hypervisor and termination point connected to each bridge.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "319fede8-b756-8c67-b0b2-bf1cf6a4070b",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834321665,
+                       "name": "Node-2-OVSDB Server Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "35c25342-e126-393b-f74b-d3f828983ba1",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834250855,
+                       "name": "Node-1-OVSDB Bridge Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for specific bridge (`brtest`) present on the given ovsdb server/hypervisor(`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "36fe5adc-41a9-859d-6986-205685fc832d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834453771,
+                       "name": "Node-3-Create Termination Point on Given Bridge",
+                       "description": "This restconf request creates port/interface (`testport`) and attach it to give bridge (`HYPERVISOR-NODE-ID`). Using ovsdb:option, you can pass the optional input to port/interface create optional. E.g. remote_ip=xx.xx.xx.xx.\n\n    Note: Please change the attributes of the interface if you don't want to create this default termination point.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n  \t\t\t\"ovsdb:options\": [\n    \t\t\t{\n                  \"ovsdb:option\": \"remote_ip\",\n                  \"ovsdb:value\" : \"10.10.14.11\"\n\t\t    \t}\n\t  \t\t],\n\t  \t\t\"ovsdb:name\": \"testport\",\n          \t\"ovsdb:interface-type\": \"ovsdb:interface-type-vxlan\",\n  \t\t\t\"tp-id\": \"testport\",\n            \"vlan-tag\": \"1\",\n            \"trunks\": [\n                {\n                    \"trunk\": \"5\"\n                }\n            ],\n            \"vlan-mode\":\"access\"\n\t\t}\n    ]\n}"
+               },
+               {
+                       "id": "38b350e8-4349-f5a0-5d42-61ef885a4d9d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834281860,
+                       "name": "Node-1-Termination Point Operational Data",
+                       "description": "This restconf request fetch data from `Operational` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "3f4c1bd6-8b5e-9e0c-577f-7e0dcfa84cdd",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834410953,
+                       "name": "Node-3-Connect to the OVSDB Server",
+                       "description": "This Restconf request will ask controller to initiate the connection to ovsdb server running on hypervisor. Controller assumes that ovsdb server is listening for tcp connection in passive mode. To configure the ovsdb server to listen in passive mode, please fire following command on hypervisor\n\n`ovs-vsctl set-manager ptcp:16640`\n\nwhatever port number you use here, you should use the same port number for HYPERVISOR-OVSDB-PORT key in \"Single Node Cluster Setup Environment\" Environmen file.\n\n        Note: Please set the environment variable `HYPERVISOR-IP` to the hypervisor ip that is running OVSDB server and `HYPERVISOR-OVSDB-PORT` to the port number on which OVSDB server is listening. Both of these environment variables are present in the \"Single Node Cluster Setup Enviornment\" file. ",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": \"{{HYPERVISOR-OVSDB-PORT}}\",\n              \"ovsdb:remote-ip\": \"{{HYPERVISOR-IP}}\"\n            }\n        }\n    ]\n}"
+               },
+               {
+                       "id": "47fa5fbe-2b71-aae5-1859-fb42090efd24",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834223225,
+                       "name": "Node-1-OVSDB Server Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "4980abaf-b36a-42c7-4cde-cdc3d0ef594d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834302452,
+                       "name": "Node-2-OVSDB Configuration Topology",
+                       "description": "This restconf request fetch the topology details from `Configuration` data store that is pushed by user..",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "499c888c-0868-3241-603e-5c775f9cd678",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834269373,
+                       "name": "Node-1-Delete OVS Bridge on Hypervisor",
+                       "description": "This restconf request deletes OVS bridge (`brtest`) on the hypervisor with the node-id provided through `HYPERVISOR-NODE-ID` environment variable set in the `Single Node Cluster Setup Environment` file.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "5e628d2c-cadf-4ca8-1800-6517c07cb917",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834426689,
+                       "name": "Node-3-OVSDB Bridge Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for specific bridge (`brtest`) present on given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "6cf9fe58-77ca-fac5-bf9a-b5294254a9ef",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834286293,
+                       "name": "Node-1-Create Termination Point on Given Bridge",
+                       "description": "This restconf request creates port/interface (`testport`) and attach it to give bridge (`HYPERVISOR-NODE-ID`). Using ovsdb:option, you can pass the optional input to port/interface create optional. E.g. remote_ip=xx.xx.xx.xx.\n\n    Note: Please change the attributes of the interface if you don't want to create this default termination point.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n  \t\t\t\"ovsdb:options\": [\n    \t\t\t{\n                  \"ovsdb:option\": \"remote_ip\",\n                  \"ovsdb:value\" : \"10.10.14.11\"\n\t\t    \t}\n\t  \t\t],\n\t  \t\t\"ovsdb:name\": \"testport\",\n          \t\"ovsdb:interface-type\": \"ovsdb:interface-type-vxlan\",\n  \t\t\t\"tp-id\": \"testport\",\n            \"vlan-tag\": \"1\",\n            \"trunks\": [\n                {\n                    \"trunk\": \"5\"\n                }\n            ],\n            \"vlan-mode\":\"access\"\n\t\t}\n    ]\n}"
+               },
+               {
+                       "id": "70f19c4e-9c96-7774-36ec-424566c24597",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834290451,
+                       "name": "Node-1-Delete Termination Point on Given Bridge",
+                       "description": "Delete termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`). ",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "783d6e22-bfb0-9bec-bc24-da5d75b82123",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834389570,
+                       "name": "Node-3-OVSDB Configuration Topology",
+                       "description": "This restconf request fetch the topology details from `Configuration` data store that is pushed by user..",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "7ee803d2-3326-5f61-8fc0-5ebd8ac2c56c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834438109,
+                       "name": "Node-3-Delete OVS Bridge on Hypervisor",
+                       "description": "This restconf request deletes OVS bridge (`brtest`) on the hypervisor with the node-id provided through `HYPERVISOR-NODE-ID` environment variable set in the `Single Node Cluster Setup Environment` file.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "821cc80a-d417-a2ea-36e5-6138252a8ecb",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834326599,
+                       "name": "Node-2-Connect to the OVSDB Server",
+                       "description": "This Restconf request will ask controller to initiate the connection to ovsdb server running on hypervisor. Controller assumes that ovsdb server is listening for tcp connection in passive mode. To configure the ovsdb server to listen in passive mode, please fire following command on hypervisor\n\n`ovs-vsctl set-manager ptcp:16640`\n\nwhatever port number you use here, you should use the same port number for HYPERVISOR-OVSDB-PORT key in \"Single Node Cluster Setup Environment\" Environmen file.\n\n        Note: Please set the environment variable `HYPERVISOR-IP` to the hypervisor ip that is running OVSDB server and `HYPERVISOR-OVSDB-PORT` to the port number on which OVSDB server is listening. Both of these environment variables are present in the \"Single Node Cluster Setup Enviornment\" file. ",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": \"{{HYPERVISOR-OVSDB-PORT}}\",\n              \"ovsdb:remote-ip\": \"{{HYPERVISOR-IP}}\"\n            }\n        }\n    ]\n}"
+               },
+               {
+                       "id": "843e0282-c43e-4754-d415-f2a59b3eeb65",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834311880,
+                       "name": "Node-2-OVSDB Operational Topology",
+                       "description": "This restconf request fetches the topology details from the `Operational` data store that contains details about all the connected hypervisor, bridges present on the hypervisor and termination point connected to each bridge.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "87269c7c-4a76-6dc1-036a-91be949477b0",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834316676,
+                       "name": "Node-2-OVSDB Server Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "92688f6e-dd8b-5b2f-4525-ecfccf4d6248",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834361798,
+                       "name": "Node-2-Termination Point Operational Data",
+                       "description": "This restconf request fetch data from `Operational` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "939becd9-43d9-be67-0cec-49caf45aaef8",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834458122,
+                       "name": "Node-3-Delete Termination Point on Given Bridge",
+                       "description": "Delete termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`). ",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "9ff5feea-b08d-b0b7-2934-1cf6c10ab643",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834229957,
+                       "name": "Node-1-Connect to the OVSDB Server",
+                       "description": "This Restconf request will ask controller to initiate the connection to ovsdb server running on hypervisor. Controller assumes that ovsdb server is listening for tcp connection in passive mode. To configure the ovsdb server to listen in passive mode, please fire following command on hypervisor\n\n`ovs-vsctl set-manager ptcp:16640`\n\nwhatever port number you use here, you should use the same port number for HYPERVISOR-OVSDB-PORT key in \"Single Node Cluster Setup Environment\" Environmen file.\n\n        Note: Please set the environment variable `HYPERVISOR-IP` to the hypervisor ip that is running OVSDB server and `HYPERVISOR-OVSDB-PORT` to the port number on which OVSDB server is listening. Both of these environment variables are present in the \"Single Node Cluster Setup Enviornment\" file. ",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": \"{{HYPERVISOR-OVSDB-PORT}}\",\n              \"ovsdb:remote-ip\": \"{{HYPERVISOR-IP}}\"\n            }\n        }\n    ]\n}"
+               },
+               {
+                       "id": "a110b75d-6445-2618-09e6-2f4ff0ab387d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834373402,
+                       "name": "Node-2-Delete Termination Point on Given Bridge",
+                       "description": "Delete termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`). ",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "a51f9d53-7917-7d2a-655c-d7f772045122",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834218789,
+                       "name": "Node-1-OVSDB Server Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "b0592ca5-7d6a-ebd4-6f98-c431d1c11ce7",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834257622,
+                       "name": "Node-1-OVSDB Bridge Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for specific bridge (`brtest`) present on given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "b4f9dbc2-ab25-e45b-302f-cd058367d8a9",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834368804,
+                       "name": "Node-2-Create Termination Point on Given Bridge",
+                       "description": "This restconf request creates port/interface (`testport`) and attach it to give bridge (`HYPERVISOR-NODE-ID`). Using ovsdb:option, you can pass the optional input to port/interface create optional. E.g. remote_ip=xx.xx.xx.xx.\n\n    Note: Please change the attributes of the interface if you don't want to create this default termination point.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n  \t\t\t\"ovsdb:options\": [\n    \t\t\t{\n                  \"ovsdb:option\": \"remote_ip\",\n                  \"ovsdb:value\" : \"10.10.14.11\"\n\t\t    \t}\n\t  \t\t],\n\t  \t\t\"ovsdb:name\": \"testport\",\n          \t\"ovsdb:interface-type\": \"ovsdb:interface-type-vxlan\",\n  \t\t\t\"tp-id\": \"testport\",\n            \"vlan-tag\": \"1\",\n            \"trunks\": [\n                {\n                    \"trunk\": \"5\"\n                }\n            ],\n            \"vlan-mode\":\"access\"\n\t\t}\n    ]\n}"
+               },
+               {
+                       "id": "b592f176-36a7-6830-f3a9-0547f18bcd2d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834432527,
+                       "name": "Node-3-Create OVS   Bridge on Hypervisor",
+                       "description": "This restconf request creates bridge (`brtest`) on the specified hypervisor running ovsdb server. Restconf URI need the node-id of the OVSDB server (hypervisor) where you need to get the bridge. You can find out the node id by using the \"GET Operational Topology\" request.\n\n       Note: these %2F ('/') in the url are not there by mistake, those are there intentionally because node-id can contain '/'.\n",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n          \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}/bridge/brtest\",\n             \"ovsdb:bridge-name\": \"brtest\",\n             \"ovsdb:datapath-id\": \"00:00:b2:bf:48:25:f2:4b\",\n             \"ovsdb:protocol-entry\": [\n                {\n                  \"protocol\": \"ovsdb:ovsdb-bridge-protocol-openflow-13\"\n                }\n              ],\n              \"ovsdb:controller-entry\": [\n                {\n                  \"target\": \"tcp:11.11.11.11:6633\"\n                }\n              ],\n             \"ovsdb:managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://{{HYPERVISOR-NODE-ID}}']\"\n        }\n    ]\n}"
+               },
+               {
+                       "id": "b9748414-6b9d-4fcc-2f43-b6be86a4e4be",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834331946,
+                       "name": "Node-2-Disconnect from OVSDB Server",
+                       "description": "This restconf request ask controller to disconnect from the OVSDB server/hypervisor (`HYPERVISOR-NODE-ID`).\n",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "bd270450-ee6a-6ebb-f7f1-8e0461ee4f56",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834357784,
+                       "name": "Node-2-Termination Point Configuration Data",
+                       "description": "This restconf request fetch data from `Configuration` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "be720a0e-5a69-91e2-93fb-5ffc4efe7f8c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834199359,
+                       "name": "Node-1-OVSDB Configuration Topology",
+                       "description": "This restconf request fetch the topology details from `Configuration` data store that is pushed by user..",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "c01d85a0-5f9a-54ef-f2ff-3aefef8c465e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834442134,
+                       "name": "Node-3-Termination Point Configuration Data",
+                       "description": "This restconf request fetch data from `Configuration` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "c24aebbf-bb85-3201-f605-21e7fef17ae1",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834353913,
+                       "name": "Node-2-Delete OVS Bridge on Hypervisor",
+                       "description": "This restconf request deletes OVS bridge (`brtest`) on the hypervisor with the node-id provided through `HYPERVISOR-NODE-ID` environment variable set in the `Single Node Cluster Setup Environment` file.",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "c60b33eb-c776-06fc-1f28-551c429ad196",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834337153,
+                       "name": "Node-2-OVSDB Bridge Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for specific bridge (`brtest`) present on the given ovsdb server/hypervisor(`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "c9430389-323d-452f-a204-c8c0ef12dcf6",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834415258,
+                       "name": "Node-3-Disconnect from OVSDB Server",
+                       "description": "This restconf request ask controller to disconnect from the OVSDB server/hypervisor (`HYPERVISOR-NODE-ID`).\n",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "cef78015-fff6-62f0-698b-76f26505e6df",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834262569,
+                       "name": "Node-1-Create OVS   Bridge on Hypervisor",
+                       "description": "This restconf request creates bridge (`brtest`) on the specified hypervisor running ovsdb server. Restconf URI need the node-id of the OVSDB server (hypervisor) where you need to get the bridge. You can find out the node id by using the \"GET Operational Topology\" request.\n\n       Note: these %2F ('/') in the url are not there by mistake, those are there intentionally because node-id can contain '/'.\n",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n          \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}/bridge/brtest\",\n             \"ovsdb:bridge-name\": \"brtest\",\n             \"ovsdb:datapath-id\": \"00:00:b2:bf:48:25:f2:4b\",\n             \"ovsdb:protocol-entry\": [\n                {\n                  \"protocol\": \"ovsdb:ovsdb-bridge-protocol-openflow-13\"\n                }\n              ],\n              \"ovsdb:controller-entry\": [\n                {\n                  \"target\": \"tcp:11.11.11.11:6633\"\n                }\n              ],\n             \"ovsdb:managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://{{HYPERVISOR-NODE-ID}}']\"\n        }\n    ]\n}"
+               },
+               {
+                       "id": "d7e5948a-cab1-a6eb-32bd-a9220691a6d6",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-1-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834244138,
+                       "name": "Node-1-Disconnect from OVSDB Server",
+                       "description": "This restconf request ask controller to disconnect from the OVSDB server/hypervisor (`HYPERVISOR-NODE-ID`).\n",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "d9b65865-d54b-408b-f868-3e71fee53593",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834342352,
+                       "name": "Node-2-OVSDB Bridge Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for specific bridge (`brtest`) present on given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "dcafada2-2452-3701-f26c-c189e18f3ab0",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834405872,
+                       "name": "Node-3-OVSDB Server Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               },
+               {
+                       "id": "f42c21e0-116d-5428-1dfb-9b01e8ad72fa",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{NODE-2-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834350002,
+                       "name": "Node-2-Create OVS   Bridge on Hypervisor",
+                       "description": "This restconf request creates bridge (`brtest`) on the specified hypervisor running ovsdb server. Restconf URI need the node-id of the OVSDB server (hypervisor) where you need to get the bridge. You can find out the node id by using the \"GET Operational Topology\" request.\n\n       Note: these %2F ('/') in the url are not there by mistake, those are there intentionally because node-id can contain '/'.\n",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n          \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}/bridge/brtest\",\n             \"ovsdb:bridge-name\": \"brtest\",\n             \"ovsdb:datapath-id\": \"00:00:b2:bf:48:25:f2:4b\",\n             \"ovsdb:protocol-entry\": [\n                {\n                  \"protocol\": \"ovsdb:ovsdb-bridge-protocol-openflow-13\"\n                }\n              ],\n              \"ovsdb:controller-entry\": [\n                {\n                  \"target\": \"tcp:11.11.11.11:6633\"\n                }\n              ],\n             \"ovsdb:managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://{{HYPERVISOR-NODE-ID}}']\"\n        }\n    ]\n}"
+               },
+               {
+                       "id": "ff01de93-1b51-200a-87d0-443091fdfb78",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{NODE-3-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443834446829,
+                       "name": "Node-3-Termination Point Operational Data",
+                       "description": "This restconf request fetch data from `Operational` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "4cd83ae0-a164-c12a-a872-c2205817594a"
+               }
+       ]
+}
\ No newline at end of file
diff --git a/resources/commons/Ovsdb-Southbound-Collection-for-Single-Node-Cluster.json.postman_collection b/resources/commons/Ovsdb-Southbound-Collection-for-Single-Node-Cluster.json.postman_collection
new file mode 100644 (file)
index 0000000..84e1976
--- /dev/null
@@ -0,0 +1,285 @@
+{
+       "id": "2de57d6a-ec2c-a568-c3a9-761f712622d3",
+       "name": "Ovsdb Southbound Collection for Single Node Cluster",
+       "description": "All the rest conf request present in this collection depends on the \"Single Node Cluster Setup Environment\" file.\nYou need to import this file, using the \"Manager Environment\" option present in the right top cornor of the postman window.",
+       "order": [
+               "dc447867-22db-fd3a-b482-6186bd3d190a",
+               "b09f9ed0-4df7-35d3-e81d-b9447313d722",
+               "8b2d3563-28d4-91c8-5f2b-ce959c348f2d",
+               "933a4c6d-cd57-1a68-012e-1d08a9c34bc6",
+               "31a9b08f-051b-c42d-9abd-612e8056c3b0",
+               "655ce1b6-dc16-d38c-6ab4-4b8b9515e1ce",
+               "2cc24c37-d5f2-2ef3-d946-8cfe44eabf56",
+               "22815a0a-75ca-f191-92b5-ca3b2fb67bd7",
+               "88edd164-76a3-c5a5-2b89-613ec89e82a4",
+               "58ee801a-3fa3-0d48-7672-14a390a0ea6d",
+               "b25cd26b-dd0b-369d-a246-ed1a29d0189b",
+               "8fb3e047-f00a-1dff-df9c-c548b2749c1e",
+               "001b745f-fad9-3f41-38f1-6ef5baf011a6",
+               "c7cb64ce-db7b-0c95-6268-bc265766a597"
+       ],
+       "folders": [],
+       "timestamp": 0,
+       "owner": "128022",
+       "remoteLink": "",
+       "public": false,
+       "requests": [
+               {
+                       "id": "001b745f-fad9-3f41-38f1-6ef5baf011a6",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443830363372,
+                       "name": "Create Termination Point on Given Bridge",
+                       "description": "This restconf request creates port/interface (`testport`) and attach it to give bridge (`HYPERVISOR-NODE-ID`). Using ovsdb:option, you can pass the optional input to port/interface create optional. E.g. remote_ip=xx.xx.xx.xx.\n\n    Note: Please change the attributes of the interface if you don't want to create this default termination point.",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3",
+                       "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n  \t\t\t\"ovsdb:options\": [\n    \t\t\t{\n                  \"ovsdb:option\": \"remote_ip\",\n                  \"ovsdb:value\" : \"10.10.14.11\"\n\t\t    \t}\n\t  \t\t],\n\t  \t\t\"ovsdb:name\": \"testport\",\n          \t\"ovsdb:interface-type\": \"ovsdb:interface-type-vxlan\",\n  \t\t\t\"tp-id\": \"testport\",\n            \"vlan-tag\": \"1\",\n            \"trunks\": [\n                {\n                    \"trunk\": \"5\"\n                }\n            ],\n            \"vlan-mode\":\"access\"\n\t\t}\n    ]\n}"
+               },
+               {
+                       "id": "22815a0a-75ca-f191-92b5-ca3b2fb67bd7",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443831851013,
+                       "name": "OVSDB Bridge Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for specific bridge (`brtest`) present on given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "2cc24c37-d5f2-2ef3-d946-8cfe44eabf56",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443828713776,
+                       "name": "OVSDB Bridge Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for specific bridge (`brtest`) present on the given ovsdb server/hypervisor(`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "31a9b08f-051b-c42d-9abd-612e8056c3b0",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443827769663,
+                       "name": "Connect to the OVSDB Server",
+                       "description": "This Restconf request will ask controller to initiate the connection to ovsdb server running on hypervisor. Controller assumes that ovsdb server is listening for tcp connection in passive mode. To configure the ovsdb server to listen in passive mode, please fire following command on hypervisor\n\n`ovs-vsctl set-manager ptcp:16640`\n\nwhatever port number you use here, you should use the same port number for HYPERVISOR-OVSDB-PORT key in \"Single Node Cluster Setup Environment\" Environmen file.\n\n        Note: Please set the environment variable `HYPERVISOR-IP` to the hypervisor ip that is running OVSDB server and `HYPERVISOR-OVSDB-PORT` to the port number on which OVSDB server is listening. Both of these environment variables are present in the \"Single Node Cluster Setup Enviornment\" file. ",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": \"{{HYPERVISOR-OVSDB-PORT}}\",\n              \"ovsdb:remote-ip\": \"{{HYPERVISOR-IP}}\"\n            }\n        }\n    ]\n}"
+               },
+               {
+                       "id": "58ee801a-3fa3-0d48-7672-14a390a0ea6d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443828628211,
+                       "name": "Delete OVS Bridge on Hypervisor",
+                       "description": "This restconf request deletes OVS bridge (`brtest`) on the hypervisor with the node-id provided through `HYPERVISOR-NODE-ID` environment variable set in the `Single Node Cluster Setup Environment` file.",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "655ce1b6-dc16-d38c-6ab4-4b8b9515e1ce",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443830167496,
+                       "name": "Disconnect from OVSDB Server",
+                       "description": "This restconf request ask controller to disconnect from the OVSDB server/hypervisor (`HYPERVISOR-NODE-ID`).\n",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "88edd164-76a3-c5a5-2b89-613ec89e82a4",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443827829511,
+                       "name": "Create OVS   Bridge on Hypervisor",
+                       "description": "This restconf request creates bridge (`brtest`) on the specified hypervisor running ovsdb server. Restconf URI need the node-id of the OVSDB server (hypervisor) where you need to get the bridge. You can find out the node id by using the \"GET Operational Topology\" request.\n\n       Note: these %2F ('/') in the url are not there by mistake, those are there intentionally because node-id can contain '/'.\n",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3",
+                       "rawModeData": "{\n  \"network-topology:node\": [\n        {\n          \"node-id\": \"ovsdb://{{HYPERVISOR-NODE-ID}}/bridge/brtest\",\n             \"ovsdb:bridge-name\": \"brtest\",\n             \"ovsdb:datapath-id\": \"00:00:b2:bf:48:25:f2:4b\",\n             \"ovsdb:protocol-entry\": [\n                {\n                  \"protocol\": \"ovsdb:ovsdb-bridge-protocol-openflow-13\"\n                }\n              ],\n              \"ovsdb:controller-entry\": [\n                {\n                  \"target\": \"tcp:11.11.11.11:6633\"\n                }\n              ],\n             \"ovsdb:managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb://{{HYPERVISOR-NODE-ID}}']\"\n        }\n    ]\n}"
+               },
+               {
+                       "id": "8b2d3563-28d4-91c8-5f2b-ce959c348f2d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443829913657,
+                       "name": "OVSDB Server Configuration Data",
+                       "description": "This restconf request fetch the data from `Configuration` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "8fb3e047-f00a-1dff-df9c-c548b2749c1e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443831912311,
+                       "name": "Termination Point Operational Data",
+                       "description": "This restconf request fetch data from `Operational` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "933a4c6d-cd57-1a68-012e-1d08a9c34bc6",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443831731294,
+                       "name": "OVSDB Server Operational Data",
+                       "description": "This restconf request fetch the data from `Operational` data store for given ovsdb server/hypervisor (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "folder": null,
+                       "id": "b09f9ed0-4df7-35d3-e81d-b9447313d722",
+                       "name": "OVSDB Operational Topology",
+                       "dataMode": "params",
+                       "data": [],
+                       "rawModeData": "  {\n    \"network-topology:node\": [\n          {\n              \"node-id\": \"ovsdb:node3\",\n              \"connection-info\": {\n                \"ovsdb:remote-port\": 16640,\n                \"ovsdb:remote-ip\": \"192.168.201.129\"\n              }\n          }\n      ]\n  }",
+                       "descriptionFormat": null,
+                       "description": "This restconf request fetches the topology details from the `Operational` data store that contains details about all the connected hypervisor, bridges present on the hypervisor and termination point connected to each bridge.",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "method": "GET",
+                       "pathVariables": {},
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/",
+                       "preRequestScript": "",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "b25cd26b-dd0b-369d-a246-ed1a29d0189b",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443831899373,
+                       "name": "Termination Point Configuration Data",
+                       "description": "This restconf request fetch data from `Configuration` data store for specific termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`).",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "id": "c7cb64ce-db7b-0c95-6268-bc265766a597",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F{{HYPERVISOR-NODE-ID}}%2Fbridge%2Fbrtest/termination-point/testport/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1443831952250,
+                       "name": "Delete Termination Point on Given Bridge",
+                       "description": "Delete termination point (`testport`) present on the given bridge (`HYPERVISOR-NODE-ID`). ",
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               },
+               {
+                       "folder": null,
+                       "id": "dc447867-22db-fd3a-b482-6186bd3d190a",
+                       "name": "OVSDB Configuration Topology",
+                       "dataMode": "params",
+                       "data": [],
+                       "rawModeData": null,
+                       "descriptionFormat": null,
+                       "description": "This restconf request fetch the topology details from `Configuration` data store that is pushed by user..",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+                       "method": "GET",
+                       "pathVariables": {},
+                       "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1",
+                       "preRequestScript": "",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "collectionId": "2de57d6a-ec2c-a568-c3a9-761f712622d3"
+               }
+       ]
+}
\ No newline at end of file
diff --git a/resources/commons/Qos-and-Queue-Collection-Environment-Variables.postman_environment b/resources/commons/Qos-and-Queue-Collection-Environment-Variables.postman_environment
new file mode 100644 (file)
index 0000000..9e1c5db
--- /dev/null
@@ -0,0 +1,30 @@
+{
+    "id": "06bd940f-ba4c-fd63-25ca-be8272411257",
+    "name": "Qos and Queue Collection Environment Variables",
+    "values": [
+        {
+            "key": "CONTROLLER-IP",
+            "value": "10.11.12.1",
+            "type": "text",
+            "name": "CONTROLLER-IP",
+            "enabled": true
+        },
+        {
+            "key": "HYPERVISOR-IP",
+            "value": "10.20.20.1",
+            "type": "text",
+            "name": "HYPERVISOR-IP",
+            "enabled": true
+        },
+        {
+            "key": "HYPERVISOR-OVSDB-PORT",
+            "value": "6640",
+            "type": "text",
+            "name": "HYPERVISOR-OVSDB-PORT",
+            "enabled": true
+        }
+    ],
+    "timestamp": 1454573803907,
+    "synced": false,
+    "syncedFilename": ""
+}
diff --git a/resources/commons/Qos-and-Queue-Collection.json.postman_collection b/resources/commons/Qos-and-Queue-Collection.json.postman_collection
new file mode 100644 (file)
index 0000000..d1a1de7
--- /dev/null
@@ -0,0 +1,282 @@
+{
+    "id": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+    "name": "Qos and Queue Collection",
+    "description": "This collection demonstrates how to:\n\n- create Qos and Queue entries in the OVSDB\n- add or delete Queue entries from a Qos entry\n- add or delete a Qos entry from a termination point\n- delete Qos and Queue entries",
+    "order": [
+        "8470a026-b32c-a292-49a2-a523fe831881",
+        "f1627096-7541-0c7e-e998-cd29e90f2547",
+        "78f912b9-eb93-6df1-e6bd-b175a8ee097a",
+        "17f45b0e-bdd2-6c7b-18a9-26df17d2ca20",
+        "194fbaf3-362e-54c9-2daf-c9b76f38ee57",
+        "64210287-3ec5-48f3-7ee5-447c09cc3c84",
+        "9d1dc5b0-99a2-9d31-29b6-35dcc0cf24fa",
+        "760bb52a-e621-bf9c-7053-e72a94899fa9",
+        "501cf348-4095-3826-1081-c1b3ba428f3c",
+        "61f5f3d5-1014-b211-b9bf-80a6b269d9b4",
+        "c3549a74-512b-7e93-a5e8-0219e1956c99",
+        "18641f3c-2f50-9761-c780-3f6ee358c616",
+        "fbecd07b-135b-6070-0178-71af93998104"
+    ],
+    "folders": [],
+    "timestamp": 1454567977189,
+    "owner": "",
+    "remoteLink": "",
+    "public": false,
+    "requests": [
+        {
+            "id": "17f45b0e-bdd2-6c7b-18a9-26df17d2ca20",
+            "headers": "Content-Type: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:qos-entries/QOS-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572576470,
+            "name": "Add a QpS entry to a qos-entries list",
+            "description": "This restconf request will create or update a Qos entry for the ovsdb node 'HOST1'.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"ovsdb:qos-entries\": [\n    {\n      \"qos-id\": \"QOS-1\",\n      \"qos-type\": \"ovsdb:qos-type-linux-htb\",\n      \"qos-other-config\": [\n        {\n          \"other-config-key\": \"max-rate\",\n          \"other-config-value\": \"3300000\"\n        }\n      ]\n    }\n  ]\n}"
+        },
+        {
+            "id": "18641f3c-2f50-9761-c780-3f6ee358c616",
+            "headers": "",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:queues/QUEUE-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572803238,
+            "name": "Delete a Queue entry from an ovsdb node",
+            "description": "This restconf command will delete a Qos entry.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": []
+        },
+        {
+            "id": "194fbaf3-362e-54c9-2daf-c9b76f38ee57",
+            "headers": "Content-Type: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:queues/QUEUE-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572671919,
+            "name": "Add a Queue entry to the queues list of aovsdb node 'HOST1'",
+            "description": "This restconf request will create or update a Queue entry on ovsdb node 'HOST1'.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"ovsdb:queues\": [\n    {\n      \"queue-id\": \"QUEUE-1\",\n      \"dscp\": 25,\n      \"queues-other-config\": [\n        {\n          \"queue-other-config-key\": \"max-rate\",\n          \"queue-other-config-value\": \"3600000\"\n        }\n      ]\n    }\n  ]\n}"
+        },
+        {
+            "id": "501cf348-4095-3826-1081-c1b3ba428f3c",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:qos-entries/QOS-1/queue-list/0/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572752090,
+            "name": "Delete a Queue entry from a Qos entry",
+            "description": "This restconf command will delete a queue entry from a qos entry.\n\nThe queue entry is identified by it's key value (the queue number) in\nthe queue-list which is part of the qos entry.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": []
+        },
+        {
+            "id": "61f5f3d5-1014-b211-b9bf-80a6b269d9b4",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1%2Fbridge%2Fbr-test/termination-point/testport/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572769501,
+            "name": "Add existing QoS UUID to existing termination point",
+            "description": "This restconf request will specify the UUID of a Qos entry to associate with a port.\n\nThe Qos UUID is the actual operational value of a Qos entry.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n \t  \t\t\"ovsdb:name\": \"testport\",\n \t\t\t\"tp-id\": \"testport\",\n \t\t\t\"qos\": \"4126e461-020d-497d-97b7-c8f409d1c9b9\"\n  \t\t}\n    ]\n}"
+        },
+        {
+            "id": "64210287-3ec5-48f3-7ee5-447c09cc3c84",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:qos-entries/QOS-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572690160,
+            "name": "Get Operational QoS Entry from Qos Entry list",
+            "description": "This restconf queries the operational md-sal for a specific Qos entry which was previously created by restconf (e.g. 'QOS-1').\n\nThis is useful for determining the actual UUID of the Qos entry in order to assign it to a port (i.e. termination point).",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": []
+        },
+        {
+            "id": "760bb52a-e621-bf9c-7053-e72a94899fa9",
+            "headers": "Content-Type: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:qos-entries/QOS-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572737919,
+            "name": "Add a Queue List to a QoS entry",
+            "description": "This restconf adds a Queue to a Qos entry by specifying a queue-list\nin the Qos entry which uses the operational queue UUID value.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"ovsdb:qos-entries\": [\n    {\n      \"qos-id\": \"QOS-1\",\n      \"queue-list\": [\n          {\n              \"queue-number\": \"0\",\n              \"queue-uuid\": \"8100a05f-d3fa-4e65-bbd1-6e886713f592\"\n          }\n        ]\n    }\n  ]\n}"
+        },
+        {
+            "id": "78f912b9-eb93-6df1-e6bd-b175a8ee097a",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1%2Fbridge%2Fbr-test/termination-point/testport/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454573176142,
+            "name": "Create Termination Point",
+            "description": "This restconf request creates port/interface (`testport`) and attach it to give bridge 'br-test'. \n",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n\t  \t\t\"ovsdb:name\": \"testport\",\n  \t\t\t\"tp-id\": \"testport\"\n\t\t}\n    ]\n}"
+        },
+        {
+            "id": "8470a026-b32c-a292-49a2-a523fe831881",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "POST",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454573115055,
+            "name": "POST to create OVSDB NODE HOST1",
+            "description": "Fire this Restconf request if you want to initiate the connection to ovsdb node from controller. It assumes that ovsdb node is listening for tcp connection in passive mode. To configure the ovsdb node for listening incoming connection, please fire following command at ovsdb node machine\n\n\"ovs-vsctl set-manager tcp:16640\"",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "\r\n        {\r\n            \"node\": [\r\n                {\r\n                    \"node-id\": \"ovsdb:HOST1\",\r\n                    \"connection-info\": {\r\n                        \"ovsdb:remote-ip\": \"{{HYPERVISOR-IP}}\",\r\n                        \"ovsdb:remote-port\": \"{{HYPERVISOR-OVSDB-PORT}}\"\r\n                    }\r\n                }\r\n            ]\r\n        }\r\n"
+        },
+        {
+            "id": "9d1dc5b0-99a2-9d31-29b6-35dcc0cf24fa",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/operational/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:queues/QUEUE-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "GET",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572710554,
+            "name": "Get a specific operaiontal Queue entry",
+            "description": "This restconf command will query the operational md-sal for a specified Queue entry (e.g. 'QUEUE-1') which has previously been added to the config md-sal.\n\nThis is useful in order to get the actual UUID of the Queue entry in order to assign it to a Qos entry.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": []
+        },
+        {
+            "id": "c3549a74-512b-7e93-a5e8-0219e1956c99",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\nAccept: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1%2Fbridge%2Fbr-test/termination-point/testport/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572787173,
+            "name": "Delete a QoS UUID from a termination point",
+            "description": "This restconf request will delete a Qos entry from a port (termination point).\n\nNote - this is done by doing a PUT operation on the termination port with the Qos\nentry cleared.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"network-topology:termination-point\": [\n    \t{\n \t  \t\t\"ovsdb:name\": \"testport\",\n \t\t\t\"tp-id\": \"testport\"\n  \t\t}\n    ]\n}"
+        },
+        {
+            "id": "f1627096-7541-0c7e-e998-cd29e90f2547",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1%2Fbridge%2Fbr-test",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "PUT",
+            "data": [],
+            "dataMode": "raw",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572634841,
+            "name": "Create bridge br-test on HOST1",
+            "description": "Create bridge \"br-test\" on OVSDB node \"ovsdb:HOST1\"",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": [],
+            "rawModeData": "{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"ovsdb:HOST1/bridge/br-test\",\n             \"ovsdb:bridge-name\": \"br=test\",\n             \"ovsdb:managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='ovsdb:HOST1']\"\n        }\n    ]\n}"
+        },
+        {
+            "id": "fbecd07b-135b-6070-0178-71af93998104",
+            "headers": "",
+            "url": "http://{{CONTROLLER-IP}}:8181/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:HOST1/ovsdb:qos-entries/QOS-1/",
+            "preRequestScript": "",
+            "pathVariables": {},
+            "method": "DELETE",
+            "data": [],
+            "dataMode": "params",
+            "version": 2,
+            "tests": "",
+            "currentHelper": "normal",
+            "helperAttributes": {},
+            "time": 1454572816260,
+            "name": "Delete a QoS entry from a node",
+            "description": "This restconf command will delete a Qos entry from an ovsdb node.",
+            "collectionId": "af60f3ad-e690-74ea-1a5a-2ed6f4013755",
+            "responses": []
+        }
+    ]
+}
diff --git a/resources/commons/README b/resources/commons/README
new file mode 100644 (file)
index 0000000..6aac3d3
--- /dev/null
@@ -0,0 +1,40 @@
+
+This directory contains all the associated scripts and configuration files that can be used by developers and
+administrators working on ovsdb project in general.
+
+Contents
+--------
+
+- localhost.json.postman_environment : Environment that associates address and port to localhost:8080 in templates for the collections below.
+
+- Mininet_Demo_OVSDB_OF.json.postman_collection : Collection of REST-APIs used in the Mininet demo (http://www.youtube.com/watch?v=8iWhMVlflwE)
+
+- Neutron-v2.0-LBaaS-API-Examples_July15.json.postman_collection.txt : Collection of REST-APIs to interact with LBaas pool/pool member/loadbalancer.
+
+- showOvsdbMdsal.py : Dumps mdsal related info from running ODL that is related to ovsdb and netvirt. Use 'showOvsdbMdsal.py -h' for usage
+
+- ODL-Clustering.json.postman_collection : Collection contains Restconf request to fetch clustering service related data to check the state of 3 node cluster and inventory/topology shards.
+    - Please import and load 3-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
+
+- Ovsdb-Southbound-Collection-for-Single-Node-Cluster.json.postman_collection : Collection contains Restconf request for doing CRUD operations (connection, bridge, termination point) on southbound plugin running in standalone controller.
+    - Please import and load Single-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
+
+- Ovsdb-Southbound-Collection-for-3-Node-Cluster.json.postman_collection :
+    - Please import and load 3-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
+
+
+- Single-Node-Cluster-Setup-Environment-Variables.postman_environment : Postman environment file that defines variables for Restconf request for southbound plugin running in Single controller instance
+
+- 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
+
+- Qos-and-Queue-Collection.json.postman_collection - Collection of Postman Restconf commands for doing CRUD operations on Qos and Queue entries.
+
+- readable_flows.py : script for formatting ovs-ofctl dump-flows output into a more readable format. Run w/ -h for help
+
+- pplogs.py : script for reformatting serialized nested objects in OpenDaylight log lines. Run w/ -h for help
diff --git a/resources/commons/Single-Node-Cluster-Setup-Environment-Variables.postman_environment b/resources/commons/Single-Node-Cluster-Setup-Environment-Variables.postman_environment
new file mode 100644 (file)
index 0000000..e9b9e4b
--- /dev/null
@@ -0,0 +1,37 @@
+{
+    "id": "76b6f656-7d9c-e4cd-80a4-5d6a42f07cd3",
+    "name": "Single Node Cluster Setup Environment Variables",
+    "values": [
+        {
+            "key": "CONTROLLER-IP",
+            "value": "localhost",
+            "type": "text",
+            "name": "CONTROLLER-IP",
+            "enabled": true
+        },
+        {
+            "key": "HYPERVISOR-NODE-ID",
+            "value": "192.168.201.128:16640",
+            "type": "text",
+            "name": "HYPERVISOR-NODE-ID",
+            "enabled": true
+        },
+        {
+            "key": "HYPERVISOR-IP",
+            "value": "192.168.201.128",
+            "type": "text",
+            "name": "HYPERVISOR-IP",
+            "enabled": true
+        },
+        {
+            "key": "HYPERVISOR-OVSDB-PORT",
+            "value": "16640",
+            "type": "text",
+            "name": "HYPERVISOR-OVSDB-PORT",
+            "enabled": true
+        }
+    ],
+    "timestamp": 1443832146164,
+    "synced": false,
+    "syncedFilename": ""
+}
diff --git a/resources/commons/localhost.json.postman_environment b/resources/commons/localhost.json.postman_environment
new file mode 100644 (file)
index 0000000..ce1c4f7
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "id": "855f06f8-9128-1a19-faf2-3af865f04061", 
+    "name": "localhost", 
+    "timestamp": 1396964904677, 
+    "values": [
+        {
+            "key": "controllerHost", 
+            "type": "text", 
+            "value": "localhost"
+        }, 
+        {
+            "key": "controllerPort", 
+            "type": "text", 
+            "value": "8080"
+        }
+    ]
+}
diff --git a/resources/commons/pplog.py b/resources/commons/pplog.py
new file mode 100755 (executable)
index 0000000..8cc4e3d
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+
+import string
+from sys import stdout,stdin,argv,exit
+
+if len(argv) > 1 and argv[1] in ['-h', '-?', '--h', '--help']:
+    print 'pplog.py pretty prints Open Daylight log lines, useful for lines containing large nested objects'
+    print 'Usage: Simply pipe the lines you are interested through this script'
+    exit(0)
+
+line_num = 0
+def nl():
+    global line_num
+    line_num += 1
+    stdout.write('\n' + i)
+
+for l in stdin:
+    if '|' not in l: continue
+
+    (t, level, component, cat, art, msg) = string.split(l, '|', maxsplit=5)
+
+    I = '  '
+    opener = '[{<'
+    closer = ']}>'
+    i = ''
+
+    in_ws = 1
+    is_empty_list = 0
+    last_char = ''
+    title = ''
+    title_stack = []
+
+    for c in msg:
+        if in_ws and c in ' \t': continue
+        in_ws = 0
+
+        if c in closer:
+            i = i[:-2]
+            if not is_empty_list and last_char not in closer: nl()
+            in_ws = 1
+            is_empty_list = 0
+            title = ''
+        elif is_empty_list:
+            is_empty_list = 0
+            nl()
+
+        if last_char in closer and c != ',': nl()
+
+        stdout.write(c)
+        if not c in opener: title += c
+        last_char = c
+
+        if c in closer:
+            if len(title_stack):
+                (t,ln) = title_stack.pop()
+                if (line_num - ln) > 5: stdout.write(' /* ' + t.strip() + ' */')
+
+        if c in opener:
+            i += I
+            in_ws = 1
+            is_empty_list = 1
+            if title:
+                title_stack.append((title, line_num))
+                title = ''
+
+        if c == ',':
+            nl()
+            in_ws = 1
+            title = ''
diff --git a/resources/commons/readable_flows.py b/resources/commons/readable_flows.py
new file mode 100755 (executable)
index 0000000..4390184
--- /dev/null
@@ -0,0 +1,134 @@
+#!/usr/bin/python
+
+import subprocess
+import sys
+import re
+from collections import defaultdict
+
+help ='''## readable_flows.py:
+
+This script pretty prints ovs flows created by ovsdb. Features include:
+
+1. Where possible, MACs are followed by their corresponding IP (in parenthases) and vice-versa
+2. Tunnel ids are followed by the decimal representation used by Open Daylight
+3. Counters and stats are removed so that meaningful diffs may be generated
+4. Table numbers are given together with descriptive names
+5. Flows are grouped together by priority in decending order
+
+### Usage:
+This script must be run on the OpenStack controller since it uses the
+neutron command to map MACs and IPs.
+> sudo ovs-ofctl -OOpenFlow13 dump-flows br-int | python readable_flows.py
+'''
+
+if len(sys.argv) > 1 and sys.argv[1] in ['-h', '-?', '--h', '--help']:
+    print help
+    sys.exit(0)
+
+DEFAULT_PRIO=32768
+
+TABLE_NAME = { \
+0: 'CLASSIFIER',\
+20: 'GATEWAY_RESOLVER',\
+10: 'DIRECTOR',\
+10: 'SFC_CLASSIFIER',\
+20: 'ARP_RESPONDER',\
+30: 'INBOUND_NAT',\
+40: 'EGRESS_ACL',\
+50: 'LOAD_BALANCER',\
+60: 'ROUTING',\
+70: 'ICMP_ECHO',\
+70: 'L3_FORWARDING',\
+80: 'L2_REWRITE',\
+90: 'INGRESS_ACL',\
+100: 'OUTBOUND_NAT',\
+110: 'L2_FORWARDING'}
+
+PORT_LIST_CMD = 'neutron port-list -c mac_address -c fixed_ips'.split(' ')
+
+LINE_PATTERN = '.*(?P<table>table=\d*), (?P<counters>n_packets=\d*, n_bytes=\d*), (?P<prio>priority=\d*)?,?(?P<rule>.*)'
+MAX_LINE = 30
+
+def print_rules(table, rules_by_prio):
+    print ''
+    cut = table.find('=')
+    print table.upper() + ' (' + TABLE_NAME[int(table[cut+1:])] + ')'
+
+    prios = rules_by_prio.keys()
+    prios.sort()
+    prios.reverse()
+    for prio in prios:
+        print '    priority=%i' % prio,
+        if DEFAULT_PRIO == prio: print '(DEFAULT_PRIO)'
+        else: print ''
+        for rule in rules_by_prio[prio]:
+            print_flow('        ', re.sub('actions=', 'ACTIONS=', rule))
+
+def tun_match_to_decimal(m):
+    s = m.group('num')
+    return 'tun_id=0x%s(%i)' % (s, int(s, 16))
+def tun_set_to_decimal(m):
+    s = m.group('num')
+    return '0x%s(%i)->tun_id' % (s, int(s, 16))
+
+def print_flow(indent, f):
+    print indent + f
+# WIP
+#    flow = indent + f
+#    if len(flow) <= MAX_LINE: 
+#        print flow
+#        return
+#    
+#    cut = flow.find('ACTIONS')
+#    match = flow[0:cut - 1]
+#    action = indent + indent + flow[cut:]
+#    print match
+#    while action:
+#        if len(action) <= MAX_LINE:
+#            print action
+#            break
+#        cut = action.rfind(',', 0, MAX_LINE)
+#        if cut < 2: 
+#            print action
+#            break
+#        print action[0:cut + 1]
+#        action = indent + indent + (' ' * len('ACTIONS=')) + action[cut +1:]
+
+port_list_out = subprocess.check_output(PORT_LIST_CMD)
+
+addresses = []
+for line in port_list_out.split('\n')[2:]:
+    if re.match('^$', line): continue
+    if '----' in line: continue
+    line = re.sub('^\| ', '', line)
+    line = re.sub(' *\|$', '', line)
+    (mac, fixed_ip) = line.split(' | ')
+    ip = eval(fixed_ip)['ip_address']
+    addresses.append((mac, ip))
+
+table = ''
+rules_by_prio = defaultdict(list)
+for line in sys.stdin:
+    for (mac, ip) in addresses: 
+        line = re.sub(mac, '%s(%s)' % (mac, ip), line)
+        line = re.sub('=%s(\D)' % ip, '=%s(%s)\\1' % (ip, mac), line)
+    line = re.sub('tun_id=0x(?P<num>[0-9a-fA-F]*)', tun_match_to_decimal, line)
+    line = re.sub('0x(?P<num>[0-9a-fA-F]*)->tun_id', tun_set_to_decimal, line)
+    match = re.match(LINE_PATTERN, line)
+    if not match: 
+        print '[Not a flow line?]:  ' + line,
+        continue
+
+    if  match.group('table') != table:
+        if table:
+            print_rules(table, rules_by_prio)
+            rules_by_prio = defaultdict(list)
+        table = match.group('table')
+
+    prio = DEFAULT_PRIO
+    prio_str = match.group('prio')
+    if None != prio_str: prio = int(prio_str[9:])
+    rules_by_prio[prio].append(match.group('rule'))
+
+print_rules(table, rules_by_prio)
+
diff --git a/resources/commons/showOvsdbMdsal.py b/resources/commons/showOvsdbMdsal.py
new file mode 100755 (executable)
index 0000000..3d566eb
--- /dev/null
@@ -0,0 +1,725 @@
+#!/usr/bin/env python
+
+import urllib2, base64, json, sys, optparse
+
+# globals
+CONST_DEFAULT_DEBUG=0
+options = None
+state = None
+jsonTopologyNodes = []
+jsonInventoryNodes = []
+flowInfoNodes = {}
+nodeIdToDpidCache = {}
+
+CONST_OPERATIONAL = 'operational'
+CONST_CONFIG = 'config'
+CONST_NET_TOPOLOGY = 'network-topology'
+CONST_TOPOLOGY = 'topology'
+CONST_TP_OF_INTERNAL = 65534
+CONST_ALIASES = ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot', 'golf', 'hotel', 'india', 'juliet',
+                 'kilo', 'lima', 'mike', 'november', 'oscar', 'papa', 'quebec', 'romeo', 'sierra', 'tango',
+                 'uniform', 'victor', 'whiskey', 'xray', 'yankee', 'zulu']
+
+
+class State:
+    def __init__(self):
+        self.nextAliasIndex = 0
+        self.nextAliasWrap = 0
+        self.nodeIdToAlias = {}
+
+        self.bridgeNodes = {}
+        self.ovsdbNodes = {}
+        self.ofLinks = {}
+
+    def __repr__(self):
+        return 'State {}:{} {}:{} {}:{} {}:{} {}:{}'.format(
+            'nextAliasIndex', self.nextAliasIndex,
+            'nextAliasWrap', self.nextAliasWrap,
+            'bridgeNodes_ids', self.bridgeNodes.keys(),
+            'ovsdbNodes_ids', self.ovsdbNodes.keys(),
+            'nodeIdToAlias', self.nodeIdToAlias)
+
+    def registerBridgeNode(self, bridgeNode):
+        self.bridgeNodes[bridgeNode.nodeId] = bridgeNode
+
+    def registerOvsdbNode(self, ovsdbNode):
+        self.ovsdbNodes[ovsdbNode.nodeId] = ovsdbNode
+
+    def getNextAlias(self, nodeId):
+        result = CONST_ALIASES[ self.nextAliasIndex ]
+        if self.nextAliasWrap > 0:
+            result += '_' + str(self.nextAliasWrap)
+
+        if CONST_ALIASES[ self.nextAliasIndex ] == CONST_ALIASES[-1]:
+            self.nextAliasIndex = 0
+            self.nextAliasWrap += 1
+        else:
+            self.nextAliasIndex += 1
+
+        self.nodeIdToAlias[ nodeId ] = result
+        return result
+
+# --
+
+class TerminationPoint:
+    def __init__(self, name, ofPort, tpType, mac='', ifaceId=''):
+        self.name = name
+        self.ofPort = ofPort
+        self.tpType = tpType
+        self.mac = mac
+        self.ifaceId = ifaceId
+
+    def __repr__(self):
+        result = '{} {}:{}'.format(self.name, 'of', self.ofPort)
+
+        if self.tpType != '':
+            result += ' {}:{}'.format('type', self.tpType)
+        if self.mac != '':
+            result += ' {}:{}'.format('mac', self.mac)
+        if self.ifaceId != '':
+            result += ' {}:{}'.format('ifaceId', self.ifaceId)
+
+        return '{' + result + '}'
+
+# --
+
+class BridgeNode:
+    def __init__(self, nodeId, dpId, name, controllerTarget, controllerConnected):
+        global state
+        self.alias = state.getNextAlias(nodeId)
+        self.nodeId = nodeId
+        self.dpId = dpId
+        self.name = name
+        self.controllerTarget = controllerTarget
+        self.controllerConnected = controllerConnected
+        self.tps = []
+
+    def getOpenflowName(self):
+        if self.dpId is None:
+            return self.nodeId
+        return dataPathIdToOfFormat(self.dpId)
+
+    def addTerminationPoint(self, terminationPoint):
+        self.tps.append(terminationPoint)
+
+    def __repr__(self):
+        return 'BridgeNode {}:{} {}:{} {}:{} {}:{} {}:{} {}:{} {}:{} {}:{}'.format(
+            'alias', self.alias,
+            'nodeId', self.nodeId,
+            'dpId', self.dpId,
+            'openflowName', self.getOpenflowName(),
+            'name', self.name,
+            'controllerTarget', self.controllerTarget,
+            'controllerConnected', self.controllerConnected,
+            'tps', self.tps)
+
+# --
+
+class OvsdbNode:
+    def __init__(self, nodeId, inetMgr, inetNode, otherLocalIp, ovsVersion):
+        global state
+        if inetNode != '':
+            self.alias = inetNode
+        else:
+            self.alias = nodeId
+        self.nodeId = nodeId
+        self.inetMgr = inetMgr
+        self.inetNode = inetNode
+        self.otherLocalIp = otherLocalIp
+        self.ovsVersion = ovsVersion
+
+    def __repr__(self):
+        return 'OvsdbNode {}:{} {}:{} {}:{} {}:{} {}:{} {}:{}'.format(
+            'alias', self.alias,
+            'nodeId', self.nodeId,
+            'inetMgr', self.inetMgr,
+            'inetNode', self.inetNode,
+            'otherLocalIp', self.otherLocalIp,
+            'ovsVersion', self.ovsVersion)
+
+# ======================================================================
+
+def make_it_a_string(param):
+    result = ""
+    try:
+        result = str( param )
+    except:
+        pass
+    return result
+
+# ======================================================================
+
+def printError(msg):
+    sys.stderr.write(msg)
+
+# ======================================================================
+
+def prt(msg, logLevel=0):
+    prtCommon(msg, logLevel)
+def prtLn(msg, logLevel=0):
+    prtCommon('{}\n'.format(msg), logLevel)
+def prtCommon(msg, logLevel):
+    if options.debug >= logLevel:
+        sys.stdout.write(msg)
+
+# ======================================================================
+
+def getMdsalTreeType():
+    if options.useConfigTree:
+        return CONST_CONFIG
+    return CONST_OPERATIONAL
+
+# --
+
+def grabJson(url):
+
+    try:
+        request = urllib2.Request(url)
+        # You need the replace to handle encodestring adding a trailing newline
+        # (https://docs.python.org/2/library/base64.html#base64.encodestring)
+        base64string = base64.encodestring('{}:{}'.format(options.odlUsername, options.odlPassword)).replace('\n', '')
+        request.add_header('Authorization', 'Basic {}'.format(base64string))
+        result = urllib2.urlopen(request)
+    except urllib2.URLError, e:
+        printError('Unable to send request: {}\n'.format(e))
+        sys.exit(1)
+
+    if (result.code != 200):
+        printError( '{}\n{}\n\nError: unexpected code: {}\n'.format(result.info(), result.read(), result.code) )
+        sys.exit(1)
+
+    data = json.load(result)
+    prtLn(data, 4)
+    return data
+
+# --
+
+def grabInventoryJson(mdsalTreeType):
+    global jsonInventoryNodes
+
+    url = 'http://{}:{}/restconf/{}/opendaylight-inventory:nodes/'.format(options.odlIp, options.odlPort, mdsalTreeType)
+    data = grabJson(url)
+
+    if not 'nodes' in data:
+        printError( '{}\n\nError: did not find nodes in {}'.format(data, url) )
+        sys.exit(1)
+
+    data2 = data['nodes']
+    if not 'node' in data2:
+        printError( '{}\n\nError: did not find node in {}'.format(data2, url) )
+        sys.exit(1)
+
+    jsonInventoryNodes = data2['node']
+
+# --
+
+def parseInventoryJson(mdsalTreeType):
+    global jsonInventoryNodes
+    global flowInfoNodes
+
+    for nodeDict in jsonInventoryNodes:
+        if not 'id' in nodeDict:
+            continue
+
+        bridgeOfId = nodeDict.get('id')
+        prtLn('inventory node {} has keys {}'.format(bridgeOfId, nodeDict.keys()), 3)
+
+        # locate bridge Node
+        bridgeNodeId = None
+        bridgeNode = None
+        for currNodeId in state.bridgeNodes.keys():
+            if state.bridgeNodes[currNodeId].getOpenflowName() == bridgeOfId:
+                bridgeNodeId = currNodeId
+                bridgeNode = state.bridgeNodes[currNodeId]
+                break
+
+        if bridgeNodeId is None:
+            prtLn('inventory node {}'.format(bridgeOfId), 1)
+        else:
+            prtLn('inventory node {}, aka {}, aka {}'.format(bridgeOfId, bridgeNodeId, showPrettyName(bridgeNodeId)), 1)
+
+        flowInfoNode = {}
+
+        indent = ' ' * 2
+        prtLn('{}features: {}'.format(indent, nodeDict.get('flow-node-inventory:switch-features', {})), 2)
+        prt('{}sw: {}'.format(indent, nodeDict.get('flow-node-inventory:software')), 2)
+        prt('{}hw: {}'.format(indent, nodeDict.get('flow-node-inventory:hardware')), 2)
+        prt('{}manuf: {}'.format(indent, nodeDict.get('flow-node-inventory:manufacturer')), 2)
+        prtLn('{}ip: {}'.format(indent, nodeDict.get('flow-node-inventory:ip-address')), 2)
+
+
+        for inventoryEntry in nodeDict.get('flow-node-inventory:table', []):
+            if 'id' in inventoryEntry:
+                currTableId = inventoryEntry.get('id')
+                for currFlow in inventoryEntry.get('flow', []):
+                    prtLn('{}table {}: {}'.format(indent, currTableId, currFlow.get('id')), 1)
+                    prtLn('{}{}'.format(indent * 2, currFlow), 2)
+
+                    if currTableId in flowInfoNode:
+                        flowInfoNode[ currTableId ].append( currFlow.get('id') )
+                    else:
+                        flowInfoNode[ currTableId ] = [ currFlow.get('id') ]
+
+        prtLn('', 1)
+
+        for currTableId in flowInfoNode.keys():
+            flowInfoNode[currTableId].sort()
+
+        # store info collected in flowInfoNodes
+        flowInfoNodes[bridgeOfId] = flowInfoNode
+
+# --
+
+def grabTopologyJson(mdsalTreeType):
+    global jsonTopologyNodes
+
+    url = 'http://{}:{}/restconf/{}/network-topology:network-topology/'.format(options.odlIp, options.odlPort, mdsalTreeType)
+    data = grabJson(url)
+
+    if not CONST_NET_TOPOLOGY in data:
+        printError( '{}\n\nError: did not find {} in data'.format(data, CONST_NET_TOPOLOGY) )
+        sys.exit(1)
+
+    data2 = data[CONST_NET_TOPOLOGY]
+    if not CONST_TOPOLOGY in data2:
+        printError( '{}\n\nError: did not find {} in data2'.format(data2, CONST_TOPOLOGY) )
+        sys.exit(1)
+
+    jsonTopologyNodes = data2[CONST_TOPOLOGY]
+
+# --
+
+def buildDpidCache():
+    global jsonTopologyNodes
+    global nodeIdToDpidCache
+
+    # only needed if not parsing operational tree
+    if getMdsalTreeType() == CONST_OPERATIONAL:
+        return
+
+    jsonTopologyNodesSave = jsonTopologyNodes
+    grabTopologyJson(CONST_OPERATIONAL)
+    jsonTopologyNodesLocal = jsonTopologyNodes
+    jsonTopologyNodes = jsonTopologyNodesSave
+
+    for nodeDict in jsonTopologyNodesLocal:
+        if nodeDict.get('topology-id') != 'ovsdb:1':
+            continue
+        for node in nodeDict.get('node', []):
+            if node.get('node-id') is None or node.get('ovsdb:datapath-id') is None:
+                continue
+            nodeIdToDpidCache[ node.get('node-id') ] = node.get('ovsdb:datapath-id')
+
+# --
+
+def parseTopologyJson(mdsalTreeType):
+    for nodeDict in jsonTopologyNodes:
+        if not 'topology-id' in nodeDict:
+            continue
+        prtLn('{} {} keys are: {}'.format(mdsalTreeType, nodeDict['topology-id'], nodeDict.keys()), 3)
+        if 'node' in nodeDict:
+            nodeIndex = 0
+            for currNode in nodeDict['node']:
+                parseTopologyJsonNode('', mdsalTreeType, nodeDict['topology-id'], nodeIndex, currNode)
+                nodeIndex += 1
+            prtLn('', 2)
+        if (mdsalTreeType == CONST_OPERATIONAL) and (nodeDict['topology-id'] == 'flow:1') and ('link' in nodeDict):
+            parseTopologyJsonFlowLink(nodeDict['link'])
+
+    prtLn('', 1)
+
+# --
+
+def parseTopologyJsonNode(indent, mdsalTreeType, topologyId, nodeIndex, node):
+    if node.get('node-id') is None:
+        printError( 'Warning: unexpected node: {}\n'.format(node) )
+        return
+    prt('{} {} node[{}] {} '.format(indent + mdsalTreeType, topologyId, nodeIndex, node.get('node-id')), 2)
+    if 'ovsdb:bridge-name' in node:
+        prtLn('', 2)
+        parseTopologyJsonNodeBridge(indent + '  ', mdsalTreeType, topologyId, nodeIndex, node)
+    elif 'ovsdb:connection-info' in node:
+        prtLn('', 2)
+        parseTopologyJsonNodeOvsdb(indent + '  ', mdsalTreeType, topologyId, nodeIndex, node)
+    else:
+        prtLn('keys: {}'.format(node.keys()), 2)
+
+# --
+
+def parseTopologyJsonNodeOvsdb(indent, mdsalTreeType, topologyId, nodeIndex, node):
+    keys = node.keys()
+    keys.sort()
+    for k in keys:
+        prtLn('{}{} : {}'.format(indent, k, node[k]), 2)
+
+    connectionInfoRaw = node.get('ovsdb:connection-info')
+    connectionInfo = {}
+    if type(connectionInfoRaw) is dict:
+        connectionInfo['inetMgr'] = make_it_a_string(connectionInfoRaw.get('local-ip')) + ':' + make_it_a_string(connectionInfoRaw.get('local-port'))
+        connectionInfo['inetNode'] = make_it_a_string(connectionInfoRaw.get('remote-ip')) + ':' + make_it_a_string(connectionInfoRaw.get('remote-port'))
+    otherConfigsRaw = node.get('ovsdb:openvswitch-other-configs')
+    otherLocalIp = ''
+    if type(otherConfigsRaw) is list:
+        for currOtherConfig in otherConfigsRaw:
+            if type(currOtherConfig) is dict and \
+                    currOtherConfig.get('other-config-key') == 'local_ip':
+                otherLocalIp = currOtherConfig.get('other-config-value')
+                break
+
+    ovsdbNode = OvsdbNode(node.get('node-id'), connectionInfo.get('inetMgr'), connectionInfo.get('inetNode'), otherLocalIp, node.get('ovsdb:ovs-version'))
+    state.registerOvsdbNode(ovsdbNode)
+    prtLn('Added {}'.format(ovsdbNode), 1)
+
+# --
+
+def parseTopologyJsonNodeBridge(indent, mdsalTreeType, topologyId, nodeIndex, node):
+
+    controllerTarget = None
+    controllerConnected = None
+    controllerEntries = node.get('ovsdb:controller-entry')
+    if type(controllerEntries) is list:
+        for currControllerEntry in controllerEntries:
+            if type(currControllerEntry) is dict:
+                controllerTarget = currControllerEntry.get('target')
+                controllerConnected = currControllerEntry.get('is-connected')
+                break
+
+    nodeId = node.get('node-id')
+    dpId = node.get('ovsdb:datapath-id', nodeIdToDpidCache.get(nodeId))
+    bridgeNode = BridgeNode(nodeId, dpId, node.get('ovsdb:bridge-name'), controllerTarget, controllerConnected)
+
+    keys = node.keys()
+    keys.sort()
+    for k in keys:
+        if k == 'termination-point' and len(node[k]) > 0:
+            tpIndex = 0
+            for tp in node[k]:
+                terminationPoint = parseTopologyJsonNodeBridgeTerminationPoint('%stermination-point[%d] :' % (indent, tpIndex), mdsalTreeType, topologyId, nodeIndex, node, tp)
+
+                # skip boring tps
+                if terminationPoint.ofPort == CONST_TP_OF_INTERNAL and \
+                        (terminationPoint.name == 'br-ex' or terminationPoint.name == 'br-int'):
+                    pass
+                else:
+                    bridgeNode.addTerminationPoint(terminationPoint)
+
+                tpIndex += 1
+        else:
+            prtLn('{}{} : {}'.format(indent, k, node[k]), 2)
+
+    state.registerBridgeNode(bridgeNode)
+    prtLn('Added {}'.format(bridgeNode), 1)
+
+
+# --
+
+def parseTopologyJsonNodeBridgeTerminationPoint(indent, mdsalTreeType, topologyId, nodeIndex, node, tp):
+    attachedMac = ''
+    ifaceId = ''
+
+    keys = tp.keys()
+    keys.sort()
+    for k in keys:
+        if (k == 'ovsdb:port-external-ids' or k == 'ovsdb:interface-external-ids') and len(tp[k]) > 0:
+            extIdIndex = 0
+            for extId in tp[k]:
+                prtLn('{} {}[{}] {} : {}'.format(indent, k, extIdIndex, extId.get('external-id-key'), extId.get('external-id-value')), 2)
+                extIdIndex += 1
+
+                if extId.get('external-id-key') == 'attached-mac':
+                    attachedMac = extId.get('external-id-value')
+                if extId.get('external-id-key') == 'iface-id':
+                    ifaceId = extId.get('external-id-value')
+        else:
+            prtLn('{} {} : {}'.format(indent, k, tp[k]), 2)
+
+    return TerminationPoint(tp.get('ovsdb:name'),
+                            tp.get('ovsdb:ofport'),
+                            tp.get('ovsdb:interface-type', '').split('-')[-1],
+                            attachedMac, ifaceId)
+
+# --
+
+def parseTopologyJsonFlowLink(link):
+    linkCount = 0
+    spc = ' ' * 2
+    for currLinkDict in link:
+        linkCount += 1
+        linkId = currLinkDict.get('link-id')
+        linkDest = currLinkDict.get('destination', {}).get('dest-tp')
+        linkSrc = currLinkDict.get('source', {}).get('source-tp')
+
+        linkDestNode = currLinkDict.get('destination', {}).get('dest-node')
+        linkSrcNode = currLinkDict.get('source', {}).get('source-node')
+        prtLn('{} {} {} => {}:{} -> {}:{}'.format(spc, linkCount, linkId, linkSrcNode, linkSrc.split(':')[-1], linkDestNode, linkDest.split(':')[-1]), 3)
+
+        if linkId != linkSrc:
+            printError('Warning: ignoring link with unexpected id: %s != %s\n' % (linkId, linkSrc))
+            continue
+        else:
+            state.ofLinks[linkSrc] = linkDest
+
+# --
+
+def showPrettyNamesMap():
+    spc = ' ' * 2
+    if not options.useAlias or len(state.bridgeNodes) == 0:
+        return
+
+    prtLn('aliasMap:', 0)
+    resultMap = {}
+    for bridge in state.bridgeNodes.values():
+        resultMap[ bridge.alias ] = '{0: <25} {1: <7} {2}'.format(bridge.getOpenflowName(), bridge.name, bridge.dpId)
+
+    for resultMapKey in sorted(resultMap):
+        prtLn('{0}{1: <10} ->  {2}'.format(spc, resultMapKey, resultMap[resultMapKey]), 0)
+    prtLn('', 0)
+
+# --
+
+def showNodesPretty():
+    if len(state.ovsdbNodes) == 0:
+        showBridgeOnlyNodes()
+        return
+
+    aliasDict = { state.ovsdbNodes[nodeId].alias : nodeId for nodeId in state.ovsdbNodes.keys() }
+    aliasDictKeys = aliasDict.keys()
+    aliasDictKeys.sort()
+    for ovsAlias in aliasDictKeys:
+        ovsdbNode = state.ovsdbNodes[ aliasDict[ovsAlias] ]
+
+        prt('ovsdbNode:{} mgr:{} version:{}'.format(ovsAlias, ovsdbNode.inetMgr, ovsdbNode.ovsVersion), 0)
+        if ovsdbNode.inetNode.split(':')[0] != ovsdbNode.otherLocalIp:
+            prt(' **localIp:{}'.format(ovsdbNode.otherLocalIp), 0)
+        prtLn('', 0)
+        showPrettyBridgeNodes('  ', getNodeBridgeIds(ovsdbNode.nodeId), ovsdbNode)
+    showBridgeOnlyNodes(True)
+    prtLn('', 0)
+
+# --
+
+def showFlowInfoPretty():
+    global flowInfoNodes
+    spc = ' ' * 2
+
+    if not options.showFlows:
+        return
+
+    if len(flowInfoNodes) == 0:
+        prtLn('no flowInfo found\n', 0)
+        return
+
+    # translate flowKeys (openflow:123124) into their alias format
+    # then sort it and translate back, so we list them in the order
+    flowInfoNodeKeysDict = {}
+    for flowInfoNodeKey in flowInfoNodes.keys():
+        flowInfoNodeKeysDict[ showPrettyName(flowInfoNodeKey) ] = flowInfoNodeKey
+    flowInfoNodeKeysKeys = flowInfoNodeKeysDict.keys()
+    flowInfoNodeKeysKeys.sort()
+
+    flowInfoNodesKeys = [ flowInfoNodeKeysDict[ x ] for x in flowInfoNodeKeysKeys ]
+
+    nodeIdToDpidCacheReverse = {dataPathIdToOfFormat(v): k for k, v in nodeIdToDpidCache.items()}
+    nodesVisited = 0
+    for flowInfoNodeKey in flowInfoNodesKeys:
+        if nodesVisited > 0: prtLn('', 0)
+
+        nodeName = showPrettyName(flowInfoNodeKey)
+        if nodeName == flowInfoNodeKey:
+            nodeName += '  ( {} )'.format( nodeIdToDpidCacheReverse.get(flowInfoNodeKey, 'node_not_in_topology') )
+
+        prtLn('{} tree flows at {}'.format(getMdsalTreeType(), nodeName), 0)
+        flowInfoNode = flowInfoNodes[flowInfoNodeKey]
+        flowInfoTables = flowInfoNode.keys()
+        flowInfoTables.sort()
+        for flowInfoTable in flowInfoTables:
+            for rule in flowInfoNode[flowInfoTable]:
+                prtLn('{}table {}: {}'.format(spc, flowInfoTable, rule), 0)
+        nodesVisited += 1
+
+    prtLn('', 0)
+
+# --
+
+def getNodeBridgeIds(nodeIdFilter = None):
+    resultMap = {}
+    for bridge in state.bridgeNodes.values():
+        if nodeIdFilter is None or nodeIdFilter in bridge.nodeId:
+            resultMap[ bridge.alias ] = bridge.nodeId
+    resultMapKeys = resultMap.keys()
+    resultMapKeys.sort()
+    return [ resultMap[x] for x in resultMapKeys ]
+
+# --
+
+def showPrettyBridgeNodes(indent, bridgeNodeIds, ovsdbNode = None):
+    if bridgeNodeIds is None:
+        return
+
+    for nodeId in bridgeNodeIds:
+        bridgeNode = state.bridgeNodes[nodeId]
+        prt('{}{}:{}'.format(indent, showPrettyName(nodeId), bridgeNode.name), 0)
+
+        if ovsdbNode is None or \
+                bridgeNode.controllerTarget is None or \
+                bridgeNode.controllerTarget == '' or \
+                ovsdbNode.inetMgr.split(':')[0] != bridgeNode.controllerTarget.split(':')[-2] or \
+                bridgeNode.controllerConnected != True:
+            prt(' controller:{}'.format(bridgeNode.controllerTarget), 0)
+            prt(' connected:{}'.format(bridgeNode.controllerConnected), 0)
+        prtLn('', 0)
+        showPrettyTerminationPoints(indent + '  ', bridgeNode.tps)
+
+# --
+
+def showBridgeOnlyNodes(showOrphansOnly = False):
+    if len(state.bridgeNodes) == 0:
+        return
+
+    # group bridges by nodeId prefix
+    resultMap = {}
+    for bridge in state.bridgeNodes.values():
+        nodePrefix = bridge.nodeId.split('/bridge/')[0]
+
+        if showOrphansOnly and nodePrefix in state.ovsdbNodes:
+            continue
+
+        if nodePrefix in resultMap:
+            resultMap[nodePrefix][bridge.alias] = bridge.nodeId
+        else:
+            resultMap[nodePrefix] = { bridge.alias: bridge.nodeId }
+    resultMapKeys = resultMap.keys()
+    resultMapKeys.sort()
+
+    if len(resultMapKeys) == 0:
+        return  #noop
+
+    for nodePrefix in resultMapKeys:
+        nodePrefixEntriesKeys = resultMap[nodePrefix].keys()
+        nodePrefixEntriesKeys.sort()
+        # prtLn('Bridges in {}: {}'.format(nodePrefix, nodePrefixEntriesKeys), 0)
+        prtLn('Bridges in {}'.format(nodePrefix), 0)
+        nodeIds = [ resultMap[nodePrefix][nodePrefixEntry] for nodePrefixEntry in nodePrefixEntriesKeys ]
+        showPrettyBridgeNodes('  ', nodeIds)
+
+    prtLn('', 0)
+
+# --
+
+def showPrettyTerminationPoints(indent, tps):
+
+    tpsDict = {}
+    for tp in tps:
+        tpsDict[ tp.ofPort ] = tp
+
+    tpDictKeys = tpsDict.keys()
+    tpDictKeys.sort()
+    for tpKey in tpDictKeys:
+        tp = tpsDict[tpKey]
+        prt('{}of:{} {}'.format(indent, tp.ofPort, tp.name), 0)
+        if tp.mac != '':
+            prt(' {}:{}'.format('mac', tp.mac), 0)
+        if tp.ifaceId != '':
+            prt(' {}:{}'.format('ifaceId', tp.ifaceId), 0)
+
+        prtLn('', 0)
+
+# --
+
+def dataPathIdToOfFormat(dpId):
+    return 'openflow:' + str( int('0x' + dpId.replace(':',''), 16) )
+
+# --
+
+def showPrettyName(name):
+    if not options.useAlias:
+        return name
+
+    # handle both openflow:138604958315853:2 and openflow:138604958315853 (aka dpid)
+    # also handle ovsdb://uuid/5c72ec51-1e71-4a04-ab0b-b044fb5f4dc0/bridge/br-int  (aka nodeId)
+    #
+    nameSplit = name.split(':')
+    ofName = ':'.join(nameSplit[:2])
+    ofPart = ''
+    if len(nameSplit) > 2:
+        ofPart = ':' + ':'.join(nameSplit[2:])
+
+    for bridge in state.bridgeNodes.values():
+        if bridge.getOpenflowName() == ofName or bridge.nodeId == name:
+            return '{}{}'.format(bridge.alias, ofPart)
+
+    # not found, return paramIn
+    return name
+
+# --
+
+def showOfLinks():
+    spc = ' ' * 2
+    ofLinksKeys = state.ofLinks.keys()
+    ofLinksKeys.sort()
+    ofLinksKeysVisited = set()
+
+    if len(ofLinksKeys) == 0:
+        # prtLn('no ofLinks found\n', 0)
+        return
+
+    prtLn('ofLinks (discover via lldp):', 0)
+    for ofLinkKey in ofLinksKeys:
+        if ofLinkKey in ofLinksKeysVisited:
+            continue
+        if state.ofLinks.get( state.ofLinks[ofLinkKey] ) == ofLinkKey:
+            prtLn('{}{} <-> {}'.format(spc, showPrettyName(ofLinkKey), showPrettyName(state.ofLinks[ofLinkKey])), 0)
+            ofLinksKeysVisited.add(state.ofLinks[ofLinkKey])
+        else:
+            prtLn('{}{} -> {}'.format(spc, showPrettyName(ofLinkKey), showPrettyName(state.ofLinks[ofLinkKey])), 0)
+        ofLinksKeysVisited.add(ofLinkKey)
+    prtLn('', 0)
+
+# --
+
+def parseArgv():
+    global options
+
+    parser = optparse.OptionParser(version="0.1")
+    parser.add_option("-d", "--debug", action="count", dest="debug", default=CONST_DEFAULT_DEBUG,
+                      help="Verbosity. Can be provided multiple times for more debug.")
+    parser.add_option("-n", "--noalias", action="store_false", dest="useAlias", default=True,
+                      help="Do not map nodeId of bridges to an alias")
+    parser.add_option("-i", "--ip", action="store", type="string", dest="odlIp", default="localhost",
+                      help="opendaylights ip address")
+    parser.add_option("-t", "--port", action="store", type="string", dest="odlPort", default="8080",
+                      help="opendaylights listening tcp port on restconf northbound")
+    parser.add_option("-u", "--user", action="store", type="string", dest="odlUsername", default="admin",
+                      help="opendaylight restconf username")
+    parser.add_option("-p", "--password", action="store", type="string", dest="odlPassword", default="admin",
+                      help="opendaylight restconf password")
+    parser.add_option("-c", "--config", action="store_true", dest="useConfigTree", default=False,
+                      help="parse mdsal restconf config tree instead of operational tree")
+    parser.add_option("-f", "--hide-flows", action="store_false", dest="showFlows", default=True,
+                      help="hide flows")
+
+    (options, args) = parser.parse_args(sys.argv)
+    prtLn('argv options:{} args:{}'.format(options, args), 2)
+
+# --
+
+def doMain():
+    global state
+
+    state = State()
+    parseArgv()
+    buildDpidCache()
+    grabTopologyJson(getMdsalTreeType())
+    grabInventoryJson(getMdsalTreeType())
+    parseTopologyJson(getMdsalTreeType())
+    parseInventoryJson(getMdsalTreeType())
+    showPrettyNamesMap()
+    showNodesPretty()
+    showFlowInfoPretty()
+    showOfLinks()
+
+# --
+
+if __name__ == "__main__":
+    doMain()
+    sys.exit(0)
diff --git a/resources/demo/netvirtsfc-env/README.md b/resources/demo/netvirtsfc-env/README.md
new file mode 100755 (executable)
index 0000000..e993674
--- /dev/null
@@ -0,0 +1,147 @@
+#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
new file mode 100644 (file)
index 0000000..3811901
--- /dev/null
@@ -0,0 +1,34 @@
+
+# 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
new file mode 100644 (file)
index 0000000..a11d562
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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 <<EOL > /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
new file mode 100755 (executable)
index 0000000..0e08495
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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
new file mode 100755 (executable)
index 0000000..3c494a3
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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
new file mode 100755 (executable)
index 0000000..95a9f0f
--- /dev/null
@@ -0,0 +1,3 @@
+#!/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
new file mode 100755 (executable)
index 0000000..c3355e6
--- /dev/null
@@ -0,0 +1,346 @@
+#!/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
new file mode 100755 (executable)
index 0000000..a920344
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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
new file mode 100755 (executable)
index 0000000..fa27cc2
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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
new file mode 100755 (executable)
index 0000000..dac82d8
--- /dev/null
@@ -0,0 +1,9 @@
+#!/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
new file mode 100755 (executable)
index 0000000..1b8ca93
--- /dev/null
@@ -0,0 +1,19 @@
+#!/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
new file mode 100644 (file)
index 0000000..5ccf548
Binary files /dev/null and b/resources/demo/netvirtsfc-env/images/asymmetric-sfc-demo.png differ
diff --git a/resources/demo/netvirtsfc-env/infrastructure_launch.py b/resources/demo/netvirtsfc-env/infrastructure_launch.py
new file mode 100755 (executable)
index 0000000..81ab714
--- /dev/null
@@ -0,0 +1,167 @@
+#!/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
new file mode 100755 (executable)
index 0000000..b19835b
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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 <hostinterface> <guest> <ipaddr>/<subnet> <broadcast> <gateway> [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
new file mode 100755 (executable)
index 0000000..cb5569d
--- /dev/null
@@ -0,0 +1,4 @@
+#!/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
new file mode 100755 (executable)
index 0000000..07ff657
--- /dev/null
@@ -0,0 +1,11 @@
+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
new file mode 100755 (executable)
index 0000000..a70544a
--- /dev/null
@@ -0,0 +1,141 @@
+#!/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
new file mode 100755 (executable)
index 0000000..b9f7e7b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+ovsdbversion="1.2.1-SNAPSHOT"
+
+# Attempt to keep l2switch from monkeying with the flows
+#sed -i 's/<is-proactive-flood-mode>true<\/is-proactive-flood-mode>/<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/<is-install-lldp-flow>true<\/is-install-lldp-flow>/<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/<of13provider>[a-z]\{1,\}<\/of13provider>/<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
new file mode 100755 (executable)
index 0000000..c0251af
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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
new file mode 100755 (executable)
index 0000000..ca2426e
--- /dev/null
@@ -0,0 +1 @@
+ovs-appctl ofproto/trace $1
diff --git a/resources/demo/netvirtsfc-env/utils/hosts b/resources/demo/netvirtsfc-env/utils/hosts
new file mode 100644 (file)
index 0000000..1ed1fb4
--- /dev/null
@@ -0,0 +1,12 @@
+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
new file mode 100755 (executable)
index 0000000..ed9050a
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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
new file mode 100755 (executable)
index 0000000..eee7ef1
--- /dev/null
@@ -0,0 +1,11 @@
+#!/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
new file mode 100755 (executable)
index 0000000..3974b38
--- /dev/null
@@ -0,0 +1,12 @@
+#!/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/openstack/DevStack.json.postman_collection b/resources/openstack/DevStack.json.postman_collection
new file mode 100644 (file)
index 0000000..47918f8
--- /dev/null
@@ -0,0 +1 @@
+{"id":"8ced994a-307c-ff92-8fff-b6ab521e1aec","name":"DevStack","description":"Scripts used in devstack testing","order":["534300ea-fca8-4c8a-769c-227b3129d3a0","d1a99582-dff6-26ae-6416-89bd3788dd47"],"folders":[],"timestamp":1385264376897,"synced":false,"requests":[{"collectionId":"8ced994a-307c-ff92-8fff-b6ab521e1aec","id":"534300ea-fca8-4c8a-769c-227b3129d3a0","name":"Connect to ovsdb-server running in Devstack Controller","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/connectionmanager/node/STACK1/address/192.168.56.101/port/6640/","method":"PUT","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\n","data":[],"dataMode":"params","timestamp":0,"responses":[],"version":2,"synced":false},{"collectionId":"8ced994a-307c-ff92-8fff-b6ab521e1aec","id":"d1a99582-dff6-26ae-6416-89bd3788dd47","name":"Connect to ovsdb-server running in Devstack compute","description":"","url":"http://{{controllerHost}}:{{controllerPort}}/controller/nb/v2/connectionmanager/node/STACK2/address/192.168.56.102/port/6640/","method":"PUT","headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\n","data":[],"dataMode":"params","timestamp":0,"responses":[],"version":2,"synced":false}]}
\ No newline at end of file
diff --git a/resources/openstack/Neutron-v2.0-API-Examples.json.postman_collection b/resources/openstack/Neutron-v2.0-API-Examples.json.postman_collection
new file mode 100644 (file)
index 0000000..b30e200
--- /dev/null
@@ -0,0 +1,1021 @@
+{
+       "id": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+       "name": "Neutron-v2.0-API-Examples",
+       "description": "A collection of OpenStack Neutron v2.0 REST API calls for Postman. Import these into Postman and use to validate the OpenDaylight Neutron NB-API interfaces.\n\nResources:\n- Postman http://www.getpostman.com\n- Neutron v2.0 https://wiki.openstack.org/wiki/Neutron/APIv2-specification",
+       "order": [
+               "747f9a54-e64f-57f6-ce6d-8ad358817696"
+       ],
+       "folders": [
+               {
+                       "id": "126c18b5-94b8-689b-c932-371cddb543f2",
+                       "name": "Neutron Firewall as a Service (FWaaS)",
+                       "description": "",
+                       "order": [
+                               "747f9a54-e64f-57f6-ce6d-8ad358817696",
+                               "7ef5413c-7f22-ac12-5444-f9be6a7c029e",
+                               "ed8face9-6585-8a9b-9e09-870e3a5e5546",
+                               "09bcfbe4-b01a-3615-820f-7fc3a2261e05",
+                               "a1efd833-3d79-1621-9aa5-61b0fecec94a",
+                               "a183a8b3-bddb-dc04-ae73-3beb11af4d04"
+                       ],
+                       "collection_name": "Neutron-v2.0-API-Examples",
+                       "collection_id": "bd9b142f-e3ad-452d-f088-eed1b741b937"
+               },
+               {
+                       "id": "770b37d2-85c3-d373-28de-4913009875f8",
+                       "name": "Neutron Load Balancer as a Service (LBaaS)",
+                       "description": "",
+                       "order": [
+                               "4ecb4af3-e10b-6710-bbcf-af2b80a8887f",
+                               "8c4d8a07-64c5-f821-4799-d528f01e88cc",
+                               "a483b6c9-2f07-f59e-effa-883591fee938",
+                               "5c73f0bc-7502-26e1-42e1-c918ecbd56ae",
+                               "b6761938-4918-6120-c181-33f5d8c9f1a5",
+                               "a896a2b2-3273-2ff0-c801-1cbecdc2cc85",
+                               "033e8332-94d9-b9cd-6b2d-4adb37dd8a9c",
+                               "c9f46dde-6b6d-0def-ae83-7885be0dbf87"
+                       ],
+                       "collection_name": "Neutron-v2.0-API-Examples",
+                       "collection_id": "bd9b142f-e3ad-452d-f088-eed1b741b937"
+               },
+               {
+                       "id": "7b2236c6-cd5b-1bc0-fd02-737efb4995dc",
+                       "name": "Neutron Port Security",
+                       "description": "",
+                       "order": [
+                               "f9de4b7d-8b08-fb14-d557-3cf81d7465f4",
+                               "9fe0d840-dcd3-6d3e-d410-e88538858e3a",
+                               "c9cc2212-1f16-ead6-5dc0-073aed1e2c61",
+                               "1387de10-9981-2ecb-32b8-4cc4806894cf",
+                               "56d38607-d1dc-adba-a3fd-7e4d63e6c75d",
+                               "4f72cdab-70f1-dba9-3986-3305c7ef18c8",
+                               "f01b7f99-0aeb-739f-eb4a-cd467320b85c"
+                       ],
+                       "collection_name": "Neutron-v2.0-API-Examples",
+                       "collection_id": "bd9b142f-e3ad-452d-f088-eed1b741b937"
+               },
+               {
+                       "id": "2ad17469-46b9-3b8e-0686-b361e092c755",
+                       "name": "Neutron Port, Network, Subnet, CRUD",
+                       "description": "",
+                       "order": [
+                               "55aab7d7-6159-c4fb-5b3f-42cbb55c4e7b",
+                               "1215e515-a4ff-7d7e-acbf-905c6706db86",
+                               "9d37dcb1-e1e6-9fae-01ea-cc30aeb874a6",
+                               "78eb34fc-1933-c019-bf7f-fdae9652f9cd",
+                               "94c4ed8e-8e48-2384-38b0-5497fe05ba7a",
+                               "83af7fdb-53b2-3818-006e-bb52b8304e6a",
+                               "ef3c7339-ba4d-124d-7e1f-67d9ab638277"
+                       ],
+                       "collection_name": "Neutron-v2.0-API-Examples",
+                       "collection_id": "bd9b142f-e3ad-452d-f088-eed1b741b937"
+               },
+               {
+                       "id": "f080abc2-2590-5b74-dd6d-3acc19090bce",
+                       "name": "Neutron Router, CRUD",
+                       "description": "",
+                       "order": [
+                               "a209e7b3-9d00-bd9a-b920-39fd577b52c6",
+                               "5542be98-775d-3a61-2709-59b0d692e453",
+                               "828984bd-db02-aec4-d154-cd8e7f2b559b",
+                               "ec4ca40c-be6e-d76b-81a3-8fd328180132",
+                               "9e7c7b50-1580-c7e2-70a0-445b42e218b1",
+                               "84b71139-7a9a-2f27-d0f6-745b8dbe876f",
+                               "41940ad7-cec0-99c5-204a-eceab3aa7b78",
+                               "e6b74bbb-cf2f-9eec-e530-537f1c065f8e",
+                               "7370da7f-234e-3f7a-ed12-e384131d886d",
+                               "7b61cef4-38da-3a4e-c968-38a98f31e85d",
+                               "ba73a129-a385-0554-7e6c-dc687ea78bbb",
+                               "62417324-b809-5a83-d3f3-cd4fef07bbe5",
+                               "70ae1c0d-5b58-0c2a-5b62-d186a74059ab",
+                               "846c29b1-07fd-3d7d-f997-845ba91232b9"
+                       ],
+                       "collection_name": "Neutron-v2.0-API-Examples",
+                       "collection_id": "bd9b142f-e3ad-452d-f088-eed1b741b937"
+               }
+       ],
+       "timestamp": 1394529177458,
+       "synced": false,
+       "requests": [
+               {
+                       "id": "033e8332-94d9-b9cd-6b2d-4adb37dd8a9c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/healthmonitors/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "POST",
+                       "data": "{\n   \"healthmonitor\":{\n      \"id\":\"f3eeab00-8367-4524-b662-55e64d4cacb5\",\n      \"tenant_id\":\"453105b9-1754-413f-aab1-55f1af620750\",\n      \"type\":\"HTTP\",\n      \"delay\":20,\n      \"timeout\":10,\n      \"max_retries\":5,\n      \"http_method\":\"GET\",\n      \"url_path\":\"/check\",\n      \"expected_codes\":\"200-299\",\n      \"admin_state_up\":true,\n      \"status\":\"ACTIVE\"\n   }\n}",
+                       "dataMode": "raw",
+                       "name": "Post Add Neutron Load Balancer HealthMonitor",
+                       "description": "Example posting of a Neutron v2.0  Load Balancer HealthMonitor.",
+                       "descriptionFormat": "html",
+                       "time": 1407147940644,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "09bcfbe4-b01a-3615-820f-7fc3a2261e05",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_rules",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139182979,
+                       "name": "Get Neutron FWaaS Rules",
+                       "description": "Return a list of Neutron v2.0 API FWaaS rules.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "0f889e0b-f37f-a82f-06b3-5db88c96f8f7",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers/",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139182979,
+                       "name": "Get Neutron LBaaS ",
+                       "description": "Return a Neutron v2.0  Load Balancer (LBaaS).",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "1215e515-a4ff-7d7e-acbf-905c6706db86",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/networks/",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139794797,
+                       "name": "Get Neutron Networks",
+                       "description": "Return a list of Neutron v2.0 Networks",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "1387de10-9981-2ecb-32b8-4cc4806894cf",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-groups/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"security_group\":{\n      \"name\":\"TCP Port Range\",\n      \"description\":\"Example TCP port range security group\",\n     \"tenant_id\":\"3B82FF05-72A2-413E-B051-222222222222\",\n     \"id\":\"C9F5924D-4D08-4819-BFC4-444444444444\"\n   }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401137715163,
+                       "name": "Post Add Security Group Port Range",
+                       "description": "Example Neutron v2.0  Add Security Group with a TCP Port Range",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "1fdc36bb-a2bd-23df-9ddf-b47fc9231d96",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139182979,
+                       "name": "Get Neutron LBaaS  copy",
+                       "description": "Return a Neutron v2.0  Load Balancer (LBaaS).",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "36de75f0-4f3c-ca9e-adf5-155349f4b766",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/networks/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"networks\":[\n      {\n         \"status\":\"ACTIVE\",\n         \"subnets\":[\n         ],\n         \"name\":\"sample_network_89\",\n         \"provider:physical_network\":null,\n   \"admin_state_up\":false,\n   \"tenant_id\":\"60cd4f6dbc5f499982a284e7b83b5be3\",\n   \"provider:network_type\":\"local\",\n   \"router:external\":false,\n   \"shared\":false,\n   \"id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n   \"provider:segmentation_id\":89\n}\n  ]\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139810802,
+                       "name": "Post Add Neutron Network copy",
+                       "description": "Post a list of Neutron v2.0 Networks",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "3a98617b-1cf1-e97f-ba30-1d4ad2f4a29e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_rules",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139182979,
+                       "name": "Get Neutron FWaaS Rules copy",
+                       "description": "Return a list of Neutron v2.0 API FWaaS rules.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "id": "41940ad7-cec0-99c5-204a-eceab3aa7b78",
+                       "name": "Delete Neutron Router ",
+                       "description": "Delete Neutron Router",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers/8604a0de-7f6b-409a-a47c-a1cc7bc77b2e/",
+                       "method": "DELETE",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": "",
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1407866898433,
+                       "synced": false
+               },
+               {
+                       "id": "4ecb4af3-e10b-6710-bbcf-af2b80a8887f",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "POST",
+                       "data": "{\n  \"loadbalancer\": {\n    \"id\": \"8992a43f-83af-4b49-9afd-c2bfbd82d7d7\",\n    \"name\": \"Example LB\",\n    \"description\": \"A very simple example load balancer.\",\n    \"vip_address\": \"1.2.3.4\",\n    \"vip_subnet_id\": \"SUBNET_ID\",\n    \"tenant_id\": \"7725fe12-1c14-4f45-ba8e-44bf01763578\",\n    \"status\": \"PENDING_CREATE\"\n  }\n}",
+                       "dataMode": "raw",
+                       "name": "Post Add Neutron Load Balancer",
+                       "description": "Example posting of a Neutron v2.0  Load Balancer (LBaaS).",
+                       "descriptionFormat": "html",
+                       "time": 1407147822865,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "4f72cdab-70f1-dba9-3986-3305c7ef18c8",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-groups/",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139154340,
+                       "name": "Get Neutron Security Groups",
+                       "description": "Return a list of Neutron v2.0 API security groups.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "5542be98-775d-3a61-2709-59b0d692e453",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"subnet\": {\n    \"name\": \"\",\n    \"enable_dhcp\": true,\n    \"network_id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f6\",\n    \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\",\n    \"dns_nameservers\": [\n    ],\n    \"allocation_pools\": [\n      {\n        \"start\": \"192.168.200.2\",\n        \"end\": \"192.168.200.254\"\n      }\n    ],\n    \"host_routes\": [\n    ],\n    \"ip_version\": 4,\n    \"gateway_ip\": \"192.168.200.1\",\n    \"cidr\": \"192.168.200.0/24\",\n    \"id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17127\"\n  }\n}\n",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407944320612,
+                       "name": "Post Add Neutron Subnets to external Network",
+                       "description": "Post a list of Neutron v2.0 Subnets",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "55aab7d7-6159-c4fb-5b3f-42cbb55c4e7b",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/networks/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"networks\":[\n      {\n         \"status\":\"ACTIVE\",\n         \"subnets\":[\n         ],\n         \"name\":\"sample_network_89\",\n         \"provider:physical_network\":null,\n   \"admin_state_up\":false,\n   \"tenant_id\":\"60cd4f6dbc5f499982a284e7b83b5be3\",\n   \"provider:network_type\":\"local\",\n   \"router:external\":false,\n   \"shared\":false,\n   \"id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n   \"provider:segmentation_id\":89\n}\n  ]\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139810802,
+                       "name": "Post Add Neutron Network",
+                       "description": "Post a list of Neutron v2.0 Networks",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "56d38607-d1dc-adba-a3fd-7e4d63e6c75d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-group-rules/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"security_group_rule\":{\n      \"id\":\"A9F6424D-4D08-4819-BFC4-333333333333\",\n      \"direction\":\"ingress\",\n      \"port_range_min\":\"5000\",\n      \"ethertype\":\"IPv4\",\n      \"port_range_max\":\"6000\",\n      \"protocol\":\"tcp\",\n      \"remote_ip_prefix\":\"172.16.10.0/24\",\n      \"remote_group_id\":\"85cc3048-abc3-43cc-89b3-377341426ac5\",\n      \"security_group_id\":\"C9F5924D-4D08-4819-BFC4-444444444444\",\n      \"tenant_id\":\"3B82FF05-72A2-413E-B051-222222222222\"\n   }\n}\n",
+                       "dataMode": "raw",
+                       "name": "Post Add Security Rule Port Range",
+                       "description": "Neutron v2.0 Add a Neutron Security Rule with a TCP Port Range.",
+                       "descriptionFormat": "html",
+                       "time": 1401138106104,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "5c73f0bc-7502-26e1-42e1-c918ecbd56ae",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/listeners/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Get Load Balancer  Listeners",
+                       "description": "Return a Neutron v2.0  Load Balancer Listeners.",
+                       "descriptionFormat": "html",
+                       "time": 1407147923753,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "5ddf6ac3-a30f-0f73-ed0a-9b18ae2f340d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"subnet\": {\n    \"name\": \"\",\n    \"enable_dhcp\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\",\n    \"dns_nameservers\": [\n    ],\n    \"allocation_pools\": [\n      {\n        \"start\": \"192.168.199.2\",\n        \"end\": \"192.168.199.254\"\n      }\n    ],\n    \"host_routes\": [\n    ],\n    \"ip_version\": 4,\n    \"gateway_ip\": \"192.168.199.1\",\n    \"cidr\": \"192.168.199.0/24\",\n    \"id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407876968386,
+                       "name": "Post Add Neutron Subnet",
+                       "description": "Post Neutron v2.0 Subnets",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "62417324-b809-5a83-d3f3-cd4fef07bbe5",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/floatingips/2f245a7b-796b-4f26-9cf9-9e82d248fda7",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407945038085,
+                       "name": "Get Neutron Floating IP",
+                       "description": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "70ae1c0d-5b58-0c2a-5b62-d186a74059ab",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/floatingips/2f245a7b-796b-4f26-9cf9-9e82d248fda7",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": "{\n  \"floatingip\": {\n      \"router_id\": \"8604a0de-7f6b-409a-a47c-a1cc7bc77b2e\",\n      \"tenant_id\": \"60cd4f6dbc5f499982a284e7b83b5be3\",\n      \"floating_network_id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f6\",\n      \"fixed_ip_address\": null,\n      \"port_id\": null,\n      \"id\": \"2f245a7b-796b-4f26-9cf9-9e82d248fda7\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407947274681,
+                       "name": "Update Neutron Floating IP -- disassociate port",
+                       "description": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "7370da7f-234e-3f7a-ed12-e384131d886d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers/8604a0de-7f6b-409a-a47c-a1cc7bc77b2e/remove_router_interface",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": "{\n  \"subnet_id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\",\n  \"port_id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\"\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407894647769,
+                       "name": "Post Remove Neutron Router Interface",
+                       "description": "Remove Neutron Router Interface",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "747f9a54-e64f-57f6-ce6d-8ad358817696",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"firewall\": {\n    \"admin_state_up\": true,\n    \"description\": \"Example Neutron v2.0 Firewall Creation\",\n    \"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\",\n    \"id\": \"3b0ef8f4-82c7-44d4-a4fb-6177f9a21977\",\n    \"name\": \"Example FWaaS Firewall\",\n    \"status\": \"PENDING_CREATE\",\n    \"tenant_id\": \"45977fa2dbd7482098dd68d0d8970117\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401140100321,
+                       "name": "Post Add Neutron FWaaS Firewall",
+                       "description": "Example posting of a Neutron v2.0 Neutron FWaaS firewall.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "78eb34fc-1933-c019-bf7f-fdae9652f9cd",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407893656841,
+                       "name": "Get Neutron Subnets",
+                       "description": "Return a list of Neutron v2.0 API Subnets.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "7b61cef4-38da-3a4e-c968-38a98f31e85d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/floatingips",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"floatingip\": {\n      \"router_id\": \"8604a0de-7f6b-409a-a47c-a1cc7bc77b2e\",\n      \"tenant_id\": \"60cd4f6dbc5f499982a284e7b83b5be3\",\n      \"floating_network_id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f6\",\n      \"fixed_ip_address\": \"192.168.199.1\",\n      \"floating_ip_address\": \"192.168.200.2\",\n      \"port_id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\",\n      \"id\": \"2f245a7b-796b-4f26-9cf9-9e82d248fda7\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407944603189,
+                       "name": "Post Add Neutron Floating IP",
+                       "description": "Example posting of a Neutron v2.0 Floating IP.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "7ef5413c-7f22-ac12-5444-f9be6a7c029e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139224214,
+                       "name": "Get Neutron FWaaS Firewalls",
+                       "description": "Return a list of Neutron FWaaS v2.0 API FWaaS firewalls.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "828984bd-db02-aec4-d154-cd8e7f2b559b",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"router\": {\n  \"status\": \"ACTIVE\",\n  \"external_gateway_info\": {\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f6\"\n  },\n  \"name\": \"another_router\",\n  \"admin_state_up\": true,\n  \"tenant_id\": \"60cd4f6dbc5f499982a284e7b83b5be3\",\n  \"id\": \"8604a0de-7f6b-409a-a47c-a1cc7bc77b2e\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407882177180,
+                       "name": "Post Add Neutron Router",
+                       "description": "Example posting of a Neutron v2.0 Neutron Router.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "83af7fdb-53b2-3818-006e-bb52b8304e6a",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/ports/65c0ee9f-d634-4522-8954-51021b570b0d",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": "",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407893936097,
+                       "name": "Post Delete Neutron Port",
+                       "description": "Post a list of Neutron v2.0 Subnets",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "846c29b1-07fd-3d7d-f997-845ba91232b9",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/floatingips/2f245a7b-796b-4f26-9cf9-9e82d248fda7",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407947338774,
+                       "name": "Delete Neutron Floating IP",
+                       "description": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "id": "84b71139-7a9a-2f27-d0f6-745b8dbe876f",
+                       "name": "Put Update Neutron Router ",
+                       "description": "Update Neutron Router",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers/8604a0de-7f6b-409a-a47c-a1cc7bc77b2e/",
+                       "method": "PUT",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": "{\n  \"router\": {\n  \"external_gateway_info\": {\n     \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f6\"\n  },\n  \"name\": \"another_router_renamed\",\n  \"admin_state_up\": false\n  }\n}",
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1407866749069,
+                       "synced": false
+               },
+               {
+                       "id": "8c4d8a07-64c5-f821-4799-d528f01e88cc",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Get Neutron Load Balancer",
+                       "description": "Return a Neutron v2.0  Load Balancer (LBaaS).",
+                       "descriptionFormat": "html",
+                       "time": 1407147839448,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "94c4ed8e-8e48-2384-38b0-5497fe05ba7a",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"port\": {\n    \"status\": \"DOWN\",\n    \"binding:host_id\": \"\",\n    \"name\": \"private-port\",\n    \"allowed_address_pairs\": [\n    ],\n    \"admin_state_up\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"d6700c0c9ffa4f1cb322cd4a1f3906fa\",\n    \"binding:vif_details\": {\n    },\n    \"binding:vnic_type\": \"normal\",\n    \"binding:vif_type\": \"unbound\",\n    \"mac_address\": \"fa:16:3e:c9:cb:f0\",\n    \"binding:profile\": {\n    },\n    \"fixed_ips\": [\n      {\n        \"subnet_id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\",\n        \"ip_address\": \"192.168.199.1\"\n      }\n    ],\n    \"id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\",\n    \"security_groups\": [\n      \"f0ac4394-7e4a-4409-9701-ba8be283dbc3\"\n    ]\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407897276098,
+                       "name": "Post Add Neutron Ports",
+                       "description": "Post a list of Neutron v2.0 Subnets",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "9d37dcb1-e1e6-9fae-01ea-cc30aeb874a6",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"subnet\": {\n    \"name\": \"\",\n    \"enable_dhcp\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\",\n    \"dns_nameservers\": [\n    ],\n    \"allocation_pools\": [\n      {\n        \"start\": \"192.168.199.2\",\n        \"end\": \"192.168.199.254\"\n      }\n    ],\n    \"host_routes\": [\n    ],\n    \"ip_version\": 4,\n    \"gateway_ip\": \"192.168.199.1\",\n    \"cidr\": \"192.168.199.0/24\",\n    \"id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\"\n  }\n}\n",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407877671809,
+                       "name": "Post Add Neutron Subnets",
+                       "description": "Post a list of Neutron v2.0 Subnets",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "id": "9e7c7b50-1580-c7e2-70a0-445b42e218b1",
+                       "name": "Get Neutron Router",
+                       "description": "Get Neutron Router, based on id",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers/8604a0de-7f6b-409a-a47c-a1cc7bc77b2e",
+                       "method": "GET",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": "{\n  \"router\": {\n  \"status\": \"ACTIVE\",\n  \"external_gateway_info\": {\n  \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f6\"\n  },\n  \"name\": \"another_router\",\n  \"admin_state_up\": true,\n  \"tenant_id\": \"60cd4f6dbc5f499982a284e7b83b5be3\",\n  \"id\": \"8604a0de-7f6b-409a-a47c-a1cc7bc77b2e\"\n  }\n}",
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1407866340804,
+                       "synced": false
+               },
+               {
+                       "id": "9fe0d840-dcd3-6d3e-d410-e88538858e3a",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-group-rules/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"security_group_rule\":{\n      \"id\":\"A9F6424D-4D08-4819-BFC4-444444444444\",\n      \"direction\":\"ingress\",\n      \"port_range_min\":\"80\",\n      \"ethertype\":\"IPv4\",\n      \"port_range_max\":\"80\",\n      \"protocol\":\"tcp\",\n      \"remote_ip_prefix\":\"172.0.0.0/24\",\n      \"remote_group_id\":\"85cc3048-abc3-43cc-89b3-377341426ac5\",\n      \"security_group_id\":\"C9F5924D-4D08-4819-BFC4-111111111111\",\n      \"tenant_id\":\"3B82FF05-72A2-413E-B051-222222222222\"\n   }\n}\n",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401137905549,
+                       "name": "Post Add Security Rules Frontend Tier",
+                       "description": "Example Neutron v2.0 security rule for a front web tier.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "a183a8b3-bddb-dc04-ae73-3beb11af4d04",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_policies",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407148296484,
+                       "name": "Get Neutron FWaaS Policies",
+                       "description": "Return a list of Neutron v2.0 Neutron FWaaS Firewall policies.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "a1efd833-3d79-1621-9aa5-61b0fecec94a",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_policies",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"firewall_policies\": [\n    {\n      \"audited\": false,\n      \"description\": \"\",\n      \"firewall_rules\": [\n        \"8722e0e0-9cc9-4490-9660-8c9a5732fbb0\"\n      ],\n      \"id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\",\n      \"name\": \"Example FWaaS Policy\",\n      \"shared\": false,\n      \"tenant_id\": \"45977fa2dbd7482098dd68d0d8970117\"\n    }\n  ]\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139374457,
+                       "name": "Post Add Neutron FWaaS Policy",
+                       "description": "Example posting of a Neutron v2.0 FWaaS policy.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "id": "a209e7b3-9d00-bd9a-b920-39fd577b52c6",
+                       "name": "Post Add Neutron External Network",
+                       "description": "Post add Neutron v2.0 External Network",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/networks/",
+                       "method": "POST",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": "{\n   \"networks\":[\n      {\n         \"status\":\"ACTIVE\",\n         \"subnets\":[\n         ],\n         \"name\":\"sample_network_90\",\n         \"provider:physical_network\":null,\n   \"admin_state_up\":false,\n   \"tenant_id\":\"60cd4f6dbc5f499982a284e7b83b5be3\",\n   \"provider:network_type\":\"local\",\n   \"router:external\":true,\n   \"shared\":false,\n   \"id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f6\",\n   \"provider:segmentation_id\":90\n}\n  ]\n}",
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1407865757248,
+                       "synced": false,
+                       "isFromCollection": true,
+                       "collectionRequestId": "cac027e1-bbc9-f147-5142-5b48a4f02863"
+               },
+               {
+                       "id": "a483b6c9-2f07-f59e-effa-883591fee938",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/listeners/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "POST",
+                       "data": "{\n  \"listener\": {\n    \"id\": \"9bb09b2b-a0e3-4fa7-8020-76efd4b30d30\",\n    \"default_pool_id\": \"8311446e-8a13-4c00-95b3-03a92f9759c7\",\n    \"tenant_id\": \"352686b7-c4b2-44ec-a458-84239713f685\",\n    \"name\": \"Example HTTPS Listener\",\n    \"description\": \"A very simple example of an HTTPS listener\",\n    \"protocol\": \"https\",\n    \"protocol_port\": \"443\",\n    \"load_balancer_id\": \"b8a35470-f65d-11e3-a3ac-0800200c9a66\",\n    \"admin_state_up\": true,\n    \"status\": \"ACTIVE\"\n  }\n}",
+                       "dataMode": "raw",
+                       "name": "Post Add Load Balancer Listeners",
+                       "description": "Example posting of a Neutron v2.0  Load Balancer Listeners.",
+                       "descriptionFormat": "html",
+                       "time": 1407147879638,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "a896a2b2-3273-2ff0-c801-1cbecdc2cc85",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/pools/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Get Neutron Load Balancer  Pool",
+                       "description": "Return a Neutron v2.0  Load Balancer Pool.",
+                       "descriptionFormat": "html",
+                       "time": 1407147861621,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "aaaf62a6-9a7d-4fde-0031-bfd60a23c1c0",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_policies",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1397457663853,
+                       "name": "Get Neutron FWaaS Policies copy",
+                       "description": "Return a list of Neutron v2.0 Neutron FWaaS Firewall policies.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "ac935eb8-1bd6-007f-70e2-73c5a01e1da5",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139224214,
+                       "name": "Get Neutron FWaaS Firewalls copy",
+                       "description": "Return a list of Neutron FWaaS v2.0 API FWaaS firewalls.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "b6761938-4918-6120-c181-33f5d8c9f1a5",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/pools/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "POST",
+                       "data": "{\n  \"pool\": {\n    \"id\": \"332abe93-f488-41ba-870b-2ac66be7f853\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"name\": \"Example pool\",\n    \"description\": \"\",\n    \"protocol\": \"tcp\",\n    \"lb_algorithm\": \"ROUND_ROBIN\",\n    \"session_persistence\": {\n    },\n    \"healthmonitor_id\": null,\n    \"members\": [\n    ],\n    \"admin_state_up\": true,\n    \"status\": \"ACTIVE\"\n  }\n}",
+                       "dataMode": "raw",
+                       "name": "Post Add Neutron Load Balancer Pool",
+                       "description": "Example posting of a Neutron v2.0  Load Balancer Pool.",
+                       "descriptionFormat": "html",
+                       "time": 1407147853324,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "b922977b-b639-04d5-1a84-a95dfea15139",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407877015645,
+                       "name": "Get Neutron Subnets",
+                       "description": "Return a list of Neutron v2.0 API Subnets.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "ba73a129-a385-0554-7e6c-dc687ea78bbb",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/floatingips",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407944696947,
+                       "name": "Get Neutron Floating IPs",
+                       "description": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "c8def042-8f03-4820-5c00-f01cd84281f4",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"port\": {\n    \"status\": \"DOWN\",\n    \"binding:host_id\": \"\",\n    \"name\": \"private-port\",\n    \"allowed_address_pairs\": [\n    ],\n    \"admin_state_up\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"d6700c0c9ffa4f1cb322cd4a1f3906fa\",\n    \"binding:vif_details\": {\n    },\n    \"binding:vnic_type\": \"normal\",\n    \"binding:vif_type\": \"unbound\",\n    \"device_owner\": \"\",\n    \"mac_address\": \"fa:16:3e:c9:cb:f0\",\n    \"binding:profile\": {\n    },\n    \"fixed_ips\": [\n      {\n        \"subnet_id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\",\n        \"ip_address\": \"192.168.199.20\"\n      }\n    ],\n    \"id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\",\n    \"security_groups\": [\n      \"f0ac4394-7e4a-4409-9701-ba8be283dbc3\"\n    ],\n    \"device_id\": \"\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407877181799,
+                       "name": "Post Add Neutron Network Port",
+                       "description": "Post a list of Neutron v2.0 Port",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "c9cc2212-1f16-ead6-5dc0-073aed1e2c61",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-group-rules/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"security_group_rule\":{\n      \"id\":\"A9F6424D-4D08-4819-BFC4-333333333333\",\n      \"direction\":\"ingress\",\n      \"port_range_min\":\"3306\",\n      \"ethertype\":\"IPv4\",\n      \"port_range_max\":\"3306\",\n      \"protocol\":\"tcp\",\n      \"remote_ip_prefix\":\"10.0.0.0/24\",\n      \"remote_group_id\":\"85cc3048-abc3-43cc-89b3-377341426ac5\",\n      \"security_group_id\":\"C9F5924D-4D08-4819-BFC4-111111111111\",\n      \"tenant_id\":\"3B82FF05-72A2-413E-B051-222222222222\"\n   }\n}\n",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401137493078,
+                       "name": "Post Add Security Rule Backend Tier",
+                       "description": "Neutron v2.0 Add a Neutron Security Rule for a backend database tier example",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "c9f46dde-6b6d-0def-ae83-7885be0dbf87",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/healthmonitors/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "Get Load Balancer  Health Monitors",
+                       "description": "Return a Neutron v2.0  Load Balancer Health Monitors.",
+                       "descriptionFormat": "html",
+                       "time": 1407147951823,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "d8411d71-bb1d-f932-7e1d-197811a2a37c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_policies/c69933c1-b472-44f9-8226-30dc4ffd454c",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1406950874873,
+                       "name": "Get Neutron FWaaS Policy",
+                       "description": "Return a list of Neutron v2.0 Neutron FWaaS Firewall policies.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "e6b74bbb-cf2f-9eec-e530-537f1c065f8e",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers/8604a0de-7f6b-409a-a47c-a1cc7bc77b2e/add_router_interface",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": "{\n  \"subnet_id\": \"3b80198d-4f7b-4f77-9ef5-774d54e17126\",\n  \"port_id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\"\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1407894571634,
+                       "name": "Post Add Neutron Router Interface",
+                       "description": "Add Neutron Router Interface",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "synced": false
+               },
+               {
+                       "id": "eb1baf45-cdb2-7f50-a6aa-6fe934c1a355",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"firewall\": {\n    \"admin_state_up\": true,\n    \"description\": \"Example Neutron v2.0 Firewall Creation\",\n    \"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\",\n    \"id\": \"3b0ef8f4-82c7-44d4-a4fb-6177f9a21977\",\n    \"name\": \"Example FWaaS Firewall\",\n    \"status\": \"PENDING_CREATE\",\n    \"tenant_id\": \"45977fa2dbd7482098dd68d0d8970117\"\n  }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401140100321,
+                       "name": "Post Add Neutron FWaaS Firewall copy",
+                       "description": "Example posting of a Neutron v2.0 Neutron FWaaS firewall.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "id": "ec4ca40c-be6e-d76b-81a3-8fd328180132",
+                       "name": "Get Neutron Routers",
+                       "description": "Get Neutron Routers",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/routers",
+                       "method": "GET",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "data": "{\n  \"firewall\": {\n    \"admin_state_up\": true,\n    \"description\": \"Example Neutron v2.0 Firewall Creation\",\n    \"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\",\n    \"id\": \"3b0ef8f4-82c7-44d4-a4fb-6177f9a21977\",\n    \"name\": \"Example FWaaS Firewall\",\n    \"status\": \"PENDING_CREATE\",\n    \"tenant_id\": \"45977fa2dbd7482098dd68d0d8970117\"\n  }\n}",
+                       "dataMode": "raw",
+                       "timestamp": 0,
+                       "version": 2,
+                       "time": 1407854898874,
+                       "synced": false
+               },
+               {
+                       "id": "ed8face9-6585-8a9b-9e09-870e3a5e5546",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/fw/firewalls_rules",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n  \"firewall_rules\": [\n    {\n      \"action\": \"allow\",\n      \"description\": \"Example FWaaS Rule\",\n      \"destination_ip_address\": null,\n      \"destination_port\": \"22\",\n      \"enabled\": true,\n      \"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\",\n      \"id\": \"8722e0e0-9cc9-4490-9660-8c9a5732fbb0\",\n      \"ip_version\": 4,\n      \"name\": \"ALLOW_SSH\",\n      \"position\": 1,\n      \"protocol\": \"tcp\",\n      \"shared\": false,\n      \"source_ip_address\": null,\n      \"source_port\": null,\n      \"tenant_id\": \"45977fa2dbd7482098dd68d0d8970117\"\n    }\n  ]\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139588833,
+                       "name": "Post Add Neutron FWaaS Rule",
+                       "description": "Example posting of a Neutron v2.0 Neutron FWaaS firewall rule.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "ef3c7339-ba4d-124d-7e1f-67d9ab638277",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139136358,
+                       "name": "Get Neutron Ports",
+                       "description": "Return a list of Neutron v2.0 API ports.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "f01b7f99-0aeb-739f-eb4a-cd467320b85c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-group-rules/",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401139648839,
+                       "name": "Get Neutron Security Rules",
+                       "description": "Return a list of Neutron v2.0 security rules.",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               },
+               {
+                       "id": "f9de4b7d-8b08-fb14-d557-3cf81d7465f4",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+                       "url": "http://127.0.0.1:8080/controller/nb/v2/neutron/security-groups/",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": "{\n   \"security_group\":{\n      \"name\":\"backend_databases\",\n      \"description\":\"Example security group for backend_databases\",\n     \"tenant_id\":\"3B82FF05-72A2-413E-B051-222222222222\",\n     \"id\":\"C9F5924D-4D08-4819-BFC4-111111111111\"\n   }\n}",
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "time": 1401136080941,
+                       "name": "Post Add Security Group Web Tiers",
+                       "description": "Neutron v2.0 Add a web tier security group",
+                       "collectionId": "bd9b142f-e3ad-452d-f088-eed1b741b937",
+                       "responses": [],
+                       "synced": false
+               }
+       ]
+}
diff --git a/resources/openstack/Neutron-v2.0-LBaaS-API-Examples.json.postman_collection b/resources/openstack/Neutron-v2.0-LBaaS-API-Examples.json.postman_collection
new file mode 100644 (file)
index 0000000..e5c65d0
--- /dev/null
@@ -0,0 +1,305 @@
+{
+   "id":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+   "name":"Neutron-v2.0-LBaaS-API-Examples",
+   "description":"A collection of OpenStack Neutron v2.0 REST API calls for Postman. Import these into Postman and use to validate the OpenDaylight Neutron NB-API interfaces.\n\nResources:\n- Postman http://www.getpostman.com\n- Neutron v2.0 https://wiki.openstack.org/wiki/Neutron/APIv2-specification",
+   "order":[
+      "ab56feb7-741c-09a1-6d61-5b70d3efb00d",
+      "9042ff64-a91c-1ed1-d358-84efe27c5a0c",
+      "a0477924-0f54-3c9b-f801-504619ac848e",
+      "81160a47-b9e5-f5a2-3436-06f315a22252",
+      "38db7b1b-3215-ef48-b03e-3c35b4392962",
+      "09a6d683-9f53-9f42-d26e-6a153fa1e095",
+      "c51aee6b-3a7f-a599-3e48-bf74c8519312",
+      "3ccccdb1-1804-6ede-9ad0-77b9d74346c4",
+      "88cb3b1b-085f-957a-7b8f-a3dc3ccfa11f",
+      "7a989db7-a585-c65e-69c4-a693003090a2",
+      "cdc484d4-59b3-c6dc-765e-2310da116137",
+      "76409539-7a91-d18c-5c38-b3a5ee3bd371",
+      "aefb1037-96a1-be86-84c5-26c43149f678"
+   ],
+   "folders":[
+      {
+         "id":"126c18b5-94b8-689b-c932-371cddb543f2",
+         "name":"Neutron Firewall as a Service (FWaaS)",
+         "description":"",
+         "order":[
+            "747f9a54-e64f-57f6-ce6d-8ad358817696",
+            "7ef5413c-7f22-ac12-5444-f9be6a7c029e",
+            "ed8face9-6585-8a9b-9e09-870e3a5e5546",
+            "09bcfbe4-b01a-3615-820f-7fc3a2261e05",
+            "a1efd833-3d79-1621-9aa5-61b0fecec94a",
+            "a183a8b3-bddb-dc04-ae73-3beb11af4d04"
+         ],
+         "collection_name":"Neutron-v2.0-API-Examples",
+         "collection_id":"bd9b142f-e3ad-452d-f088-eed1b741b937"
+      },
+      {
+         "id":"770b37d2-85c3-d373-28de-4913009875f8",
+         "name":"Neutron Load Balancer as a Service (LBaaS)",
+         "description":"",
+         "order":[
+            "4ecb4af3-e10b-6710-bbcf-af2b80a8887f",
+            "8c4d8a07-64c5-f821-4799-d528f01e88cc",
+            "a483b6c9-2f07-f59e-effa-883591fee938",
+            "5c73f0bc-7502-26e1-42e1-c918ecbd56ae",
+            "b6761938-4918-6120-c181-33f5d8c9f1a5",
+            "a896a2b2-3273-2ff0-c801-1cbecdc2cc85",
+            "033e8332-94d9-b9cd-6b2d-4adb37dd8a9c",
+            "c9f46dde-6b6d-0def-ae83-7885be0dbf87"
+         ],
+         "collection_name":"Neutron-v2.0-API-Examples",
+         "collection_id":"bd9b142f-e3ad-452d-f088-eed1b741b937"
+      },
+      {
+         "id":"7b2236c6-cd5b-1bc0-fd02-737efb4995dc",
+         "name":"Neutron Port Security",
+         "description":"",
+         "order":[
+            "f9de4b7d-8b08-fb14-d557-3cf81d7465f4",
+            "9fe0d840-dcd3-6d3e-d410-e88538858e3a",
+            "c9cc2212-1f16-ead6-5dc0-073aed1e2c61",
+            "1387de10-9981-2ecb-32b8-4cc4806894cf",
+            "56d38607-d1dc-adba-a3fd-7e4d63e6c75d",
+            "4f72cdab-70f1-dba9-3986-3305c7ef18c8",
+            "f01b7f99-0aeb-739f-eb4a-cd467320b85c"
+         ],
+         "collection_name":"Neutron-v2.0-API-Examples",
+         "collection_id":"bd9b142f-e3ad-452d-f088-eed1b741b937"
+      },
+      {
+         "id":"2ad17469-46b9-3b8e-0686-b361e092c755",
+         "name":"Neutron Port, Network, Subnet, CRUD",
+         "description":"",
+         "order":[
+            "55aab7d7-6159-c4fb-5b3f-42cbb55c4e7b",
+            "1215e515-a4ff-7d7e-acbf-905c6706db86",
+            "9d37dcb1-e1e6-9fae-01ea-cc30aeb874a6",
+            "78eb34fc-1933-c019-bf7f-fdae9652f9cd",
+            "94c4ed8e-8e48-2384-38b0-5497fe05ba7a",
+            "83af7fdb-53b2-3818-006e-bb52b8304e6a",
+            "ef3c7339-ba4d-124d-7e1f-67d9ab638277"
+         ],
+         "collection_name":"Neutron-v2.0-API-Examples",
+         "collection_id":"bd9b142f-e3ad-452d-f088-eed1b741b937"
+      },
+      {
+         "id":"f080abc2-2590-5b74-dd6d-3acc19090bce",
+         "name":"Neutron Router, CRUD",
+         "description":"",
+         "order":[
+            "a209e7b3-9d00-bd9a-b920-39fd577b52c6",
+            "5542be98-775d-3a61-2709-59b0d692e453",
+            "828984bd-db02-aec4-d154-cd8e7f2b559b",
+            "ec4ca40c-be6e-d76b-81a3-8fd328180132",
+            "9e7c7b50-1580-c7e2-70a0-445b42e218b1",
+            "84b71139-7a9a-2f27-d0f6-745b8dbe876f",
+            "41940ad7-cec0-99c5-204a-eceab3aa7b78",
+            "e6b74bbb-cf2f-9eec-e530-537f1c065f8e",
+            "7370da7f-234e-3f7a-ed12-e384131d886d",
+            "7b61cef4-38da-3a4e-c968-38a98f31e85d",
+            "ba73a129-a385-0554-7e6c-dc687ea78bbb",
+            "62417324-b809-5a83-d3f3-cd4fef07bbe5",
+            "70ae1c0d-5b58-0c2a-5b62-d186a74059ab",
+            "846c29b1-07fd-3d7d-f997-845ba91232b9"
+         ],
+         "collection_name":"Neutron-v2.0-API-Examples",
+         "collection_id":"bd9b142f-e3ad-452d-f088-eed1b741b937"
+      }
+   ],
+   "timestamp":1394529177458,
+   "synced":false,
+   "requests":[
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"09a6d683-9f53-9f42-d26e-6a153fa1e095",
+         "name":"Get Neutron Load Balancer  Pool",
+         "description":"Return a Neutron v2.0  Load Balancer Pool.",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/pools/",
+         "method":"GET",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":[
+
+         ],
+         "dataMode":"params",
+         "responses":[
+
+         ],
+         "version":2
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"38db7b1b-3215-ef48-b03e-3c35b4392962",
+         "name":"Post Add Neutron Load Balancer Pool",
+         "description":"Example posting of a Neutron v2.0  Load Balancer Pool.",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/pools/",
+         "method":"POST",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n  \"pool\": {\n    \"id\": \"332abe93-f488-41ba-870b-2ac66be7f853\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"name\": \"Example pool\",\n    \"description\": \"\",\n    \"protocol\": \"http\",\n    \"lb_algorithm\": \"ROUND_ROBIN\",\n    \"session_persistence\": {\n    },\n    \"healthmonitor_id\": null,\n    \"members\": [{\n      \"id\": \"a183a8b3-bddb-dc04-ae73-3beb11af4d04\",\n \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n \"address\": \"10.0.0.7\",\n \"protocol_port\":80,\n \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n      \"admin_state_up\": true\n }],\n    \"admin_state_up\": true,\n    \"status\": \"ACTIVE\"\n  }\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1410588134504
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"3ccccdb1-1804-6ede-9ad0-77b9d74346c4",
+         "name":"Get Neutron Load Balancers",
+         "description":"Return a Neutron v2.0  Load Balancer (LBaaS).",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers/",
+         "method":"GET",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":[
+
+         ],
+         "dataMode":"params",
+         "responses":[
+
+         ],
+         "version":2
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"76409539-7a91-d18c-5c38-b3a5ee3bd371",
+         "name":"Get Neutron Load Balancer Pool Members",
+         "description":"Return Neutron v2.0  Load Balancer (LBaaS). pool members",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/pools/332abe93-f488-41ba-870b-2ac66be7f853/members",
+         "method":"GET",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411258713277
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"7a989db7-a585-c65e-69c4-a693003090a2",
+         "name":"Delete Neutron Load Balancer",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers/8992a43f-83af-4b49-9afd-c2bfbd82d7d7",
+         "method":"DELETE",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"",
+         "dataMode":"raw",
+         "timestamp":0,
+         "responses":[
+
+         ],
+         "version":2
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"81160a47-b9e5-f5a2-3436-06f315a22252",
+         "name":"Post Add Neutron Network Port 2",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+         "method":"POST",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n  \"port\": {\n    \"status\": \"UP\",\n    \"binding:host_id\": \"\",\n    \"name\": \"private-port\",\n    \"allowed_address_pairs\": [\n    ],\n    \"admin_state_up\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"binding:vif_details\": {\n    },\n    \"binding:vnic_type\": \"normal\",\n    \"binding:vif_type\": \"unbound\",\n    \"device_owner\": \"\",\n    \"mac_address\": \"fa:16:3e:c9:cb:f4\",\n    \"binding:profile\": {\n    },\n    \"fixed_ips\": [\n      {\n        \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n        \"ip_address\": \"10.0.0.8\"\n      }\n    ],\n    \"id\": \"65c0ee9f-d634-4522-8954-51021b570b0e\",\n    \"security_groups\": [\n      \"f0ac4394-7e4a-4409-9701-ba8be283dbc3\"\n    ],\n    \"device_id\": \"\"\n  }\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411259165825
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"88cb3b1b-085f-957a-7b8f-a3dc3ccfa11f",
+         "name":"Post Add Neutron Load Balancer",
+         "description":"Example posting of a Neutron v2.0  Load Balancer (LBaaS).",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/loadbalancers/",
+         "method":"POST",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n  \"loadbalancer\": {\n    \"id\": \"8992a43f-83af-4b49-9afd-c2bfbd82d7d7\",\n    \"name\": \"Example LB\",\n    \"description\": \"A very simple example load balancer.\",\n    \"vip_address\": \"10.0.0.5\",\n    \"vip_subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n    \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n    \"status\": \"PENDING_CREATE\"\n  }\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1410506408065
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"9042ff64-a91c-1ed1-d358-84efe27c5a0c",
+         "name":"Post Add Neutron Subnet",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/subnets/",
+         "method":"POST",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n  \"subnet\": {\n    \"name\": \"\",\n    \"enable_dhcp\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"dns_nameservers\": [\n    ],\n    \"allocation_pools\": [\n      {\n        \"start\": \"10.0.0.2\",\n        \"end\": \"10.0.0.254\"\n      }\n    ],\n    \"host_routes\": [\n    ],\n    \"ip_version\": 4,\n    \"gateway_ip\": \"10.0.0.1\",\n    \"cidr\": \"10.0.0.0/24\",\n    \"id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\"\n  }\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411259299009
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"a0477924-0f54-3c9b-f801-504619ac848e",
+         "name":"Post Add Neutron Network Port",
+         "description":"Post a list of Neutron v2.0 Port",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/ports/",
+         "method":"POST",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n  \"port\": {\n    \"status\": \"UP\",\n    \"binding:host_id\": \"\",\n    \"name\": \"private-port\",\n    \"allowed_address_pairs\": [\n    ],\n    \"admin_state_up\": true,\n    \"network_id\": \"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n    \"tenant_id\": \"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n    \"binding:vif_details\": {\n    },\n    \"binding:vnic_type\": \"normal\",\n    \"binding:vif_type\": \"unbound\",\n    \"device_owner\": \"\",\n    \"mac_address\": \"fa:16:3e:c9:cb:f0\",\n    \"binding:profile\": {\n    },\n    \"fixed_ips\": [\n      {\n        \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n        \"ip_address\": \"10.0.0.7\"\n      }\n    ],\n    \"id\": \"65c0ee9f-d634-4522-8954-51021b570b0d\",\n    \"security_groups\": [\n      \"f0ac4394-7e4a-4409-9701-ba8be283dbc3\"\n    ],\n    \"device_id\": \"\"\n  }\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411259172338
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"ab56feb7-741c-09a1-6d61-5b70d3efb00d",
+         "name":"Post Add Neutron Network",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/networks/",
+         "method":"POST",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n   \"networks\":[\n      {\n         \"status\":\"ACTIVE\",\n         \"subnets\":[\n         ],\n         \"name\":\"sample_network_89\",\n         \"provider:physical_network\":null,\n   \"admin_state_up\":false,\n   \"tenant_id\":\"19eaa775-cf5d-49bc-902e-2f85f668d995\",\n   \"provider:network_type\":\"local\",\n   \"router:external\":false,\n   \"shared\":false,\n   \"id\":\"e9330b1f-a2ef-4160-a991-169e56ab17f5\",\n   \"provider:segmentation_id\":89\n}\n  ]\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411259104205
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"aefb1037-96a1-be86-84c5-26c43149f678",
+         "name":"Delete Neutron Load Balancer Pool Member",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/pools/332abe93-f488-41ba-870b-2ac66be7f853/members/a183a8b3-bddb-dc04-ae73-3beb11af4d05",
+         "method":"DELETE",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411230459830
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"c51aee6b-3a7f-a599-3e48-bf74c8519312",
+         "name":"Delete Neutron Load Balancer Pool",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/pools/332abe93-f488-41ba-870b-2ac66be7f853",
+         "method":"DELETE",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"",
+         "dataMode":"raw",
+         "timestamp":0,
+         "responses":[
+
+         ],
+         "version":2
+      },
+      {
+         "collectionId":"f2eafc5e-f558-a4b5-dffd-37c9209df60b",
+         "id":"cdc484d4-59b3-c6dc-765e-2310da116137",
+         "name":"Post Add LoadBalancer Pool Member",
+         "description":"",
+         "url":"http://127.0.0.1:8080/controller/nb/v2/neutron/pools/332abe93-f488-41ba-870b-2ac66be7f853/members/",
+         "method":"PUT",
+         "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/json\nContent-Type: application/json\n",
+         "data":"{\n  \"member\": {\n      \"id\": \"a183a8b3-bddb-dc04-ae73-3beb11af4d05\",\n \"tenant_id\": \"c778d7b543914fc68df8b44f57035f0b\",\n \"address\": \"10.0.0.8\",\n \"protocol_port\":80,\n \"subnet_id\": \"5966ebd4-b456-4e11-a3a3-def0d3f432d4\",\n      \"admin_state_up\": true,\n    \"weight\": 1,\n    \"status\": \"UP\"\n }\n}",
+         "dataMode":"raw",
+         "timestamp":0,
+         "version":2,
+         "time":1411230445515
+      }
+   ]
+}
diff --git a/resources/openstack/README b/resources/openstack/README
new file mode 100644 (file)
index 0000000..d2fa6ce
--- /dev/null
@@ -0,0 +1,28 @@
+
+This directory contains all the associated scripts and configuration files that can be used by developers and 
+administrators working on openstack and devstack.
+
+Contents
+--------
+
+1. odl_os_ovs.sh : Stands for OpenDaylight_OpenStack_Openvswith.sh (cant be more Open than this ;) )
+                   Script used in OpenStack Deployments/devstack in order to initialize openvswitch/ovsdb-server
+                   in order to work with the OpenDaylight's OVSDB southbound plugin effectively.
+                   This scripts sets up ovsdb-server manager to listen to the Passive TCP socket open on 6640.
+                   It also configures the Open_vSwitch table in OVSDB with local-ip for the Overlay Tunnel end-point. 
+
+2. local.conf.controller : A sample development local.conf used on the devstack Controller node with Neutron ML2 mechanism driver for OpenDaylight.  
+
+3. local.conf.compute : A sample development local.conf used on the devstack Compute node with Neutron ML2 mechanism driver for OpenDaylight.  
+
+4. DevStack.json.postman_collection : Relevant POSTMAN OpenDaylight REST-APIs that can be used for testing Openstack / Devstack deployments.
+
+5. dsconf.sh : Menu-driven script to create a local.conf, based on DevStack node configuration/need
+
+6. sethostname.sh : script to set the hostname (/etc/hosts, /etc/hostname, and "hostname" command)
+
+7. bootvm.sh : script to boot a VM from DevStack controller (requires . ./openrc admin admin)
+
+8. pingvm.sh : script to ping a VM from DevStack controller (requires . ./openrc admin admin)
+
+9. make-vxlan-net.sh : script to create a Neutron network and subnet using VXLAN tunnels (requires . ./openrc admin admin)
diff --git a/resources/openstack/bootvm.sh b/resources/openstack/bootvm.sh
new file mode 100755 (executable)
index 0000000..526ee8a
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 Cisco Systems, Inc.
+#
+# 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
+#
+# Authors : Thomas Bachman
+
+#
+# Script for booting VMs onto networks
+#
+
+#defaults
+vm=`hostname`
+net=private
+image=cirros-0.3.1-x86_64-uec
+
+nova hypervisor-list
+echo -n "Enter the hypervisor name to use for new instance [$vm]: "
+read -a entry
+if [ "$entry" != "" ]; then
+    vm=$entry
+fi
+
+neutron net-list
+echo -n "Enter the name of the network to use for the VM [$net]: "
+read -a entry
+if [ "$entry" != "" ]; then
+    net=$entry
+fi
+
+nova image-list
+echo -n "Enter the name of the image to use for the VM [$image]: "
+read -a entry
+if [ "$entry" != "" ]; then
+    image=$entry
+fi
+
+nova boot --flavor m1.tiny --image $(nova image-list | grep "$image\s" | awk '{print $2}') --nic net-id=$(neutron net-list | grep $net | awk '{print $2}') admin-private --availability_zone=nova:$vm
diff --git a/resources/openstack/dsconf.sh b/resources/openstack/dsconf.sh
new file mode 100755 (executable)
index 0000000..b85bab1
--- /dev/null
@@ -0,0 +1,368 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 Cisco Systems, Inc.
+#
+# 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
+#
+# Authors : Thomas Bachman
+
+#
+# Generate the local.conf, based on this machine's settings,
+# and user input
+#
+
+odl_ip=""
+odl_in_ds="y"
+vm_personality="ODC"
+active_ifs=""
+service_host=""
+service_host_name=""
+odl_mgr_ip=""
+host_ip=""
+host_name=`hostname`
+host_list=""
+
+# Minimum memory requirements, in kB
+od_mem=50000000
+oc_mem=3000000
+o_mem=2000000
+odoc_mem=5000000
+oco_mem=3000000
+
+
+
+#
+# personality-dependent services
+#
+ds_common_services="qpid neutron odl-compute n-cpu"
+ds_compute_services="nova n-novnc"
+ds_controller_services="n-cond q-svc q-dhcp q-l3 q-meta tempest"
+
+#
+# everyone gets these services
+#
+services=$ds_common_services
+
+#
+# services that are disabled
+#
+disabled_services="rabbit n-net"
+
+header='''
+LOGFILE=stack.sh.log\n
+#SCREEN_LOGDIR=/opt/stack/data/log\n
+#LOG_COLOR=False\n
+OFFLINE=True\n
+#RECLONE=yes\n
+\n
+'''
+
+#
+# single quoted to prevent variable substitutions
+#
+# add host info
+
+footer='''
+Q_HOST=$SERVICE_HOST\n
+Q_PLUGIN=ml2\n
+Q_ML2_PLUGIN_MECHANISM_DRIVERS=opendaylight,logger\n
+ENABLE_TENANT_TUNNELS=True\n
+ODL_BOOT_WAIT=70\n
+\n
+VNCSERVER_PROXYCLIENT_ADDRESS=${HOST_IP}\n
+VNCSERVER_LISTEN=0.0.0.0\n
+\n
+#FLOATING_RANGE=192.168.210.0/24\n
+#PUBLIC_NETWORK_GATEWAY=192.168.75.254\n
+MYSQL_HOST=$SERVICE_HOST\n
+RABBIT_HOST=$SERVICE_HOST\n
+GLANCE_HOSTPORT=$SERVICE_HOST:9292\n
+KEYSTONE_AUTH_HOST=$SERVICE_HOST\n
+KEYSTONE_SERVICE_HOST=$SERVICE_HOST\n
+\n
+MYSQL_PASSWORD=mysql\n
+RABBIT_PASSWORD=rabbit\n
+QPID_PASSWORD=rabbit\n
+SERVICE_TOKEN=service\n
+SERVICE_PASSWORD=admin\n
+ADMIN_PASSWORD=admin\n
+\n
+[[post-config|/etc/neutron/plugins/ml2/ml2_conf.ini]]\n
+[agent]\n
+minimize_polling=True\n
+'''
+
+#
+# Create a list of active network interfaces
+#
+get_active_ifs()
+{
+   all_ifs=`egrep 'ONBOOT' /etc/sysconfig/network-scripts/ifcfg-*`
+   for interface in $all_ifs
+   do
+       active=`echo $interface | awk 'BEGIN {FS="="} {print $2}'`
+       if [ "$active" == "yes" ]; then
+           file=`echo $interface | awk 'BEGIN {FS=":"} {print $1}'`
+           intf=`basename $file | awk 'BEGIN {FS="-"} {print $2}'`
+           active_ifs=`echo "$active_ifs $intf"`
+       fi
+   done
+}
+
+#
+# Have the user select the IP address to use
+#
+select_host_ip()
+{
+    get_active_ifs
+    echo "Your system has the following IP addresses: "
+    count=0
+    if_index="0"
+    for interface in $active_ifs
+    do
+        if [ "$interface" == "lo" ]; then
+            continue;
+        fi
+        exists=`ifconfig | grep $interface`
+        if [ "$exists" == "" ]; then
+            continue;
+        fi
+        ip=`ifconfig $interface | grep 'inet ' | awk 'BEGIN {FS=" "} {print $2}'`
+        echo "    [$count] $interface: $ip"
+        let "count+=1";
+    done
+
+    entry=$if_index
+    if [ $count == 0 ]; then
+        echo "No active interfaces: please reconfigure /etc/sysconfig/network-scripts/ifcfg-<interface> and re-run"
+        exit
+    elif [ $count > 1 ]; then
+        echo -n "Select which interface to use [$entry]: "
+        read -a entry
+        if [ "$entry" > "$count" ]; then
+            let "maxcnt=count-1"
+            echo "Invalid entry, must be less than $maxcnt"
+            exit
+        elif [ "$entry" == "" ]; then
+            entry=$if_index
+        else
+            $if_index=$entry
+        fi
+    fi
+
+    count=0
+    for interface in $active_ifs
+    do
+        if [ $count == $if_index ]; then
+            #echo "foo"
+            host_ip=`ifconfig $interface | grep 'inet ' | awk 'BEGIN {FS=" "} {print $2}'`
+            break;
+        fi
+        let "count+=1"
+    done
+}
+
+#
+#  Verify the memory is sufficient for the configuration
+#
+check_mem()
+{
+    memory=`cat /proc/meminfo  | grep MemTotal | awk 'BEGIN {FS=" "} {print $2}'`
+    if [ "$vm_personality" == "O" ]; then
+        mem_needed=$od_mem
+    elif [ "$vm_personality" == "DC" ]; then
+        mem_needed=$oc_mem
+    elif [ "$vm_personality" == "D" ]; then
+        mem_needed=$o_mem
+    elif [ "$vm_personality" == "ODC" ]; then
+        mem_needed=$odoc_mem
+    elif [ "$vm_personality" == "DCD" ]; then
+        mem_needed=$oco_mem
+    fi
+    if [ "$memory" -lt "$mem_needed" ]; then
+        echo """
+             $vm_personality configurations require at least $mem_needed (have $memory).
+             Please shutdown the VM and reconfigure its memory
+             """
+        exit
+    fi
+}
+
+echo """
+   This script configures the local.conf for the
+   VM, based on the desired configuration.  The
+   VM can take on any of the following roles:
+
+       O:    OpenDaylight Controller.
+               In this role, the VM is only responsible
+               for running the OpenDaylight Controller
+
+       DC:   DevStack Controller.
+               In this role, the VM is only responsible
+               for running the DevStack controller.
+
+       D:    DevStack Compute. In this role,
+               the VM is only responsible for
+               running the DevStack compute.
+
+       ODC:  OpenDaylight Controller with DevStack Controller.
+               In this role, the VM runs both the OpenDaylight
+               controller and the DevStack controller. The
+               OpenDaylight controller is launched by DevStack.
+
+       DCD:  DevStack Controller with DevStack Compute.
+               In this role, the VM acts as both an DevStack
+               controller and compute node.
+"""
+
+echo -n "Enter VM's personality [$vm_personality]: "
+read -a entry
+if [ "$entry" == "" ]; then
+    entry=$vm_personality
+else
+    vm_personality=$entry
+fi
+if [ "$vm_personality" != "O" ] &&
+   [ "$vm_personality" != "DC" ] &&
+   [ "$vm_personality" != "D" ]  &&
+   [ "$vm_personality" != "ODC" ]  &&
+   [ "$vm_personality" != "DCD" ]; then
+    echo "$vm_personality is invalid"
+    exit;
+fi
+
+# For all nodes, run the memory check to make
+# sure they've allocated enough memory to
+# run the system.
+check_mem
+
+# Get the right IP
+select_host_ip
+
+service_host=$host_ip
+service_host_name=$host_name
+
+# For a combined ODL/DS coontroller, we still need
+# to add in the services
+if [ "$vm_personality" == "ODC" ]; then
+   services="$services $ds_controller_services odl-server"
+fi
+
+# For all pure DS nodes (no ODL -- DS controller, compute, or both),
+# we need to point it to the ODL Controller
+if [ "$vm_personality" == "D" ] ||
+   [ "$vm_personality" == "DC" ] ||
+   [ "$vm_personality" == "DCD" ]; then
+   if [ "$vm_personality" == "D" ]; then
+      services="$services $ds_compute_services"
+   else
+      services="$services $ds_controller_services"
+   fi
+   service_host=$host_ip
+   service_host_name=$host_name
+   echo """
+           DevStack nodes need to point to the OpenDaylight Controller.
+           Please provide the IP address of the OpenDaylight Controller.
+        """
+   echo -n "OpenDaylight Controller IP: "
+   read -a odl_ip
+fi
+
+
+#
+# For DS Compute Only, we need to point it to
+# the DS Controller and update the DS services
+if [ "$vm_personality" == "D" ]; then
+   services="$services $ds_compute_services"
+   echo """
+           DevStack Compute nodes need to point to the DevStack
+           Controller. Please provide the IP address and hostname
+           of the DevStack Controller
+        """
+   echo -n "DevStack Controller IP: "
+   read -a service_host
+   echo -n "DevStack Controller hostname: "
+   read -a service_host_name
+   if [ "$service_host_name" == "$host_name" ]; then
+       echo """
+               Note: You have configured the DevStack controller's
+                     with the same name as this host. If this host
+                     requires a name change, run the set_hostname.sh
+                     script before running this one.
+            """
+   fi
+   echo """
+           DevStack Compute nodes also need to point to the
+           OpenDaylight Controller. Please provide the IP address
+           of the OpenDaylight Controller
+        """
+
+   # for DS compute, keep track of service host
+   host_list=$service_host_name
+fi
+
+######
+# Generate local.conf, using parameters
+######
+echo "[[local|localrc]]" > local.conf
+
+#
+#  Header
+#
+echo -e $header | while read -r line
+do
+    echo -e $line >> local.conf
+done
+
+#
+# Services
+#
+# disable all services for compute only nodes
+if [ "$vm_personality" == "D" ]; then
+   echo "disable_all_services" >> local.conf
+fi
+
+for line in $disabled_services
+do
+   echo "disable_service $line" >> local.conf
+done
+
+for line in $services
+do
+   echo -e "enable_service $line" >> local.conf
+done
+echo -e "\n" >> local.conf
+
+
+
+#
+# Add in VM-specific parameters
+#
+echo "HOST_IP=$host_ip" >> local.conf
+echo "HOST_NAME=$host_name" >> local.conf
+echo "SERVICE_HOST=$service_host" >> local.conf
+echo "SERVICE_HOST_NAME=$service_host_name" >> local.conf
+if [ "$vm_personality" != "O" ] &&
+   [ "$vm_personality" != "ODC" ]; then
+    echo "ODL_MGR_IP=$odl_ip" >> local.conf
+fi
+
+
+#
+# Footer
+#
+echo -e $footer | while read -r line
+do
+    echo -e $line >> local.conf
+done
+
+
+if [ "$host_list" != "" ]; then
+    echo "*********************************************************"
+    echo "===========>>>> Be sure to add $host_list to /etc/hosts!"
+    echo "*********************************************************"
+fi
+
+
diff --git a/resources/openstack/local.conf.compute b/resources/openstack/local.conf.compute
new file mode 100644 (file)
index 0000000..90ec96c
--- /dev/null
@@ -0,0 +1,58 @@
+
+## RENAME THIS FILE TO local.conf BEFORE USING IT IN THE COMPUTE NODE##
+
+[[local|localrc]]
+LOGFILE=stack.sh.log
+OFFLINE=true
+#RECLONE=yes
+disable_all_services
+#enable_service n-cpu quantum q-agt n-novnc qpid
+enable_service neutron nova n-cpu quantum q-agt n-novnc qpid
+HOST_NAME=fedora2
+HOST_IP=192.168.56.102
+SERVICE_HOST_NAME=fedora1
+SERVICE_HOST=192.168.56.101
+
+FLOATING_RANGE=192.168.100.0/24
+
+Q_PLUGIN=ml2
+#Q_ML2_TENANT_NETWORK_TYPE=vlan
+#ENABLE_TENANT_VLANS=True
+Q_ML2_TENANT_NETWORK_TYPE=vxlan
+Q_AGENT_EXTRA_AGENT_OPTS=(tunnel_types=vxlan)
+Q_ML2_PLUGIN_MECHANISM_DRIVERS=opendaylight,logger
+NEUTRON_REPO=https://github.com/CiscoSystems/neutron.git
+NEUTRON_BRANCH=odl_ml2
+
+#Q_PLUGIN=ml2
+#Q_AGENT=openvswitch
+#Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,linuxbridge,l2population
+#Q_AGENT_EXTRA_AGENT_OPTS=(tunnel_types=gre)
+#Q_AGENT_EXTRA_SRV_OPTS=(local_ip=$HOST_IP)
+
+Q_HOST=$SERVICE_HOST
+MYSQL_HOST=$SERVICE_HOST
+RABBIT_HOST=$SERVICE_HOST
+GLANCE_HOSTPORT=$SERVICE_HOST:9292
+KEYSTONE_AUTH_HOST=$SERVICE_HOST
+KEYSTONE_SERVICE_HOST=$SERVICE_HOST
+MYSQL_PASSWORD=mysql
+RABBIT_PASSWORD=rabbit
+QPID_PASSWORD=rabbit
+SERVICE_TOKEN=service
+SERVICE_PASSWORD=admin
+ADMIN_PASSWORD=admin
+
+LOGFILE=/opt/stack/logs/stack.sh.log
+VERBOSE=True
+LOG_COLOR=False
+SCREEN_LOGDIR=/opt/stack/logs
+EXTRA_OPTS=(scheduler_default_filters=AllHostsFilter)
+
+[[post-config|/etc/neutron/plugins/ml2/ml2_conf.ini]]
+[ml2_odl]
+url=http://192.168.56.1:8080/controller/nb/v2/neutron
+username=admin
+password=admin
diff --git a/resources/openstack/local.conf.controller b/resources/openstack/local.conf.controller
new file mode 100644 (file)
index 0000000..8651512
--- /dev/null
@@ -0,0 +1,69 @@
+
+## RENAME THIS FILE TO local.conf BEFORE USING IT IN THE CONTROLLER NODE##
+
+[[local|localrc]]
+LOGFILE=stack.sh.log
+SCREEN_LOGDIR=/opt/stack/data/log
+LOG_COLOR=False
+#OFFLINE=True
+RECLONE=yes
+disable_service rabbit
+enable_service qpid
+enable_service n-cond
+disable_service n-net
+enable_service q-svc
+enable_service q-agt
+enable_service q-dhcp
+enable_service q-l3
+enable_service q-meta
+enable_service quantum
+# ODL WITH ML2
+# #enable_service odl
+Q_PLUGIN=ml2
+Q_ML2_TENANT_NETWORK_TYPE=vxlan
+Q_AGENT_EXTRA_AGENT_OPTS=(tunnel_types=vxlan)
+
+#Q_ML2_TENANT_NETWORK_TYPE=gre
+#ENABLE_TENANT_TUNNELS=True
+#ENABLE_TENANT_VLANS=True
+#TENANT_VLAN_RANGE=500:510
+Q_ML2_PLUGIN_MECHANISM_DRIVERS=opendaylight,logger
+NEUTRON_REPO=https://github.com/CiscoSystems/neutron.git
+NEUTRON_BRANCH=odl_ml2
+
+Q_HOST=$SERVICE_HOST
+HOST_IP=192.168.56.101
+
+#Q_PLUGIN=ml2
+#Q_AGENT=openvswitch
+#Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,linuxbridge,l2population
+#Q_USE_SECGROUP=True
+#Q_AGENT_EXTRA_SRV_OPTS=(local_ip=$HOST_IP)
+
+HOST_NAME=fedora1
+SERVICE_HOST_NAME=${HOST_NAME}
+SERVICE_HOST=192.168.56.101
+FLOATING_RANGE=192.168.100.0/24
+#PUBLIC_NETWORK_GATEWAY=192.168.75.254
+MYSQL_HOST=$SERVICE_HOST
+RABBIT_HOST=$SERVICE_HOST
+GLANCE_HOSTPORT=$SERVICE_HOST:9292
+KEYSTONE_AUTH_HOST=$SERVICE_HOST
+KEYSTONE_SERVICE_HOST=$SERVICE_HOST
+MYSQL_PASSWORD=mysql
+RABBIT_PASSWORD=rabbit
+QPID_PASSWORD=rabbit
+SERVICE_TOKEN=service
+SERVICE_PASSWORD=admin
+ADMIN_PASSWORD=admin
+
+[[post-config|/etc/neutron/plugins/ml2/ml2_conf.ini]]
+[ml2_odl]
+url=http://192.168.56.1:8080/controller/nb/v2/neutron
+username=admin
+password=admin
diff --git a/resources/openstack/make-vxlan-net.sh b/resources/openstack/make-vxlan-net.sh
new file mode 100755 (executable)
index 0000000..f4cdc6f
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 Cisco Systems, Inc.
+#
+# 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
+#
+# Authors : Thomas Bachman
+
+#
+# Create a neutron network and subnet for VXLAN (hard-coded)
+#
+
+neutron net-create vxlan-net --tenant_id  $(keystone tenant-list | grep '\sadmin' | awk '{print $2}') --provider:network_type vxlan --provider:segmentation_id 1300
+neutron  subnet-create vxlan-net 10.100.1.0/24 --name vxlan-net
diff --git a/resources/openstack/odl_os_ovs.sh b/resources/openstack/odl_os_ovs.sh
new file mode 100755 (executable)
index 0000000..15cb009
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# odl_os_ovs.sh : Stands for OpenDaylight_OpenStack_Openvswith.sh (cant be more Open than this ;) )
+
+if [ `whoami` != "root" ]; then
+    echo Please execute this script as superuser or with sudo previleges.
+    exit 1
+fi
+
+if [ "$#" -ne 1 ]; then
+  echo "Usage: odl_ovs_os.sh <tunnel-endpoint-ip-address>" >&2
+  echo "       <tunnel-endpoint-ip-address> is same as the local-ip configuration done for ovs-neutron-agent in ovs_quantum_plugin.ini"
+  exit 1
+fi
+
+ovs-vsctl set-manager ptcp:6640
+read ovstbl <<< $(ovs-vsctl get Open_vSwitch . _uuid)
+ovs-vsctl set Open_vSwitch $ovstbl other_config={"local_ip"="$1"}
+ovs-vsctl list Open_vSwitch .
diff --git a/resources/openstack/pingvm.sh b/resources/openstack/pingvm.sh
new file mode 100755 (executable)
index 0000000..c9fdacd
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 Cisco Systems, Inc.
+#
+# 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
+#
+# Authors : Thomas Bachman
+
+
+#
+# Ping an instance created by DevStack
+#
+
+# get the prefix
+ip=$1
+uuid=`neutron net-list | grep $(echo $ip | awk 'BEGIN {FS="."} {print $1 "." $2 "." $3}') | awk '{print $2}'`
+dhcp_server="qdhcp-$uuid"
+foo="ip netns exec $dhcp_server ping $ip"
+sudo $foo
diff --git a/resources/openstack/sethostname.sh b/resources/openstack/sethostname.sh
new file mode 100755 (executable)
index 0000000..db1c54c
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 Cisco Systems, Inc.
+#
+# 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
+#
+# Authors : Thomas Bachman
+
+#
+#  Set the hostname
+#
+currname=`cat /etc/hostname`
+echo "Current hostname: $currname"
+
+echo -n "Enter new hostname: "
+read -a newname
+
+#
+# Update /etc/hosts & /etc/hostname with new hostname
+#
+if [ "$newname" != "$currname" ]; then
+    res=`sed -i "s/$currname/$newname/g" /etc/hosts`
+    if [ $? -ne 0 ]; then
+        echo "failed to update /etc/hosts"
+    fi
+    res=`sed -i "s/$currname/$newname/g" /etc/hostname`
+    if [ $? -ne 0 ]; then
+        echo "failed to update /etc/hostname"
+    fi
+    res=`hostname $newname`
+    if [ $? -ne 0 ]; then
+        echo "failed to update hostname"
+    else
+        echo "Your new hostname is $newname"
+    fi
+else
+    echo "hostname already set to $newname"
+fi
diff --git a/resources/puppet/hiera.yaml b/resources/puppet/hiera.yaml
new file mode 100644 (file)
index 0000000..8e2f646
--- /dev/null
@@ -0,0 +1,10 @@
+---
+:backends:
+  - yaml
+  - json
+:yaml:
+  :datadir: /vagrant/resources/puppet/hieradata
+:json:
+  :datadir: /vagrant/resources/puppet/hieradata
+:hierarchy:
+  - hosts
diff --git a/resources/puppet/hieradata/hosts.json b/resources/puppet/hieradata/hosts.json
new file mode 100644 (file)
index 0000000..346a0d6
--- /dev/null
@@ -0,0 +1,28 @@
+{
+  "hosts": {
+    "opendaylight": {
+      "name": "opendaylight",
+      "ipaddress": "192.168.50.1"
+    },
+    "mininet": {
+      "name": "mininet",
+      "ipaddress": "192.168.50.15"
+    },
+    "devstack-control": {
+      "name": "devstack-control",
+      "ipaddress": "192.168.50.20"
+    },
+    "devstack-compute-1": {
+      "name": "devstack-compute-1",
+      "ipaddress": "192.168.50.21"
+    },
+    "devstack-compute-2": {
+      "name": "devstack-compute-2",
+      "ipaddress": "192.168.50.22"
+    },
+    "devstack-compute-3": {
+      "name": "devstack-compute-3",
+      "ipaddress": "192.168.50.23"
+    }
+  }
+}
diff --git a/resources/puppet/manifests/base.pp b/resources/puppet/manifests/base.pp
new file mode 100644 (file)
index 0000000..3f095f2
--- /dev/null
@@ -0,0 +1,12 @@
+package {"git":
+    ensure => "installed"
+}
+
+$hosts = hiera('hosts')
+
+file { "/etc/hosts":
+    ensure => file,
+    owner => "root",
+    group => "root",
+    content => template('/vagrant/resources/puppet/templates/hosts.erb')
+}
diff --git a/resources/puppet/manifests/devstack-compute.pp b/resources/puppet/manifests/devstack-compute.pp
new file mode 100644 (file)
index 0000000..96cb1c2
--- /dev/null
@@ -0,0 +1,16 @@
+vcsrepo { "/home/vagrant/devstack":
+    provider => git,
+    ensure => present,
+    user => "vagrant",
+    source => "https://github.com/openstack-dev/devstack.git",
+    before => File['/home/vagrant/devstack/local.conf']
+}
+
+$hosts = hiera('hosts')
+
+file { "/home/vagrant/devstack/local.conf":
+    ensure => present,
+    owner => "vagrant",
+    group => "vagrant",
+    content => template('/vagrant/resources/puppet/templates/compute.local.conf.erb')
+}
diff --git a/resources/puppet/manifests/devstack-control.pp b/resources/puppet/manifests/devstack-control.pp
new file mode 100644 (file)
index 0000000..0c35e4f
--- /dev/null
@@ -0,0 +1,16 @@
+vcsrepo { "/home/vagrant/devstack":
+    provider => git,
+    ensure => present,
+    user => "vagrant",
+    source => "https://github.com/openstack-dev/devstack.git",
+    before => File['/home/vagrant/devstack/local.conf']
+}
+
+$hosts = hiera('hosts')
+
+file { "/home/vagrant/devstack/local.conf":
+    ensure => present,
+    owner => "vagrant",
+    group => "vagrant",
+    content => template('/vagrant/resources/puppet/templates/control.local.conf.erb')
+}
diff --git a/resources/puppet/manifests/mininet.pp b/resources/puppet/manifests/mininet.pp
new file mode 100644 (file)
index 0000000..97013c3
--- /dev/null
@@ -0,0 +1,104 @@
+$deps = [ 'build-essential',
+          'debhelper',
+          'dkms',
+          'fakeroot',
+          'graphviz',
+          'libssl-dev',
+          'linux-headers-generic',
+          'python-all',
+          'python-qt4',
+          'python-zopeinterface',
+          'python-twisted-conch',
+          'python-twisted-web',
+          'xauth'
+]
+
+package { $deps:
+    ensure   => installed,
+}
+
+vcsrepo { '/home/vagrant/mininet':
+    ensure   => present,
+    provider => git,
+    user     => 'vagrant',
+    source   => 'git://github.com/mininet/mininet',
+    revision => '2.1.0p2',
+    before   => Exec['Install Mininet']
+}
+
+exec { 'Install Mininet':
+    command => 'bash mininet/util/install.sh -nf > /dev/null',
+    cwd     => '/home/vagrant',
+    user    => 'vagrant',
+    path    => $::path,
+    timeout => 0
+}
+
+exec {'openvswitch-2.1.2.tar.gz':
+    command => 'wget http://openvswitch.org/releases/openvswitch-2.1.2.tar.gz',
+    cwd     => '/home/vagrant',
+    path    => $::path,
+    user    => 'vagrant'
+}
+
+exec { 'Extract Open vSwitch':
+    command => 'tar -xvf openvswitch-2.1.2.tar.gz',
+    cwd     => '/home/vagrant',
+    user    => 'vagrant',
+    path    => $::path,
+    timeout => 0,
+    require => Exec['openvswitch-2.1.2.tar.gz']
+}
+
+exec { 'Compile Open vSwitch':
+    command => 'fakeroot debian/rules binary',
+    cwd     => '/home/vagrant/openvswitch-2.1.2',
+    user    => 'root',
+    path    => $::path,
+    timeout => 0,
+    require => [Exec['Extract Open vSwitch'], Package[$deps]]
+}
+
+package { 'openvswitch-common':
+    ensure   => installed,
+    provider => dpkg,
+    source   => '/home/vagrant/openvswitch-common_2.1.2-1_amd64.deb',
+    require  => Exec['Compile Open vSwitch']
+}
+
+package { 'openvswitch-switch':
+    ensure   => installed,
+    provider => dpkg,
+    source   => '/home/vagrant/openvswitch-switch_2.1.2-1_amd64.deb',
+    require  => Package['openvswitch-common']
+}
+
+package { 'openvswitch-datapath-dkms':
+    ensure   => installed,
+    provider => dpkg,
+    source   => '/home/vagrant/openvswitch-datapath-dkms_2.1.2-1_all.deb',
+    require  => Package['openvswitch-switch']
+}
+
+package { 'openvswitch-pki':
+    ensure   => installed,
+    provider => dpkg,
+    source   => '/home/vagrant/openvswitch-pki_2.1.2-1_all.deb',
+    require  => Package['openvswitch-datapath-dkms']
+}
+
+exec { 'Compile Test Controller':
+    command  => 'sh boot.sh && sh configure && make',
+    cwd      => '/home/vagrant/openvswitch-2.1.2',
+    path     => $::path,
+    user     => 'root',
+    require  => [Exec['Compile Open vSwitch'], Package[$deps]]
+}
+
+exec { 'Link Test Controller':
+    command  => 'ln -s /home/vagrant/openvswitch-2.1.2/tests/test-controller /usr/bin/ovs-controller',
+    cwd      => '/home/vagrant/openvswitch-2.1.2',
+    path     => $::path,
+    user     => 'root',
+    require  => Exec['Compile Test Controller']
+}
diff --git a/resources/puppet/scripts/bootstrap.sh b/resources/puppet/scripts/bootstrap.sh
new file mode 100644 (file)
index 0000000..49f285c
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+#
+# This bootstraps Puppet on Ubuntu 12.04 LTS.
+#
+set -e
+
+# Load up the release information
+. /etc/lsb-release
+
+#REPO_DEB_URL="http://apt.puppetlabs.com/puppetlabs-release-${DISTRIB_CODENAME}.deb"
+REPO_DEB_URL="http://apt.puppetlabs.com/puppetlabs-release-stable.deb"
+
+#--------------------------------------------------------------------
+# NO TUNABLES BELOW THIS POINT
+#--------------------------------------------------------------------
+if [ "$(id -u)" != "0" ]; then
+  echo "This script must be run as root." >&2
+  exit 1
+fi
+
+if which puppet > /dev/null 2>&1 -a apt-cache policy | grep --quiet apt.puppetlabs.com; then
+  echo "Puppet is already installed."
+  exit 0
+fi
+
+# Do the initial apt-get update
+echo "Initial apt-get update..."
+apt-get update >/dev/null
+
+# Install wget if we have to (some older Ubuntu versions)
+echo "Installing wget..."
+apt-get install -y wget >/dev/null
+
+# Install the PuppetLabs repo
+echo "Configuring PuppetLabs repo..."
+repo_deb_path=$(mktemp)
+wget --output-document="${repo_deb_path}" "${REPO_DEB_URL}" 2>/dev/null
+dpkg -i "${repo_deb_path}" >/dev/null
+apt-get update >/dev/null
+
+# Install Puppet
+echo "Installing Puppet..."
+DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install puppet >/dev/null
+
+echo "Puppet installed!"
+
+# Install RubyGems for the provider
+echo "Installing RubyGems..."
+if [ $DISTRIB_CODENAME != "trusty" ]; then
+  apt-get install -y rubygems >/dev/null
+fi
+gem install --no-ri --no-rdoc rubygems-update
+update_rubygems >/dev/null
+
+# Installing Puppet Modules
+puppet module install puppetlabs/vcsrepo
+puppet module install puppetlabs/stdlib
diff --git a/resources/puppet/templates/compute.local.conf.erb b/resources/puppet/templates/compute.local.conf.erb
new file mode 100644 (file)
index 0000000..693d416
--- /dev/null
@@ -0,0 +1,55 @@
+[[local|localrc]]
+SCREEN_LOGDIR=/opt/stack/log
+LOGFILE=stack.sh.log
+LOG_COLOR=False
+#OFFLINE=True
+#RECLONE=yes
+
+HOST_IP=<%= @hosts[@hostname]['ipaddress'] %>
+HOST_NAME=<%= @hosts[@hostname]['name'] %>
+SERVICE_HOST=<%= @hosts['devstack-control']['name'] %>
+SERVICE_HOST_NAME=<%= @hosts['devstack-control']['name'] %>
+
+Q_HOST=$SERVICE_HOST
+MYSQL_HOST=$SERVICE_HOST
+RABBIT_HOST=$SERVICE_HOST
+GLANCE_HOSTPORT=$SERVICE_HOST:9292
+KEYSTONE_AUTH_HOST=$SERVICE_HOST
+KEYSTONE_SERVICE_HOST=$SERVICE_HOST
+
+MYSQL_PASSWORD=mysql
+RABBIT_PASSWORD=rabbit
+QPID_PASSWORD=rabbit
+SERVICE_TOKEN=service
+SERVICE_PASSWORD=admin
+ADMIN_PASSWORD=admin
+
+VNCSERVER_PROXYCLIENT_ADDRESS=$HOST_IP
+VNCSERVER_LISTEN=0.0.0.0
+
+disable_all_services
+enable_service neutron quantum nova n-cpu n-novnc rabbit odl-compute
+
+# ODL WITH ML2
+Q_PLUGIN=ml2
+Q_ML2_PLUGIN_MECHANISM_DRIVERS=opendaylight,logger
+ODL_MGR_IP=<%= @hosts['opendaylight']['ipaddress'] %>
+
+ENABLE_TENANT_TUNNELS=True
+# Q_ML2_TENANT_NETWORK_TYPE=vlan
+# ENABLE_TENANT_VLANS=True
+Q_ML2_TENANT_NETWORK_TYPE=vxlan
+#Q_AGENT_EXTRA_AGENT_OPTS=(tunnel_types=vxlan)
+
+#FLOATING_RANGE=192.168.254.64/26
+
+EXTRA_OPTS=(scheduler_default_filters=AllHostsFilter)
+
+[[post-config|/etc/neutron/plugins/ml2/ml2_conf.ini]]
+[agent]
+minimize_polling=True
+
+[ml2_odl]
+url=http://<%= @hosts['opendaylight']['ipaddress'] %>:8080/controller/nb/v2/neutron
+username=admin
+password=admin
diff --git a/resources/puppet/templates/control.local.conf.erb b/resources/puppet/templates/control.local.conf.erb
new file mode 100644 (file)
index 0000000..563d5a9
--- /dev/null
@@ -0,0 +1,64 @@
+[[local|localrc]]
+SCREEN_LOGDIR=/opt/stack/log
+LOGFILE=stack.sh.log
+LOG_COLOR=False
+#OFFLINE=True
+RECLONE=yes
+
+HOST_IP=<%= @hosts['devstack-control']['ipaddress'] %>
+HOST_NAME=<%= @hosts['devstack-control']['name'] %>
+SERVICE_HOST=$HOST_IP
+SERVICE_HOST_NAME=$HOST_NAME
+
+Q_HOST=$SERVICE_HOST
+MYSQL_HOST=$SERVICE_HOST
+RABBIT_HOST=$SERVICE_HOST
+GLANCE_HOSTPORT=$SERVICE_HOST:9292
+KEYSTONE_AUTH_HOST=$SERVICE_HOST
+KEYSTONE_SERVICE_HOST=$SERVICE_HOST
+
+MYSQL_PASSWORD=mysql
+RABBIT_PASSWORD=rabbit
+QPID_PASSWORD=rabbit
+SERVICE_TOKEN=service
+SERVICE_PASSWORD=admin
+ADMIN_PASSWORD=admin
+
+enable_service rabbit
+disable_service qpid
+
+enable_service n-cond
+enable_service n-cpu
+enable_service n-novnc
+disable_service n-net
+enable_service q-svc
+# enable_service q-agt
+enable_service q-dhcp
+enable_service q-l3
+enable_service q-meta
+enable_service quantum
+enable_service odl-compute
+
+# ODL WITH ML2
+Q_PLUGIN=ml2
+Q_ML2_PLUGIN_MECHANISM_DRIVERS=opendaylight,logger
+ODL_MGR_IP=<%= @hosts['opendaylight']['ipaddress'] %>
+
+ENABLE_TENANT_TUNNELS=True
+# ENABLE_TENANT_VLANS=True
+# TENANT_VLAN_RANGE=500:510
+
+Q_ML2_TENANT_NETWORK_TYPE=vxlan
+# Q_AGENT_EXTRA_AGENT_OPTS=(tunnel_types=vxlan)
+
+#FLOATING_RANGE=192.168.254.64/26
+#PUBLIC_NETWORK_GATEWAY=192.168.75.254
+
+[[post-config|/etc/neutron/plugins/ml2/ml2_conf.ini]]
+[agent]
+minimize_polling=True
+
+[ml2_odl]
+url=http://<%= @hosts['opendaylight']['ipaddress'] %>:8080/controller/nb/v2/neutron
+username=admin
+password=admin
diff --git a/resources/puppet/templates/hosts.erb b/resources/puppet/templates/hosts.erb
new file mode 100644 (file)
index 0000000..c23f40f
--- /dev/null
@@ -0,0 +1,8 @@
+## Do Not Edit. Created by Puppet ##
+127.0.0.1   localhost
+255.255.255.255 broadcasthost
+::1             localhost
+fe80::1%lo0 localhost
+<% @hosts.values.each do |h| %>
+<%= h["ipaddress"] %>  <%= h["name"] %>
+<% end %>
diff --git a/resources/robot/README.md b/resources/robot/README.md
new file mode 100644 (file)
index 0000000..94bee67
--- /dev/null
@@ -0,0 +1,48 @@
+# Purpose
+1)
+Creates VMs running CentOS 7.0 x64 with OpenVSwitch.
+Please use the Vagrant environment variable OVS_NODES to set the number of VMs that would be created. Default value is 2 (ovs1 and ovs2).
+
+2)
+Sets up Robot framework in the first VM (ovs1). Subsequent VMs are will only have OVS
+
+# About the included OVS rpm
+To improve provisioning time, "openvswitch-2.3.1-1.x86_64.rpm" is pulled from dropbox. You can add rpm files for other OVS version if desired. Default ovs version is 2.3.1.
+
+To build ovs for the VMs from source, open the vagrant file and make changes to :
+
+Line 19: ovsversion = "<desired_ovs_release>"
+Line 50: puppet.manifest_file  = "ovsnode_build.pp"
+
+# Running integration tests for OVSDB
+
+After the VMs are provisioned. ssh into ovs1 to run integration tests for OVSDB
+
+        user@machine$ vagrant ssh ovs1
+        vagrant@ovs1:~\> sh run_robot_tests.sh
+
+# OpenDaylight Controller
+
+The controller should be running on the host machine before you run the integration tests. The VMs are setup with environmental variable $CONTROLLER with the default IP: 192.168.100.1
+
+Note: Restarting karaf at the begining of each test run probably helps generate fewer false positives.
+
+# Output and log from each test
+
+The output and logs for each test will be left in ovs1 home directory. For convinience of accessing the test results at a later time from the host machine, check "robot/scripts/results" for the result of the current and previous tests. Those are timestamped and cumulated over time. You are responsible for cleaning up this cache.
+
+# To run specific patches
+
+This script will automatically download the latest version of the master branch of the integration project. If you need to test a specific patch, open run_robot_tests.sh on the home directory of ovs1
+
+Edit the git clone url as desired
+
+        sudo git clone https://git.opendaylight.org/gerrit/integration
+
+# To run integration tests for other projects
+
+If this is temporary, edit line 17 of run_robot_tests.sh in the home directory of ovs1.
+
+        export test_suite_dir="$HOME/integration/test/csit/suites/ovsdb/"
+
+For a permanent change, make the edits described above in the version of this file in robot/scripts and re-provision your VM.
diff --git a/resources/robot/Vagrantfile b/resources/robot/Vagrantfile
new file mode 100644 (file)
index 0000000..e7c327a
--- /dev/null
@@ -0,0 +1,102 @@
+# -*- mode: ruby -*-
+# # vi: set ft=ruby :
+
+# Specify minimum Vagrant version and Vagrant API version
+Vagrant.require_version ">= 1.6.0"
+VAGRANTFILE_API_VERSION = "2"
+
+# Create boxes
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+
+# Get the number of OVS VMs to create
+num_ovs_vms = (ENV['OVS_NODES'] || 2).to_i
+
+base_name = "ovs"
+base_ip = "192.168.100."
+controller_ip = "192.168.100.1"
+os = "puppetlabs/centos-7.0-64-puppet"
+ram = "512"
+ovsversion = "2.3.1"
+vagrant_pwd="vagrant"
+ovs_node_ips = num_ovs_vms.times.collect { |n| base_ip + "#{n+21}" }
+
+num_ovs_vms.times do |n|
+    #config.ssh.password = vagrant_pwd
+    config.vm.define base_name + "#{n+1}", autostart: true do |srv|
+          ## Extract yaml variables
+          hostname = base_name + "#{n+1}"
+          local_ip = ovs_node_ips[n]
+
+          srv.vm.hostname = hostname
+          srv.vm.box = os
+          srv.vm.network "private_network", ip: local_ip
+          srv.vm.provider :virtualbox do |vb|
+        vb.name = hostname
+        vb.memory = ram
+     end # vb
+
+          # Set guest environment variables
+          command1 = 'export CONTROLLER=\"' + controller_ip + '\"'
+          srv.vm.provision :shell, privileged: true, inline: 'echo ' + command1 + ' >> /etc/profile'
+
+          # Create the mininet vm ips
+          num_ovs_vms.times do |m|
+             mininet_ip = ovs_node_ips[m]
+             command = 'export MININET' + "#{m}" + '=\"' + mininet_ip + '\"'
+             srv.vm.provision :shell, privileged: true, inline: 'echo ' + command + ' >> /etc/profile'
+          end
+
+          srv.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
+
+          ## SSH config
+          srv.ssh.forward_x11 = false
+
+          ## puppet
+          srv.vm.provision "puppet" do |puppet|
+            puppet.working_directory = "/vagrant/puppet"
+            puppet.manifests_path = "puppet/manifests"
+            puppet.manifest_file  = "ovsnode.pp"
+            puppet.options = "--verbose --debug"
+            puppet.facter = {
+              "ovsversion" => ovsversion,
+            }
+          end # puppet
+
+          # process setup commands for ovs
+          #srv.vm.provision "shell", path: "puppet/scripts/setup_defaults.sh"
+
+          if n==0
+             # setup robot framework
+             srv.vm.provision "shell", path: "scripts/setup_robot_framework.sh", privileged: false
+
+             # create the ssh key
+             srv.vm.provision "shell", path: "scripts/create_ssh_key.sh", privileged: false
+          else
+             # run special configurations on the mininet
+             srv.vm.provision "shell", path: "scripts/setup_other_mininets.sh", privileged: false
+          end
+
+          # perform special configuration - requires root permission
+          srv.vm.provision "shell", path: "scripts/special_robot_configuration.sh"
+
+          # set the guest vm date and time from the host machine
+          # this only works for debian based linux
+          # hopefully we can add other OS compatible commands in the future
+
+          time_zone = ""
+
+          begin
+            time_zone = `sudo cat /etc/timezone`
+          rescue Exception => e
+            srv.vm.provision "shell", inline: "failed to get host OS time-zone, default to EST"
+
+            # default to EST
+            time_zone = "America/New_York"
+          end
+
+          # set the time zone in the guest OS
+          srv.vm.provision "shell", path: "scripts/ovs_vm_host_timezone_map.sh", args:time_zone
+
+        end # srv
+    end #end num_ovs_vms
+end # config
diff --git a/resources/robot/puppet/manifests/dependencies.pp b/resources/robot/puppet/manifests/dependencies.pp
new file mode 100644 (file)
index 0000000..c264b40
--- /dev/null
@@ -0,0 +1,21 @@
+  $base_packages = [
+    "kernel-headers",
+    "kernel-devel",
+    "gcc",
+    "make",
+    "python-devel",
+    "openssl-devel",
+    "graphviz",
+    "kernel-debug-devel",
+    "automake",
+    "rpm-build",
+    "redhat-rpm-config",
+    "libtool",
+    "git"
+  ]
+
+  package { $base_packages:
+    ensure => installed,
+  }
+
+  notice("Dependencies are ready!")
diff --git a/resources/robot/puppet/manifests/ovsnode.pp b/resources/robot/puppet/manifests/ovsnode.pp
new file mode 100644 (file)
index 0000000..400442e
--- /dev/null
@@ -0,0 +1,39 @@
+  notice("specified ovs version to install: ${ovsversion}")
+
+  exec { "mktarget":
+    command => "/bin/mkdir -p /vagrant/shared/",
+    cwd     => "/",
+  }
+
+  file { [
+           "/vagrant/shared/",
+         ]:
+    ensure => directory,
+  }
+
+  exec { "download_ovs":
+    command => "/usr/bin/wget https://www.dropbox.com/s/v34fbw6t0mvtoi8/openvswitch-${ovsversion}-1.x86_64.rpm?dl=0 -O /vagrant/shared/openvswitch-${ovsversion}-1.x86_64.rpm",
+    cwd     => "/root",
+    creates => "/vagrant/shared/openvswitch-${ovsversion}-1.x86_64.rpm",
+    require => [
+                  Exec["mktarget"],
+               ],
+  }
+
+  exec { "install_ovs":
+    command => "yum localinstall -y /vagrant/shared/openvswitch-${ovsversion}-1.x86_64.rpm",
+    cwd => "/root",
+    path    => ["/bin", "/usr/bin"],
+    require => [
+                  Exec["download_ovs"],
+               ],
+  }
+
+  exec { "start_ovs":
+    command => "systemctl start openvswitch.service",
+    require => [
+                  Exec["install_ovs"],
+               ],
+    cwd => "/root",
+    path    => ["/bin", "/usr/bin"],
+  }
diff --git a/resources/robot/puppet/manifests/ovsnode_build.pp b/resources/robot/puppet/manifests/ovsnode_build.pp
new file mode 100644 (file)
index 0000000..8fe0050
--- /dev/null
@@ -0,0 +1,88 @@
+  import 'dependencies.pp'
+
+  notice("specified ovs version to install: ${ovsversion}")
+
+  exec { "mksource":
+    command => "/bin/mkdir -p /rpmbuild/SOURCES/",
+    cwd     => "/",
+  }
+
+  file { [
+           "/rpmbuild/",
+           "/rpmbuild/SOURCES/",
+         ]:
+    ensure => directory,
+  }
+
+  exec { "download_ovs":
+    command => "wget http://openvswitch.org/releases/openvswitch-${ovsversion}.tar.gz -O /root/openvswitch-${ovsversion}.tar.gz",
+    creates => "/root/openvswitch-${ovsversion}.tar.gz",
+    cwd    => "/root",
+    path    => ["/bin", "/usr/bin"],
+  }
+
+  exec { "check_presence":
+    command => "true",
+    onlyif  => "/usr/bin/test -e /rpmbuild/SOURCES",
+    path    => ["/bin", "/usr/bin"],
+  }
+
+  exec { "copy_archive":
+    command => "cp /root/openvswitch-${ovsversion}.tar.gz /rpmbuild/SOURCES/openvswitch-${ovsversion}.tar.gz",
+    require => [
+                  Exec["mksource"],
+                  Exec["download_ovs"],
+                  Exec["check_presence"],
+               ],
+    cwd    => "/root",
+    creates => "/rpmbuild/SOURCES/openvswitch-${ovsversion}.tar.gz",
+    path    => ["/bin", "/usr/bin"],
+  }
+
+  exec { "extract_ovs":
+    command => "tar xvfz /root/openvswitch-${ovsversion}.tar.gz",
+    require => [
+                  Exec["copy_archive"],
+               ],
+    path    => ["/bin", "/usr/bin"],
+    cwd     => "/root",
+    creates => "/root/openvswitch-${ovsversion}/README",
+  }
+
+  exec { "custom_sed":
+    command => "sed 's/openvswitch-kmod, //g' /root/openvswitch-${ovsversion}/rhel/openvswitch.spec > /root/openvswitch-${ovsversion}/rhel/openvswitch_no_kmod.spec",
+    require => [
+                  Exec["extract_ovs"],
+               ],
+    cwd => "/root",
+    path    => ["/bin", "/usr/bin"],
+  }
+
+  exec { "build_ovs":
+    command => "rpmbuild -bb --nocheck /root/openvswitch-${ovsversion}/rhel/openvswitch_no_kmod.spec",
+    cwd => "/root",
+    path    => ["/bin", "/usr/bin"],
+    require => [
+                  Exec["custom_sed"],
+               ],
+    timeout     => 0,
+    creates => "/root/rpmbuild/RPMS/x86_64/openvswitch-${ovsversion}-1.x86_64.rpm",
+  }
+
+  exec { "install_ovs":
+    command => "yum localinstall -y /rpmbuild/RPMS/x86_64/openvswitch-${ovsversion}-1.x86_64.rpm",
+    cwd => "/root",
+    path    => ["/bin", "/usr/bin"],
+    require => [
+                  Exec["build_ovs"],
+               ],
+  }
+
+  exec { "start_ovs":
+    command => "systemctl start openvswitch.service",
+    require => [
+                  Exec["install_ovs"],
+               ],
+    cwd => "/root",
+    path    => ["/bin", "/usr/bin"],
+  }
diff --git a/resources/robot/puppet/scripts/clear_ovs.sh b/resources/robot/puppet/scripts/clear_ovs.sh
new file mode 100755 (executable)
index 0000000..e48d6d6
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+#
+
+sudo service openvswitch-switch stop
+sudo rm -rf /var/log/openvswitch/*
+sudo rm -rf /etc/openvswitch/conf.db
+sudo service openvswitch-switch start
+
diff --git a/resources/robot/puppet/scripts/setup_defaults.sh b/resources/robot/puppet/scripts/setup_defaults.sh
new file mode 100644 (file)
index 0000000..577ff48
--- /dev/null
@@ -0,0 +1,11 @@
+# add a bridge
+sudo ovs-vsctl add-br ovs-br0
+
+# add a port to the bridge
+#sudo ovs-vsctl add-port ovs-br0 eth1
+
+# link the bridge the controller
+sudo ovs-vsctl set-controller ovs-br0 tcp:$CONTROLLER:6633
+
+# link the controller as a manager
+sudo ovs-vsctl set-manager tcp:$CONTROLLER:6640
diff --git a/resources/robot/scripts/clear_ovs.sh b/resources/robot/scripts/clear_ovs.sh
new file mode 100755 (executable)
index 0000000..e48d6d6
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+#
+
+sudo service openvswitch-switch stop
+sudo rm -rf /var/log/openvswitch/*
+sudo rm -rf /etc/openvswitch/conf.db
+sudo service openvswitch-switch start
+
diff --git a/resources/robot/scripts/create_ssh_key.sh b/resources/robot/scripts/create_ssh_key.sh
new file mode 100644 (file)
index 0000000..5010f05
--- /dev/null
@@ -0,0 +1,14 @@
+# create the ssh key
+if [ ! -f ~/.ssh/id_rsa ]; then
+    echo "creating ssh key..."
+    ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
+    cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
+    sudo chmod 600 ~/.ssh/authorized_keys
+fi
+
+# copy this key to vagrant folder
+cp ~/.ssh/id_rsa.pub /vagrant/shared
+
+#Modify the user prompt termination from "$" to ">"
+echo "PS1='\u@\h:\w\> '" >> ~/.bashrc
+source ~/.bashrc
diff --git a/resources/robot/scripts/ovs_vm_host_timezone_map.sh b/resources/robot/scripts/ovs_vm_host_timezone_map.sh
new file mode 100644 (file)
index 0000000..8c9881a
--- /dev/null
@@ -0,0 +1,2 @@
+# set the time zone of the guest OS
+sudo timedatectl set-timezone $1
diff --git a/resources/robot/scripts/run_robot_tests.sh b/resources/robot/scripts/run_robot_tests.sh
new file mode 100644 (file)
index 0000000..9ca5e11
--- /dev/null
@@ -0,0 +1,70 @@
+# clear OVS setup
+sh /vagrant/scripts/clear_ovs.sh
+
+# down the integration codes
+if [ -d integration/test/csit/suites ]; then
+    echo "refreshing test scripts"
+    cd integration
+    sudo git pull
+    cd ~
+else
+   echo "downloading integration..."
+   sudo git clone https://git.opendaylight.org/gerrit/integration
+fi
+
+# show the environmental variables
+printf "CONTROLLER IP:%s\n" "$CONTROLLER"
+printf "MININET VM IP:%s\n" "$MININET0"
+printf "MININETII VM IP:%s\n" "$MININET1"
+
+export test_suite_dir="$HOME/integration/test/csit/suites/ovsdb/"
+
+echo "Waiting for controller to come up..."
+COUNT="0"
+while true; do
+    # if you are using this outside ovsdb, check if ODL modules are loaded by removing the commented line below
+    # RESP=`curl --user admin:admin -sL -w "%{http_code} %{url_effective}\\n" http://$CONTROLLER:8181/restconf/modules -o /dev/null`
+
+    # ensure that netvirt topology is loaded by ODL
+    RESP=`curl --user admin:admin -sL -w "%{http_code} %{url_effective}\\n" http://$CONTROLLER:8080/restconf/operational/network-topology:network-topology/topology/netvirt:1 -o /dev/null`
+    echo $RESP
+    if [[ $RESP == *"200"* ]]; then
+        echo Controller is UP
+        break
+    fi
+
+    # exit if this goes on for a while
+    if (( "$COUNT" > "600" )); then
+        echo Timeout Controller DOWN
+        exit 1
+    else
+        COUNT=$(( ${COUNT} + 5 ))
+        echo waiting $COUNT secs...
+        sleep 5
+    fi
+done
+
+echo "Cool down for 10 seconds :)..."
+sleep 10
+sudo pybot -v CONTROLLER:$CONTROLLER -v MININET:$MININET0 -v MININET1:$MININET1 -v USER_HOME:$HOME -v MININET_USER:$USER $test_suite_dir
+
+# export the results
+if [ ! -d /vagrant/scripts/results ]; then
+    echo "creating results folder"
+    mkdir /vagrant/scripts/results
+fi
+
+# move test output to the shared results folder
+#  -- output.xml, log.html and report.html generated
+#     after each run is saved in a shared timestamp folder
+#     under /vagrant/scripts/results
+
+timestamp=$(date +'%Y.%m.%d-%H.%M.%S')
+mkdir /vagrant/scripts/results/$timestamp
+cp $PWD/output.xml /vagrant/scripts/results/$timestamp/output.xml
+cp $PWD/log.html /vagrant/scripts/results/$timestamp/log.html
+cp $PWD/report.html /vagrant/scripts/results/$timestamp/report.html
+
+
+
+
diff --git a/resources/robot/scripts/setup_other_mininets.sh b/resources/robot/scripts/setup_other_mininets.sh
new file mode 100644 (file)
index 0000000..9e1c4fe
--- /dev/null
@@ -0,0 +1,8 @@
+# add the ssh to authorized keys
+cat /vagrant/shared/id_rsa.pub >> ~/.ssh/authorized_keys
+sudo chmod 600 ~/.ssh/authorized_keys
+
+#Modify the user prompt termination from "$" to ">"
+echo "PS1='\u@\h:\w\> '" >> ~/.bashrc
+source ~/.bashrc
+
diff --git a/resources/robot/scripts/setup_robot_framework.sh b/resources/robot/scripts/setup_robot_framework.sh
new file mode 100644 (file)
index 0000000..6cf5bd4
--- /dev/null
@@ -0,0 +1,22 @@
+#ensure that CentOS5/EL5 repo is setup
+cd /tmp
+sudo wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/e/
+sudo rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-*.rpm
+
+#install git
+sudo yum install -y git
+
+# python is already installed.
+# install python-pip and python-paramiko
+sudo yum install -y python-pip
+sudo yum install -y python-paramiko
+
+#install the robot framework and required libraries
+sudo pip install requests
+sudo pip install robotframework
+sudo pip install robotframework-sshlibrary
+sudo pip install -U robotframework-requests
+sudo pip install --upgrade robotframework-httplibrary
+
+#copy the robot trigger code to user home
+cp /vagrant/scripts/run_robot_tests.sh ~/
diff --git a/resources/robot/scripts/special_robot_configuration.sh b/resources/robot/scripts/special_robot_configuration.sh
new file mode 100644 (file)
index 0000000..b4571a2
--- /dev/null
@@ -0,0 +1,7 @@
+#Allow sudo access with no password
+echo "vagrant ALL=NOPASSWD: ALL" >>/etc/sudoers
+
+#disable reverse IP resolution on the VM
+echo "UseDNS no" >>/etc/ssh/sshd_config
+
+echo "Provisioning complete"
diff --git a/utils/config/pom.xml b/utils/config/pom.xml
new file mode 100644 (file)
index 0000000..0ab3231
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>utils.config</artifactId>
+  <name>${project.artifactId}</name>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <dependencies>
+    <!-- testing dependencies -->
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/utils/config/src/main/java/org/opendaylight/netvirt/utils/config/ConfigProperties.java b/utils/config/src/main/java/org/opendaylight/netvirt/utils/config/ConfigProperties.java
new file mode 100644 (file)
index 0000000..acf3140
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 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.utils.config;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ConfigProperties {
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigProperties.class);
+    private static final Map<String, String> OVERRIDES = new HashMap<>();
+
+    private ConfigProperties() {
+        // empty
+    }
+
+    public static String getProperty(Class<?> classParam, final String propertyStr) {
+        return getProperty(classParam, propertyStr, null);
+    }
+
+    public static String getProperty(Class<?> classParam, final String propertyStr, final String defaultValue) {
+        String value = ConfigProperties.OVERRIDES.get(propertyStr);
+        if (value != null) {
+            return value;
+        }
+
+        Bundle bundle = FrameworkUtil.getBundle(classParam);
+
+        if (bundle != null) {
+            BundleContext bundleContext = bundle.getBundleContext();
+            if (bundleContext != null) {
+                value = bundleContext.getProperty(propertyStr);
+            }
+        }
+        if (value == null) {
+            value = System.getProperty(propertyStr, defaultValue);
+        }
+
+        if (value == null) {
+            LOG.debug("ConfigProperties missing a value for {}, default {}", propertyStr, defaultValue);
+        }
+
+        return value;
+    }
+
+    public static void overrideProperty(String property, String value) {
+        ConfigProperties.OVERRIDES.put(property, value);
+    }
+}
diff --git a/utils/config/src/test/java/org/opendaylight/netvirt/utils/config/ConfigPropertiesTest.java b/utils/config/src/test/java/org/opendaylight/netvirt/utils/config/ConfigPropertiesTest.java
new file mode 100644 (file)
index 0000000..90cc403
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+* Copyright (C) 2014 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
+*
+* Authors : Flavio Fernandes
+*/
+package org.opendaylight.netvirt.utils.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.powermock.api.mockito.PowerMockito;
+import org.osgi.framework.FrameworkUtil;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest( {System.class, FrameworkUtil.class} )
+ public class ConfigPropertiesTest {
+
+    private static final String TEST_PROPERTY_KEY1 = "foobar34465$3467";
+    private static final String TEST_PROPERTY_MOCK_VALUE1 = "xbarMock1";
+    private static final String TEST_PROPERTY_KEY2 = "foobar34465$3468";
+    private static final String TEST_PROPERTY_MOCK_VALUE2 = "xbarMock2";
+    private static final String TEST_PROPERTY_KEY_NOT_FOUND = "foobarKey2_12445^%346";
+    private static final String DEFAULT_PROPERTY_VALUE = "xbarDefaultValue";
+
+    @Test
+    public void testGetProperty() {
+        Bundle bundleWithoutBundleNoContext = mock(Bundle.class);
+        Bundle bundle = mock(Bundle.class);
+        BundleContext bundleContext = mock(BundleContext.class);
+
+        // mock #1
+        PowerMockito.mockStatic(FrameworkUtil.class);
+        PowerMockito.when(FrameworkUtil.getBundle(this.getClass())).thenReturn(bundle);
+        PowerMockito.when(FrameworkUtil.getBundle(ConfigPropertiesTestMockingBundleNoContext.class))
+                .thenReturn(bundleWithoutBundleNoContext);
+        // mock #2
+        when(bundle.getBundleContext()).thenReturn(bundleContext);
+        when(bundleWithoutBundleNoContext.getBundleContext()).thenReturn(null);
+        // mock #3
+        when(bundleContext.getProperty(eq(TEST_PROPERTY_KEY1))).thenReturn(TEST_PROPERTY_MOCK_VALUE1);
+        // mock #4
+        // PowerMockito.mockStatic(System.class);
+        // PowerMockito.when(System.getProperty(eq(TEST_PROPERTY_KEY2))).thenReturn(TEST_PROPERTY_MOCK_VALUE2);
+        // NOTE: The mock #4 above is not supported by PowerMockito. To work around this limitation,
+        // we will simply add the property explicitly into System (instead of the solution mentioned in link below).
+        // See: http://javax0.wordpress.com/2013/01/29/how-to-mock-the-system-class/
+        System.setProperty(TEST_PROPERTY_KEY2, TEST_PROPERTY_MOCK_VALUE2);
+
+        // test 1. bundle is null, returned from a mock
+        assertNull(FrameworkUtil.getBundle(ConfigPropertiesTestMocking.class));
+        assertEquals(FrameworkUtil.getBundle(ConfigPropertiesTest.class), bundle);
+        assertEquals(FrameworkUtil.getBundle(ConfigPropertiesTestMockingBundleNoContext.class),
+                     bundleWithoutBundleNoContext);
+
+        // test 2. bundleContext is null
+        assertNull(bundleWithoutBundleNoContext.getBundleContext());
+        assertEquals(bundle.getBundleContext(), bundleContext);
+
+        // test 3. value returned from bundleContext.getProperty() is null.
+        // Then System.getProperty() is called and can return a valid value if key is found.
+        final String value31 = ConfigProperties.getProperty(this.getClass(), TEST_PROPERTY_KEY2);
+        assertEquals(TEST_PROPERTY_MOCK_VALUE2, value31);
+
+        // test 4. value returned from ConfigProperties.getProperty is null
+        final String value41 = ConfigProperties.getProperty(ConfigPropertiesTestMocking.class, TEST_PROPERTY_KEY1);
+        assertNull(value41);  // class has no bundle
+        final String value42 = ConfigProperties.getProperty(ConfigPropertiesTestMockingBundleNoContext.class,
+                                                            TEST_PROPERTY_KEY1);
+        assertNull(value42);  // class has no bundleContext
+        final String value43 = ConfigProperties.getProperty(this.getClass(), TEST_PROPERTY_KEY_NOT_FOUND);
+        assertNull(value43);  // bundleContext will not know about key provided
+
+        // test 5. value returned from ConfigProperties.getProperty is the default value provided
+        final String value5 = ConfigProperties.getProperty(this.getClass(), TEST_PROPERTY_KEY_NOT_FOUND, DEFAULT_PROPERTY_VALUE);
+        assertEquals(DEFAULT_PROPERTY_VALUE, value5);
+
+        // test 6. value returned from ConfigProperties.getProperty is the mocked value
+        final String value61 = ConfigProperties.getProperty(this.getClass(), TEST_PROPERTY_KEY1);
+        assertEquals(TEST_PROPERTY_MOCK_VALUE1, value61);
+        final String value62 = ConfigProperties.getProperty(this.getClass(), TEST_PROPERTY_KEY1, DEFAULT_PROPERTY_VALUE);
+        assertEquals(TEST_PROPERTY_MOCK_VALUE1, value62);
+    }
+
+    // Helper classes used to de-mux mock behaviors
+    private class ConfigPropertiesTestMockingBundleNoContext {
+    }
+    private class ConfigPropertiesTestMocking {
+    }
+}
diff --git a/utils/mdsal-openflow/pom.xml b/utils/mdsal-openflow/pom.xml
new file mode 100644 (file)
index 0000000..8f3c04a
--- /dev/null
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>utils.mdsal-openflow</artifactId>
+  <name>${project.artifactId}</name>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <properties>
+    <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
+  </properties>
+
+  <dependencies>
+    <!-- controller dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-inventory</artifactId>
+    </dependency>
+    <!-- mdsal dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>opendaylight-l2-types</artifactId>
+    </dependency>
+    <!-- openflowplugin dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-base</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-api</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <!-- testing dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.netvirt.utils.mdsal.openflow
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/ActionUtils.java b/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/ActionUtils.java
new file mode 100644 (file)
index 0000000..4b7863c
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2014 - 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.utils.mdsal.openflow;
+
+import com.google.common.collect.Lists;
+import com.google.common.net.InetAddresses;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
+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.PopVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
+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.action.pop.vlan.action._case.PopVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder;
+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.action.types.rev131112.address.Address;
+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.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxHashFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxMpAlgorithm;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
+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.DstNxArpShaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpThaCaseBuilder;
+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.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.dst.choice.grouping.dst.choice.DstOfArpOpCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpSpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpTpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfEthDstCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfIpDstCaseBuilder;
+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.NxActionConntrackNodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionMultipathNodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder;
+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.apply.actions._case.apply.actions.action.action.NxActionResubmitNodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder;
+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.NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.conntrack.grouping.NxConntrack;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.conntrack.grouping.NxConntrackBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.multipath.grouping.NxMultipath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.multipath.grouping.NxMultipathBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputReg;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputRegBuilder;
+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.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.NxResubmit;
+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.nx.action.set.nshc._1.grouping.NxSetNshc1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsiBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNspBuilder;
+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.SrcNxArpShaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc1CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc2CaseBuilder;
+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.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIpv4DstCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfArpSpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfEthSrcCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfIpSrcCaseBuilder;
+
+import java.math.BigInteger;
+import java.util.List;
+
+public final class ActionUtils {
+    public static Action dropAction() {
+        return new DropActionCaseBuilder()
+            .setDropAction(new DropActionBuilder()
+                .build())
+            .build();
+    }
+
+    public static Action outputAction(NodeConnectorId id) {
+        return new OutputActionCaseBuilder()
+            .setOutputAction(new OutputActionBuilder()
+                .setOutputNodeConnector(new Uri(id.getValue()))
+                .build())
+            .build();
+    }
+
+    public static Action groupAction(Long id) {
+        return new GroupActionCaseBuilder()
+            .setGroupAction(new GroupActionBuilder()
+                .setGroupId(id)
+                .build())
+            .build();
+    }
+
+    public static Action popVlanAction() {
+        return new PopVlanActionCaseBuilder()
+            .setPopVlanAction(new PopVlanActionBuilder()
+                    .build())
+            .build();
+    }
+
+    public static Action setDlSrcAction(MacAddress mac) {
+        return new SetDlSrcActionCaseBuilder()
+            .setSetDlSrcAction(new SetDlSrcActionBuilder()
+                .setAddress(mac)
+                .build())
+            .build();
+    }
+
+    public static Action setDlDstAction(MacAddress mac) {
+        return new SetDlDstActionCaseBuilder()
+            .setSetDlDstAction(new SetDlDstActionBuilder()
+                .setAddress(mac)
+                .build())
+            .build();
+    }
+
+    public static Action setNwSrcAction(Address ip) {
+        return new SetNwSrcActionCaseBuilder()
+            .setSetNwSrcAction(new SetNwSrcActionBuilder()
+                .setAddress(ip)
+                .build())
+            .build();
+    }
+
+    public static Action setNwDstAction(Address ip) {
+        return new SetNwDstActionCaseBuilder()
+            .setSetNwDstAction(new SetNwDstActionBuilder()
+                .setAddress(ip)
+                .build())
+            .build();
+    }
+
+    public static Action decNwTtlAction() {
+        return new DecNwTtlCaseBuilder()
+            .setDecNwTtl(new DecNwTtlBuilder()
+                .build())
+            .build();
+    }
+
+    public static Action setTunnelIdAction(BigInteger tunnelId) {
+
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Build the Set Tunnel Field Action
+        TunnelBuilder tunnel = new TunnelBuilder();
+        tunnel.setTunnelId(tunnelId);
+        setFieldBuilder.setTunnel(tunnel.build());
+
+        return new SetFieldCaseBuilder()
+                .setSetField(setFieldBuilder.build())
+                .build();
+    }
+
+    public static Action nxLoadRegAction(DstChoice dstChoice,
+                                         BigInteger value,
+                                         int endOffset,
+                                         boolean groupBucket) {
+        NxRegLoad r = new NxRegLoadBuilder()
+            .setDst(new DstBuilder()
+                .setDstChoice(dstChoice)
+                .setStart(0)
+                .setEnd(endOffset)
+                .build())
+            .setValue(value)
+            .build();
+        if (groupBucket) {
+            return new NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder()
+                .setNxRegLoad(r).build();
+        } else {
+            return new NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder()
+                .setNxRegLoad(r).build();
+        }
+    }
+
+    public static Action nxLoadRegAction(DstChoice dstChoice,
+                                         BigInteger value) {
+        return nxLoadRegAction(dstChoice, value, 31, false);
+    }
+
+    public static Action nxLoadRegAction(Class<? extends NxmNxReg> reg,
+                                         BigInteger value) {
+        return nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(reg).build(),
+                               value);
+    }
+
+    public static Action nxLoadTunIPv4Action(String ipAddress,
+                                             boolean groupBucket) {
+        int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress));
+        long ipl = ip & 0xffffffffL;
+        return nxLoadRegAction(new DstNxTunIpv4DstCaseBuilder()
+                                    .setNxTunIpv4Dst(Boolean.TRUE).build(),
+                               BigInteger.valueOf(ipl),
+                               31,
+                               groupBucket);
+    }
+
+    public static Action nxLoadArpOpAction(BigInteger value) {
+        return nxLoadRegAction(new DstOfArpOpCaseBuilder()
+            .setOfArpOp(Boolean.TRUE).build(), value, 15, false);
+    }
+
+    public static Action nxLoadArpShaAction(MacAddress macAddress) {
+        return nxLoadArpShaAction(BigInteger.valueOf(toLong(macAddress)));
+    }
+    public static Action nxLoadArpShaAction(BigInteger value) {
+        return nxLoadRegAction(new DstNxArpShaCaseBuilder()
+            .setNxArpSha(Boolean.TRUE).build(), value, 47, false);
+    }
+
+    public static Action nxLoadArpSpaAction(BigInteger value) {
+        return nxLoadRegAction(new DstOfArpSpaCaseBuilder()
+            .setOfArpSpa(Boolean.TRUE).build(), value);
+    }
+
+    public static Action nxLoadArpSpaAction(String ipAddress) {
+        int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress));
+        long ipl = ip & 0xffffffffL;
+        return nxLoadArpSpaAction(BigInteger.valueOf(ipl));
+    }
+
+    public static Action setIcmpTypeAction(byte value) {
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+        setFieldBuilder.setIcmpv4Match(new Icmpv4MatchBuilder().setIcmpv4Type((short)value).build());
+        return new SetFieldCaseBuilder()
+                .setSetField(setFieldBuilder.build())
+                .build();
+    }
+
+    public static Action nxMoveRegAction(SrcChoice srcChoice,
+                                         DstChoice dstChoice,
+                                         int endOffset,
+                                         boolean groupBucket) {
+        return nxMoveRegAction(srcChoice, dstChoice, 0, 0, endOffset, groupBucket);
+    }
+
+    public static Action nxMoveRegAction(SrcChoice srcChoice,
+                                         DstChoice dstChoice,
+                                         int srcStartOffset,
+                                         int dstStartOffset,
+                                         int dstEndOffset,
+                                         boolean groupBucket) {
+        NxRegMove r = new NxRegMoveBuilder()
+            .setSrc(new SrcBuilder()
+                .setSrcChoice(srcChoice)
+                .setStart(srcStartOffset)
+                .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(r).build();
+        } else {
+            return new NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder()
+                .setNxRegMove(r).build();
+        }
+    }
+
+    public static Action nxMoveRegAction(SrcChoice srcChoice,
+                                         DstChoice dstChoice) {
+        return nxMoveRegAction(srcChoice, dstChoice, 31, false);
+    }
+
+    public static Action nxMoveRegTunIdAction(Class<? extends NxmNxReg> src,
+                                              boolean groupBucket) {
+        return nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(src).build(),
+                               new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
+                               31,
+                               groupBucket);
+    }
+
+    public static Action nxMoveArpShaToArpThaAction() {
+        return nxMoveRegAction(new SrcNxArpShaCaseBuilder().setNxArpSha(Boolean.TRUE).build(),
+                               new DstNxArpThaCaseBuilder().setNxArpTha(Boolean.TRUE).build(),
+                               47, false);
+    }
+
+    public static Action nxMoveEthSrcToEthDstAction() {
+        return nxMoveRegAction(new SrcOfEthSrcCaseBuilder().setOfEthSrc(Boolean.TRUE).build(),
+                               new DstOfEthDstCaseBuilder().setOfEthDst(Boolean.TRUE).build(),
+                               47, false);
+    }
+
+    public static Action nxMoveArpSpaToArpTpaAction() {
+        return nxMoveRegAction(new SrcOfArpSpaCaseBuilder().setOfArpSpa(Boolean.TRUE).build(),
+                               new DstOfArpTpaCaseBuilder().setOfArpTpa(Boolean.TRUE).build());
+    }
+
+    public static Action nxMoveIpSrcToIpDstAction() {
+        return nxMoveRegAction(new SrcOfIpSrcCaseBuilder().setOfIpSrc(Boolean.TRUE).build(),
+                               new DstOfIpDstCaseBuilder().setOfIpDst(Boolean.TRUE).build());
+    }
+
+
+    public static Action nxOutputRegAction(SrcChoice srcChoice) {
+        NxOutputReg r = new NxOutputRegBuilder()
+            .setSrc(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.nx.output.reg.SrcBuilder()
+                .setSrcChoice(srcChoice)
+                .setOfsNbits(31)
+                .build())
+            .setMaxLen(0xffff)
+            .build();
+        return new NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder()
+            .setNxOutputReg(r).build();
+    }
+
+    public static Action nxOutputRegAction(Class<? extends NxmNxReg> reg) {
+        return nxOutputRegAction(new SrcNxRegCaseBuilder().setNxReg(reg).build());
+    }
+
+    public static Action nxResubmitAction(Integer inPort, Short table) {
+        NxResubmitBuilder builder = new NxResubmitBuilder();
+        if (inPort != null) {
+            builder.setInPort(inPort);
+        }
+        if (table != null) {
+            builder.setTable(table);
+        }
+        NxResubmit r = builder.build();
+        return new NxActionResubmitNodesNodeTableFlowApplyActionsCaseBuilder().setNxResubmit(r).build();
+    }
+
+    public static Action nxSetNspAction(Long nsp) {
+        NxSetNspBuilder builder = new NxSetNspBuilder();
+        if (nsp != null) {
+            builder.setNsp(nsp);
+        }
+        NxSetNsp r = builder.build();
+        return new NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNsp(r).build();
+    }
+
+    public static Action nxSetNsiAction(Short nsi) {
+        NxSetNsiBuilder builder = new NxSetNsiBuilder();
+        if (nsi != null) {
+            builder.setNsi(nsi);
+        }
+        NxSetNsi r = builder.build();
+        return new NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNsi(r).build();
+    }
+
+    public static Action nxLoadNshc1RegAction(Long value) {
+        NxSetNshc1 newNshc1 = new NxSetNshc1Builder().setNshc(value).build();
+        return new NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc1(newNshc1).build();
+    }
+
+    public static Action nxLoadNshc2RegAction(Long value) {
+        NxSetNshc2 newNshc2 = new NxSetNshc2Builder().setNshc(value).build();
+        return new NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc2(newNshc2).build();
+    }
+
+    public static Action nxLoadNshc3RegAction(Long value) {
+        NxSetNshc3 newNshc3 = new NxSetNshc3Builder().setNshc(value).build();
+        return new NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc3(newNshc3).build();
+    }
+
+    public static Action nxLoadNshc4RegAction(Long value) {
+        NxSetNshc4 newNshc4 = new NxSetNshc4Builder().setNshc(value).build();
+        return new NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc4(newNshc4).build();
+    }
+
+    public static Action nxMoveRegTunDstToNshc1() {
+        return nxMoveRegAction(
+                new SrcNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),
+                new DstNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(),
+                31, false);
+    }
+
+    public static Action nxMoveTunIdtoNshc2() {
+        return nxMoveRegAction(
+                new SrcNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
+                new DstNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(),
+                31, false);
+    }
+
+    public static Action nxMoveNshc1ToTunIpv4Dst() {
+        return nxMoveRegAction(
+                new SrcNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(),
+                new DstNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),
+                31, false);
+    }
+
+    public static Action nxMoveNshc2ToTunId() {
+        return nxMoveRegAction(
+                new SrcNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(),
+                new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
+                31, false);
+    }
+
+    public static Action nxLoadTunIdAction(BigInteger tunnelId, boolean groupBucket) {
+        return nxLoadRegAction(new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), tunnelId, 31, groupBucket);
+    }
+
+    public static Action nxMultipathAction(OfjNxHashFields fields, Integer basis,
+            OfjNxMpAlgorithm algorithm, Integer maxLink, Long arg, DstChoice dstChoice,
+            Integer start, Integer end) {
+        NxMultipath r = new NxMultipathBuilder()
+            .setFields(fields)
+            .setBasis(basis)
+            .setAlgorithm(algorithm)
+            .setMaxLink(maxLink)
+            .setArg(arg)
+            .setDst(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.multipath.grouping.nx.multipath.DstBuilder()
+                    .setDstChoice(dstChoice)
+                .setStart(start)
+                .setEnd(end)
+                .build())
+            .build();
+        return new NxActionMultipathNodesNodeTableFlowApplyActionsCaseBuilder().setNxMultipath(r).build();
+    }
+
+    /**
+     * Builds the  conntrack action.
+     * @param flags the flags for the action
+     * @param zoneSrc the zoneSrc
+     * @param conntrackZone the conntrackZone
+     * @param recircTable the recirc table if it is a recirc action
+     * @return the conntrack action.
+     */
+    public static Action nxConntrackAction(Integer flags, Long zoneSrc,
+                                           Integer conntrackZone, Short recircTable) {
+        NxConntrack r = new NxConntrackBuilder()
+            .setFlags(flags)
+            .setZoneSrc(zoneSrc)
+            .setConntrackZone(conntrackZone)
+            .setRecircTable(recircTable)
+            .build();
+        return new NxActionConntrackNodesNodeTableFlowApplyActionsCaseBuilder().setNxConntrack(r).build();
+    }
+
+    /**
+     * Builds the apply action builder for the action
+     * @param action the conntrack action.
+     * @return the apply action builder.
+     */
+    public static ApplyActionsBuilder conntrackActionBuilder(Action action) {
+        ActionBuilder ab = new ActionBuilder();
+        ab.setAction(action);
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList =
+                Lists.newArrayList();
+        actionList.add(ab.build());
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        return aab;
+    }
+    /**
+     * Accepts a MAC address and returns the corresponding long, where the
+     * MAC bytes are set on the lower order bytes of the long.
+     * @param macAddress
+     * @return a long containing the mac address bytes
+     */
+    public static long toLong(byte[] macAddress) {
+        long mac = 0;
+        for (int i = 0; i < 6; i++) {
+            long t = (macAddress[i] & 0xffL) << ((5-i)*8);
+            mac |= t;
+        }
+        return mac;
+    }
+
+    /**
+     * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
+     * matter, and returns the corresponding long, where the MAC bytes are set
+     * on the lower order bytes of the long.
+     *
+     * @param macAddress
+     *            in String format
+     * @return a long containing the mac address bytes
+     */
+    public static long toLong(MacAddress macAddress) {
+        return toLong(toMACAddress(macAddress.getValue()));
+    }
+
+    /**
+     * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
+     * matter, and returns a corresponding byte[].
+     * @param macAddress
+     * @return
+     */
+    public static byte[] toMACAddress(String macAddress) {
+        final String HEXES = "0123456789ABCDEF";
+        byte[] address = new byte[6];
+        String[] macBytes = macAddress.split(":");
+        if (macBytes.length != 6) {
+            throw new IllegalArgumentException(
+                    "Specified MAC Address must contain 12 hex digits" +
+                    " separated pairwise by :'s.");
+        }
+        for (int i = 0; i < 6; ++i) {
+            address[i] = (byte) ((HEXES.indexOf(macBytes[i].toUpperCase()
+                                                        .charAt(0)) << 4) | HEXES.indexOf(macBytes[i].toUpperCase()
+                                                                                                  .charAt(1)));
+        }
+        return address;
+    }
+}
diff --git a/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java b/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java
new file mode 100644 (file)
index 0000000..3335586
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015 - 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.utils.mdsal.openflow;
+
+import com.google.common.base.Optional;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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;
+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.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.flow.MatchBuilder;
+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.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.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+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.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(FlowUtils.class);
+    private static final String OPENFLOW = "openflow";
+    public final static long REG_VALUE_FROM_LOCAL = 0x1L;
+    public final static long REG_VALUE_FROM_REMOTE = 0x2L;
+    public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg0.class;
+    public static final int ARP_OP_REQUEST = 0x1;
+    public static final int ARP_OP_REPLY = 0x2;
+
+
+    public static String getNodeName(long dpidLong) {
+        return OPENFLOW + ":" + dpidLong;
+    }
+
+    public static NodeConnectorId getNodeConnectorId(long ofPort, String nodeName) {
+        return new NodeConnectorId(nodeName + ":" + ofPort);
+    }
+
+    public static NodeConnectorId getSpecialNodeConnectorId(long dpidLong, String portName) {
+        return new NodeConnectorId(getNodeName(dpidLong) + ":" + portName);
+    }
+
+    public static NodeConnectorId getNodeConnectorId(long dpidLong, long ofPort) {
+        return getNodeConnectorId(ofPort, getNodeName(dpidLong));
+    }
+
+    public static NodeBuilder createNodeBuilder(String nodeId) {
+        NodeBuilder builder = new NodeBuilder();
+        builder.setId(new NodeId(nodeId));
+        builder.setKey(new NodeKey(builder.getId()));
+        return builder;
+    }
+
+    public static NodeBuilder createNodeBuilder(long dpidLong) {
+        return createNodeBuilder(getNodeName(dpidLong));
+    }
+
+    public static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeBuilder.getKey())
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flowBuilder.getTableId()))
+                .child(Flow.class, flowBuilder.getKey()).build();
+    }
+
+    public static InstanceIdentifier<Table> createTablePath(NodeBuilder nodeBuilder, short table) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeBuilder.getKey())
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(table)).build();
+    }
+
+    public static InstanceIdentifier<Node> createNodePath(NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeBuilder.getKey()).build();
+    }
+
+    public static Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
+                               ReadOnlyTransaction readTx, final LogicalDatastoreType store) {
+        try {
+            Optional<Flow> data = readTx.read(store, createFlowPath(flowBuilder, nodeBuilder)).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            LOG.error("Failed to get flow {}", flowBuilder.getFlowName(), e);
+        }
+
+        LOG.info("Cannot find data for Flow {} in {}", flowBuilder.getFlowName(), store);
+        return null;
+    }
+
+    public static Table getTable(NodeBuilder nodeBuilder, short table,
+                                    ReadOnlyTransaction readTx, final LogicalDatastoreType store) {
+        try {
+            Optional<Table> data = readTx.read(store, createTablePath(nodeBuilder, table)).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            LOG.error("Failed to get table {}", table, e);
+        }
+
+        LOG.info("Cannot find data for table {} in {}", table, store);
+        return null;
+    }
+
+    public static FlowBuilder getPipelineFlow(short table, short gotoTable) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setMatch(new MatchBuilder().build());
+
+        String flowName = "DEFAULT_PIPELINE_FLOW_" + table;
+        return initFlowBuilder(flowBuilder, flowName, table)
+                .setPriority(0);
+    }
+
+    /**
+     * Creates a flowBuilder.
+     * @param flowName the flow name
+     * @param priority the priority
+     * @param matchBuilder the match builder
+     * @param tableNo the table no to which flow needs to be inserted.
+     * @return the created flow builder.
+     */
+    public static FlowBuilder createFlowBuilder(String flowName,Integer priority,
+                                                MatchBuilder matchBuilder, short tableNo) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+        initFlowBuilder(flowBuilder, flowName, tableNo).setPriority(priority);
+        return flowBuilder;
+    }
+    /**
+     * Sets up common defaults for the given flow builder: a flow identifier and key based on the given flow name,
+     * strict, no barrier, the given table identifier, no hard timeout and no idle timeout.
+     *
+     * @param flowBuilder The flow builder.
+     * @param flowName The flow name.
+     * @param table The table.
+     * @return The flow builder.
+     */
+    public static FlowBuilder initFlowBuilder(FlowBuilder flowBuilder, String flowName, short table) {
+        final FlowId flowId = new FlowId(flowName);
+        flowBuilder
+                .setId(flowId)
+                .setStrict(true)
+                .setBarrier(false)
+                .setTableId(table)
+                .setKey(new FlowKey(flowId))
+                .setFlowName(flowName)
+                .setHardTimeout(0)
+                .setIdleTimeout(0);
+        return flowBuilder;
+    }
+}
diff --git a/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/InstructionUtils.java b/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/InstructionUtils.java
new file mode 100644 (file)
index 0000000..9e7c8b5
--- /dev/null
@@ -0,0 +1,1168 @@
+/*
+ * Copyright (c) 2013 - 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.utils.mdsal.openflow;
+
+import static org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils.dropAction;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
+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.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
+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.action.pop.vlan.action._case.PopVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.id.action._case.SetVlanIdActionBuilder;
+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.action.types.rev131112.address.address.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+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.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.WriteMetadataCaseBuilder;
+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.instruction.write.metadata._case.WriteMetadataBuilder;
+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.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InstructionUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(InstructionUtils.class);
+    private static final int IPV4 = 0x8100;
+    private static final int MAX_LENGTH = 0xffff;
+
+    /**
+     * Create Send to Controller Reserved Port Instruction (packet_in)
+     *
+     * @param nodeName Uri Prefix, containing nodeConnectorType and dpId (aka NodeId)
+     * @param ib Map InstructionBuilder without any instructions
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSendToControllerInstructions(String nodeName, InstructionBuilder ib) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        OutputActionBuilder output = new OutputActionBuilder();
+        output.setMaxLength(MAX_LENGTH);
+        NodeId nodeId = new NodeId(nodeName);
+        output.setOutputNodeConnector(new NodeConnectorId(nodeId.getValue() + ":"
+                + OutputPortValues.CONTROLLER.toString()));
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create NORMAL Reserved Port Instruction (packet_in)
+     *
+     * @param nodeName Uri Prefix, containing nodeConnectorType and dpId (aka NodeId)
+     * @param ib Map InstructionBuilder without any instructions
+     * @return ib Map InstructionBuilder with instructions
+     */
+
+    public static InstructionBuilder createNormalInstructions(String nodeName, InstructionBuilder ib) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        OutputActionBuilder output = new OutputActionBuilder();
+        NodeId nodeId = new NodeId(nodeName);
+        output.setOutputNodeConnector(new NodeConnectorId(nodeId.getValue() + ":"
+                + OutputPortValues.NORMAL.toString()));
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create LOCAL Reserved Port Instruction
+     *
+     * @param ib Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createLocalInstructions(InstructionBuilder ib, long dpidLong) {
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        OutputActionBuilder output = new OutputActionBuilder();
+        output.setOutputNodeConnector(new NodeConnectorId("openflow:" + dpidLong + ":"
+                + OutputPortValues.LOCAL.toString()));
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Output Port Instruction
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    public static InstructionBuilder createOutputPortInstructions(InstructionBuilder ib, Long dpidLong, Long port) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        LOG.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} inPort={} ",
+                dpidLong, port);
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        OutputActionBuilder oab = new OutputActionBuilder();
+        oab.setOutputNodeConnector(ncid);
+
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * add Output Port action to Instruction action list.
+     * This is use for flow with single output port actions.
+     * Flow with mutiple output port actions should use createOutputPortInstructions() method.
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    public static InstructionBuilder addOutputPortInstructions(InstructionBuilder ib,
+            Long dpidLong, Long port,
+            List<Instruction> instructions) {
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        LOG.debug(
+                "addOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}",
+                dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                }
+            }
+        }
+
+        /* Create output action for this port*/
+        OutputActionBuilder oab = new OutputActionBuilder();
+        oab.setOutputNodeConnector(ncid);
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+        ab.setOrder(actionList.size());
+        ab.setKey(new ActionKey(actionList.size()));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Remove Output Port from Instruction
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    public static boolean removeOutputPortFromInstructions(InstructionBuilder ib,
+            Long dpidLong, Long port, List<Instruction> instructions) {
+
+        final NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        final Uri ncidUri = new Uri(ncid);
+        LOG.debug(
+                "removeOutputPortFromInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}",
+                dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab;
+
+        // Start of by locating actions that will have port removed, from the existing instructionList
+        //
+        List<Action> existingActions;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                    break;
+                }
+            }
+        }
+
+        int removedActionOrder = 0;
+        boolean isPortDeleted = false;
+        boolean removeFlow = true;
+
+        // Locate specific action that has the port to be removed. Then, take note on its action order
+        // and remove it from list, in addition to flag that it was found.
+        //
+        for (Action action : actionList) {
+            if (action.getAction() instanceof OutputActionCase) {
+                OutputActionCase opAction = (OutputActionCase) action.getAction();
+                if (opAction.getOutputAction().getOutputNodeConnector().equals(ncidUri)) {
+                    /* Find the output port in action list and remove */
+                    removedActionOrder = action.getOrder();
+                    actionList.remove(action);
+                    isPortDeleted = true;
+                    break;
+                }
+            }
+        }
+
+        if (isPortDeleted) {
+            // Iterate through all actions in the modified list and adjust the order of
+            // the actions left behind. With that, all actions that have order higher than
+            // the action removed gets their value decremented by 1. Note that this iteration
+            // visits all entries to account for cases where the list order is not the same
+            // as the action's order.
+            //
+            for (int i = 0; i < actionList.size(); i++) {
+                Action action = actionList.get(i);
+                if (action.getOrder() > removedActionOrder) {
+                    /* Shift the action by rebuilding action, using adjusted order */
+                    ab = new ActionBuilder();
+                    ab.setAction(action.getAction());
+                    ab.setOrder(action.getOrder() - 1);
+                    ab.setKey(new ActionKey(action.getOrder() - 1));
+                    Action actionNewOrder = ab.build();
+                    actionList.remove(action);
+                    actionList.add(i, actionNewOrder);
+                } else if (action.getOrder() == removedActionOrder) {
+                    // Sanity: implementation assumes no two actions have the same order
+                    //
+                    LOG.error("Found action with same order as the action removed for {}, order {} index {}: {}",
+                            ncid, removedActionOrder, i, action);
+                }
+
+                // If action refers to a port output, then flow should be preserved.
+                // We do this, so that if we are only left with non-output port actions,
+                // we still remove the flow
+                //
+                if (action.getAction() instanceof OutputActionCase) {
+                    removeFlow = false;
+                }
+            }
+        } else {
+            // If port we are asked to delete is not found, this implementation will leave actions
+            // alone and not remove the flow, as long as a remaining OutputActionCase is found.
+            //
+            for (Action action : actionList) {
+                if (action.getAction() instanceof OutputActionCase) {
+                    removeFlow = false;
+                    break;
+                }
+            }
+        }
+
+        /* Put new action list in Apply Action instruction */
+        if (!removeFlow) {
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            LOG.debug("removeOutputPortFromInstructions() : applyAction {}", aab.build());
+            return false;
+        } else {
+            /* if all output ports are removed. Return true to indicate flow remove */
+            return true;
+        }
+    }
+
+    /**
+     * Create Set Vlan ID Instruction - This includes push vlan action, and set field -&gt; vlan vid action
+     *
+     * @param ib     Map InstructionBuilder without any instructions
+     * @param vlanId Integer representing a VLAN ID Integer representing a VLAN ID
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetVlanInstructions(InstructionBuilder ib, VlanId vlanId) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        /* First we push vlan header */
+        PushVlanActionBuilder vlan = new PushVlanActionBuilder();
+        vlan.setEthernetType(IPV4);
+        ab.setAction(new PushVlanActionCaseBuilder().setPushVlanAction(vlan.build()).build());
+        ab.setOrder(0);
+        actionList.add(ab.build());
+
+        /* Then we set vlan id value as vlanId */
+        SetVlanIdActionBuilder vl = new SetVlanIdActionBuilder();
+        vl.setVlanId(vlanId);
+        ab = new ActionBuilder();
+        ab.setAction(new SetVlanIdActionCaseBuilder().setSetVlanIdAction(vl.build()).build());
+        ab.setOrder(1);
+        actionList.add(ab.build());
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Pop Vlan Instruction - this remove vlan header
+     *
+     * @param ib Map InstructionBuilder without any instructions
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createPopVlanInstructions(InstructionBuilder ib) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        PopVlanActionBuilder popVlanActionBuilder = new PopVlanActionBuilder();
+        ab.setAction(new PopVlanActionCaseBuilder().setPopVlanAction(popVlanActionBuilder.build()).build());
+        ab.setOrder(0);
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set IPv4 Source Instruction
+     *
+     * @param ib        Map InstructionBuilder without any instructions
+     * @param prefixsrc String containing an IPv4 prefix
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createNwSrcInstructions(InstructionBuilder ib, Ipv4Prefix prefixsrc) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        SetNwSrcActionBuilder setNwsrcActionBuilder = new SetNwSrcActionBuilder();
+        Ipv4Builder ipsrc = new Ipv4Builder();
+        ipsrc.setIpv4Address(prefixsrc);
+        setNwsrcActionBuilder.setAddress(ipsrc.build());
+        ab.setAction(new SetNwSrcActionCaseBuilder().setSetNwSrcAction(setNwsrcActionBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set IPv4 Destination Instruction
+     *
+     * @param ib        Map InstructionBuilder without any instructions
+     * @param prefixdst String containing an IPv4 prefix
+     * @param extraAction (optional) Additional action to be performed in actionList
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createNwDstInstructions(InstructionBuilder ib, Ipv4Prefix prefixdst,
+                                                             ActionBuilder extraAction) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        SetNwDstActionBuilder setNwDstActionBuilder = new SetNwDstActionBuilder();
+        Ipv4Builder ipdst = new Ipv4Builder();
+        ipdst.setIpv4Address(prefixdst);
+        setNwDstActionBuilder.setAddress(ipdst.build());
+        ab.setAction(new SetNwDstActionCaseBuilder().setSetNwDstAction(setNwDstActionBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        if (extraAction != null) {
+            extraAction.setOrder(1);
+            extraAction.setKey(new ActionKey(1));
+            actionList.add(extraAction.build());
+        }
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Drop Instruction
+     *
+     * @param ib Map InstructionBuilder without any instructions
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createDropInstructions(InstructionBuilder ib) {
+
+        DropActionBuilder dab = new DropActionBuilder();
+        DropAction dropAction = dab.build();
+        ActionBuilder ab = new ActionBuilder();
+        ab.setAction(new DropActionCaseBuilder().setDropAction(dropAction).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+
+        // Add our drop action to a list
+        List<Action> actionList = new ArrayList<>();
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create GOTO Table Instruction Builder
+     *
+     * @param ib      Map InstructionBuilder without any instructions
+     * @param tableId short representing a flow table ID short representing a flow table ID
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createGotoTableInstructions(InstructionBuilder ib, short tableId) {
+
+        GoToTableBuilder gttb = new GoToTableBuilder();
+        gttb.setTableId(tableId);
+
+        // Wrap our Apply Action in an InstructionBuilder
+        ib.setInstruction(new GoToTableCaseBuilder().setGoToTable(gttb.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set Tunnel ID Instruction Builder
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param tunnelId BigInteger representing a tunnel ID
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetTunnelIdInstructions(InstructionBuilder ib, BigInteger tunnelId) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Build the Set Tunnel Field Action
+        TunnelBuilder tunnel = new TunnelBuilder();
+        tunnel.setTunnelId(tunnelId);
+        setFieldBuilder.setTunnel(tunnel.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap the Apply Action in an InstructionBuilder and return
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set Source TCP Port Instruction
+     *
+     * @param ib      Map InstructionBuilder without any instructions
+     * @param tcpport Integer representing a source TCP port
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetSrcTCPPort(InstructionBuilder ib, PortNumber tcpport) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Build the Destination TCP Port
+        PortNumber tcpsrcport = new PortNumber(tcpport);
+        TcpMatchBuilder tcpmatch = new TcpMatchBuilder();
+        tcpmatch.setTcpSourcePort(tcpsrcport);
+
+        setFieldBuilder.setLayer4Match(tcpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set Destination TCP Port Instruction
+     *
+     * @param ib      Map InstructionBuilder without any instructions
+     * @param tcpport Integer representing a source TCP port
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetDstTCPPort(InstructionBuilder ib, PortNumber tcpport) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Build the Destination TCP Port
+        PortNumber tcpdstport = new PortNumber(tcpport);
+        TcpMatchBuilder tcpmatch = new TcpMatchBuilder();
+        tcpmatch.setTcpDestinationPort(tcpdstport);
+
+        setFieldBuilder.setLayer4Match(tcpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set Source UDP Port Instruction
+     *
+     * @param ib      Map InstructionBuilder without any instructions
+     * @param udpport Integer representing a source UDP port
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetSrcUDPPort(InstructionBuilder ib, PortNumber udpport) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Build the Destination TCP Port
+        PortNumber udpsrcport = new PortNumber(udpport);
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(udpsrcport);
+
+        setFieldBuilder.setLayer4Match(udpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set Destination UDP Port Instruction
+     *
+     * @param ib      Map InstructionBuilder without any instructions
+     * @param udpport Integer representing a destination UDP port
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetDstUDPPort(InstructionBuilder ib, PortNumber udpport) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Build the Destination TCP Port
+        PortNumber udpdstport = new PortNumber(udpport);
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpDestinationPort(udpdstport);
+
+        setFieldBuilder.setLayer4Match(udpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set ICMP Code Instruction
+     *
+     * @param ib   Map InstructionBuilder without any instructions
+     * @param code short repesenting an ICMP code
+     * @return ib Map InstructionBuilder with instructions
+     */
+
+    public static InstructionBuilder createSetIcmpCodeInstruction(InstructionBuilder ib, short code) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+        Icmpv4MatchBuilder icmpv4match = new Icmpv4MatchBuilder();
+
+        // Build the ICMPv4 Code Match
+        icmpv4match.setIcmpv4Code(code);
+        setFieldBuilder.setIcmpv4Match(icmpv4match.build());
+
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Set ICMP Code Instruction
+     *
+     * @param ib Map InstructionBuilder without any instructions
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createSetIcmpTypeInstruction(InstructionBuilder ib, short type) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+        Icmpv4MatchBuilder icmpv4match = new Icmpv4MatchBuilder();
+
+        // Build the ICMPv4 Code Match
+        icmpv4match.setIcmpv4Code(type);
+        setFieldBuilder.setIcmpv4Match(icmpv4match.build());
+
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Create Decrement TTL Instruction
+     *
+     * @param ib Map InstructionBuilder without any instructions
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createDecNwTtlInstructions(InstructionBuilder ib) {
+        DecNwTtlBuilder decNwTtlBuilder = new DecNwTtlBuilder();
+        DecNwTtl decNwTtl = decNwTtlBuilder.build();
+        ActionBuilder ab = new ActionBuilder();
+        ab.setAction(new DecNwTtlCaseBuilder().setDecNwTtl(decNwTtl).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+
+        // Add our drop action to a list
+        List<Action> actionList = new ArrayList<>();
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set ARP_SHA Instructions
+     * @param ib Map InstructionBuilder
+     * @param macsrc the macsrc
+     * @return instructionbuilder with new instructions
+     */
+    public static InstructionBuilder createSrcArpMacInstructions(InstructionBuilder ib, MacAddress macsrc) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+        ArpMatchBuilder arpmatch = new ArpMatchBuilder();
+        ArpSourceHardwareAddressBuilder arpsrc = new ArpSourceHardwareAddressBuilder();
+        arpsrc.setAddress(macsrc);
+        arpmatch.setArpSourceHardwareAddress(arpsrc.build());
+        setFieldBuilder.setLayer3Match(arpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set ARP_THA Instructions
+     * @param ib Map InstructionBuilder
+     * @param macdst the macdst
+     * @return instructionbuilder with new attributes
+     */
+    public static InstructionBuilder createDstArpMacInstructions(InstructionBuilder ib, MacAddress macdst) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        ArpMatchBuilder arpmatch = new ArpMatchBuilder();
+        ArpTargetHardwareAddressBuilder arpdst = new ArpTargetHardwareAddressBuilder();
+        arpdst.setAddress(macdst);
+        setFieldBuilder.setLayer3Match(arpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set ARP_TPA Instructions
+     * @param ib Map InstructionBuilder
+     * @param dstiparp the dstiparp
+     * @return instructionbuilder with new attributes
+     */
+    public static InstructionBuilder createDstArpIpInstructions(InstructionBuilder ib, Ipv4Prefix dstiparp) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        ArpMatchBuilder arpmatch = new ArpMatchBuilder();
+        arpmatch.setArpTargetTransportAddress(dstiparp);
+        setFieldBuilder.setLayer3Match(arpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set ARP_SPA Instructions
+     * @param ib Map InstructionBuilder
+     * @param srciparp the srciparp
+     * @return instructionbuilder with new attributes
+     */
+    public static InstructionBuilder createSrcArpIpInstructions(InstructionBuilder ib, Ipv4Prefix srciparp) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        ArpMatchBuilder arpmatch = new ArpMatchBuilder();
+        arpmatch.setArpSourceTransportAddress(srciparp);
+        setFieldBuilder.setLayer3Match(arpmatch.build());
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set the Tunnel EndpointIPv4 Source Address
+     * @param ib Map InstructionBuilder
+     * @param srcIp Ipv4Prefix source IP for the tunnel endpoint (TEP)
+     * @return instructionbuilder with new attributes
+     */
+    public static InstructionBuilder createTunnelIpv4SrcInstructions(InstructionBuilder ib, Ipv4Prefix srcIp) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        // Build the tunnel endpoint source IPv4 address
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Add the new IPv4 object as the tunnel destination
+        TunnelIpv4MatchBuilder tunnelIpv4MatchBuilder = new TunnelIpv4MatchBuilder();
+        tunnelIpv4MatchBuilder.setTunnelIpv4Source(srcIp);
+        setFieldBuilder.setLayer3Match(tunnelIpv4MatchBuilder.build());
+
+        // Add the IPv4 tunnel src to the set_field value
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Resulting action is a per/flow src TEP (set_field:172.16.100.100->tun_src)
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set the Tunnel EndpointIPv4 Destination Address
+     * @param ib Map InstructionBuilder
+     * @param dstIp Ipv4Prefix destination IP for the tunnel endpoint (TEP)
+     * @return instructionbuilder with new attributes
+     */
+    public static InstructionBuilder createTunnelIpv4DstInstructions(InstructionBuilder ib, Ipv4Prefix dstIp) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        // Build the tunnel endpoint dst IPv4 address
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        // Add the new IPv4 object as the tunnel destination
+        TunnelIpv4MatchBuilder tunnelIpv4MatchBuilder = new TunnelIpv4MatchBuilder();
+        tunnelIpv4MatchBuilder.setTunnelIpv4Destination(dstIp);
+        setFieldBuilder.setLayer3Match(tunnelIpv4MatchBuilder.build());
+
+        // Add the IPv4 tunnel src to the set_field value
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Resulting action is a per/flow src TEP (set_field:172.16.100.100->tun_src)
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Set IPv4 Source Address Instructions
+     * @param ib Map InstructionBuilder
+     * @param metaData BigInteger representing the OpenFlow metadata
+     * @param metaDataMask  BigInteger representing the OpenFlow metadata mask
+     * @return instructionbuilder with new attributes
+     */
+    public static InstructionBuilder createMetadataInstructions(InstructionBuilder ib, BigInteger metaData, BigInteger metaDataMask) {
+
+        WriteMetadataBuilder aab = new WriteMetadataBuilder();
+        aab.setMetadata(metaData);
+        aab.setMetadataMask(metaDataMask);
+        ib.setInstruction(new WriteMetadataCaseBuilder().setWriteMetadata(aab.build()).build());
+
+        /**
+        *
+        * TODO Determine why the following fails serialization
+        * with a null value. Per the spec it is optional.
+        * The metadata match, the Flowmod works w/o an accompanying mask.
+        *
+        * if (metaDataMask != null) {
+        *    aab.setMetadataMask(metaDataMask);
+        * }
+        *
+        */
+
+        return ib;
+    }
+
+    public static InstructionBuilder createDlSrcInstructions(InstructionBuilder ib, MacAddress macAddress) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        SetDlSrcActionBuilder dlSrcActionBuilder= new SetDlSrcActionBuilder();
+
+        dlSrcActionBuilder.setAddress(macAddress);
+
+        ab.setAction(new SetDlSrcActionCaseBuilder().setSetDlSrcAction(dlSrcActionBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    public static InstructionBuilder createDlDstInstructions(InstructionBuilder ib, MacAddress macAddress) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        SetDlDstActionBuilder dlDstActionBuilder= new SetDlDstActionBuilder();
+
+        dlDstActionBuilder.setAddress(macAddress);
+
+        ab.setAction(new SetDlDstActionCaseBuilder().setSetDlDstAction(dlDstActionBuilder.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    public static List<Action>
+                  actionList(org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action... actions) {
+
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> alist
+            = new ArrayList<>();
+        int count = 0;
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action : actions) {
+            alist.add(new ActionBuilder()
+                .setOrder(count)
+                .setKey(new ActionKey(count))
+                .setAction(action)
+                .build());
+            count++;
+        }
+        return alist;
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction
+        applyActionIns(org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action... actions) {
+
+        return new ApplyActionsCaseBuilder()
+            .setApplyActions(new ApplyActionsBuilder()
+                .setAction(actionList(actions))
+                .build())
+            .build();
+    }
+
+    public static Instructions getInstructions(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction... instructions) {
+        List<Instruction> ins
+            = new ArrayList<>();
+        int order = 0;
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction i : instructions) {
+            ins.add(new InstructionBuilder()
+                .setOrder(order)
+                .setKey(new InstructionKey(order))
+                .setInstruction(i)
+                .build());
+            order++;
+        }
+        return new InstructionsBuilder().setInstruction(ins).build();
+    }
+
+    public static Instructions dropInstructions() {
+        return getInstructions(applyActionIns(dropAction()));
+    }
+
+    /**
+     * Extracts the existing instructions (if any) from the flow.
+     *
+     * @param flow The flow.
+     * @return The instructions in the flow (empty if none).
+     */
+    public static List<Instruction> extractExistingInstructions(Flow flow) {
+        if (flow != null) {
+            Instructions ins = flow.getInstructions();
+            if (ins != null) {
+                return ins.getInstruction();
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Configures the flow builder to have the single given instruction.
+     *
+     * @param flowBuilder The flow builder.
+     * @param instruction The instruction.
+     * @return The flow builder.
+     */
+    public static FlowBuilder setFlowBuilderInstruction(FlowBuilder flowBuilder, Instruction instruction) {
+        flowBuilder.setInstructions(
+                new InstructionsBuilder()
+                        .setInstruction(Collections.singletonList(instruction))
+                        .build());
+        return flowBuilder;
+    }
+
+    /**
+     * Get a list of Instructions containing Nicira extensions that can have
+     * additional OF/OXM instructions added to the returned Instruction list
+     * @param instructions org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instructions
+     * @return instruction list that additional
+     */
+    public static List<Instruction> getInstructionList(
+            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction... instructions) {
+        List<Instruction> ins
+                = new ArrayList<>();
+        int order = 0;
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction i : instructions) {
+            ins.add(new InstructionBuilder()
+                    .setOrder(order++)
+                    .setInstruction(i)
+                    .build());
+        }
+        return ins;
+    }
+
+    /**
+     * Create InstructionBuilder with apply action.
+     *
+     * @param aab the apply action Builder.
+     * @param order the position of the instruction in the instruction list.
+     * @param drop indicates whether it is a drop instruction.
+     * @return the instruction builder.
+     */
+    public static InstructionBuilder createInstructionBuilder(ApplyActionsBuilder aab, int order, boolean drop) {
+        InstructionBuilder ib = new InstructionBuilder();
+        ib.setOrder(order);
+        ib.setKey(new InstructionKey(order));
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+        if (drop) {
+            InstructionUtils.createDropInstructions(ib);
+        }
+        return ib;
+    }
+}
diff --git a/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtils.java b/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtils.java
new file mode 100644 (file)
index 0000000..dbdc353
--- /dev/null
@@ -0,0 +1,1711 @@
+/*
+ * Copyright (c) 2013 - 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.utils.mdsal.openflow;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
+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.Icmpv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv6MatchBuilder;
+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.MetadataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TcpFlagMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
+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.Ipv6MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+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.NxmNxReg1;
+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.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+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.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.NxmNxCtStateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxCtZoneKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg0Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg1Key;
+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.NxmNxReg3Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg4Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg5Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg6Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg7Key;
+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.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.nx.ct.state.grouping.NxmNxCtStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.ct.zone.grouping.NxmNxCtZoneBuilder;
+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.NxmNxNspKey;
+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.NxmNxNsiKey;
+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.of.tcp.src.grouping.NxmOfTcpSrcBuilder;
+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.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;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class MatchUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(MatchUtils.class);
+    public static final short ICMP_SHORT = 1;
+    public static final short TCP_SHORT = 6;
+    public static final short UDP_SHORT = 17;
+    public static final short SCTP_SHORT = 132;
+    public static final String TCP = "tcp";
+    public static final String UDP = "udp";
+    private static final int TCP_SYN = 0x0002;
+    public static final String ICMP = "icmp";
+    public static final String ICMPV6 = "icmpv6";
+    public static final short ALL_ICMP = -1;
+    public static final long ETHERTYPE_IPV4 = 0x0800;
+    public static final long ETHERTYPE_IPV6 = 0x86dd;
+    public static final long ETHERTYPE_ARP = 0x0806L;
+    public static final int UNTRACKED_CT_STATE = 0x00;
+    public static final int UNTRACKED_CT_STATE_MASK = 0x20;
+    public static final int TRACKED_EST_CT_STATE = 0x22;
+    public static final int TRACKED_REL_CT_STATE = 0x24;
+    public static final int TRACKED_NEW_CT_STATE = 0x21;
+    public static final int TRACKED_INV_CT_STATE = 0x30;
+    public static final int TRACKED_INV_CT_STATE_MASK = 0x30;
+    public static final int TRACKED_CT_STATE_MASK = 0x37;
+    public static final int TRACKED_NEW_CT_STATE_MASK = 0x21;
+
+    /**
+     * Create Ingress Port Match dpidLong, inPort
+     *
+     * @param matchBuilder Map matchBuilder MatchBuilder Object without a match
+     * @param dpidLong     Long the datapath ID of a switch/node
+     * @param inPort       Long ingress port on a switch
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createInPortMatch(MatchBuilder matchBuilder, Long dpidLong, Long inPort) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + inPort);
+        LOG.debug("createInPortMatch() Node Connector ID is - Type=openflow: DPID={} inPort={} ", dpidLong, inPort);
+        matchBuilder.setInPort(NodeConnectorId.getDefaultInstance(ncid.getValue()));
+        matchBuilder.setInPort(ncid);
+
+        return matchBuilder;
+    }
+
+    public static MatchBuilder createInPortReservedMatch(MatchBuilder matchBuilder, Long dpidLong, String inPort) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + inPort);
+        LOG.debug("createInPortResrevedMatch() Node Connector ID is - Type=openflow: DPID={} inPort={} ",
+                dpidLong, inPort);
+        matchBuilder.setInPort(NodeConnectorId.getDefaultInstance(ncid.getValue()));
+        matchBuilder.setInPort(ncid);
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create EtherType Match
+     *
+     * @param matchBuilder Map matchBuilder MatchBuilder Object without a match
+     * @param etherType    Long EtherType
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createEtherTypeMatch(MatchBuilder matchBuilder, EtherType etherType) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(etherType));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        return matchBuilder;
+    }
+
+    public static MatchBuilder createEthSrcDstMatch(MatchBuilder matchBuilder, MacAddress srcMac, MacAddress dstMac) {
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        if (srcMac != null) {
+            EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+            ethSourceBuilder.setAddress(srcMac);
+            ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+        }
+        if (dstMac != null) {
+            EthernetDestinationBuilder ethDestinationBuild = new EthernetDestinationBuilder();
+            ethDestinationBuild.setAddress(dstMac);
+            ethernetMatch.setEthernetDestination(ethDestinationBuild.build());
+        }
+        if (matchBuilder.getEthernetMatch() != null && matchBuilder.getEthernetMatch().getEthernetType() != null) {
+            ethernetMatch.setEthernetType(matchBuilder.getEthernetMatch().getEthernetType());
+        }
+
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create Ethernet Source Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param sMacAddr     String representing a source MAC
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createEthSrcMatch(MatchBuilder matchBuilder, MacAddress sMacAddr) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(sMacAddr);
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create Ethernet Destination Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param vlanId       Integer representing a VLAN ID Integer representing a VLAN ID
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createVlanIdMatch(MatchBuilder matchBuilder, VlanId vlanId, boolean present) {
+        VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
+        VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
+        vlanIdBuilder.setVlanId(new VlanId(vlanId));
+        vlanIdBuilder.setVlanIdPresent(present);
+        vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
+        matchBuilder.setVlanMatch(vlanMatchBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create Ethernet Destination Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param dMacAddr     String representing a destination MAC
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createDestEthMatch(MatchBuilder matchBuilder, MacAddress dMacAddr, MacAddress mask) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(dMacAddr);
+        if (mask != null) {
+            ethDestinationBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Tunnel ID Match Builder
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param tunnelId     BigInteger representing a tunnel ID
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createTunnelIDMatch(MatchBuilder matchBuilder, BigInteger tunnelId) {
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(tunnelId);
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Match ICMP code and type
+     *
+     * @param matchBuilder MatchBuilder Object
+     * @param type         short representing an ICMP type
+     * @param code         short representing an ICMP code
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createICMPv4Match(MatchBuilder matchBuilder, short type, short code) {
+
+        // Build the IPv4 Match requied per OVS Syntax
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol((short) 1);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        // Build the ICMPv4 Match
+        Icmpv4MatchBuilder icmpv4match = new Icmpv4MatchBuilder();
+        if (type != ALL_ICMP) {
+            icmpv4match.setIcmpv4Type(type);
+        }
+        if (code != ALL_ICMP) {
+            icmpv4match.setIcmpv4Code(code);
+        }
+        matchBuilder.setIcmpv4Match(icmpv4match.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Match ICMPv6 code and type
+     *
+     * @param matchBuilder MatchBuilder Object
+     * @param type         short representing an ICMP type
+     * @param code         short representing an ICMP code
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createICMPv6Match(MatchBuilder matchBuilder, short type, short code) {
+
+        // Build the IPv6 Match required per OVS Syntax
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol((short) 58);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        // Build the ICMPv6 Match
+        Icmpv6MatchBuilder icmpv6match = new Icmpv6MatchBuilder();
+        if (type != ALL_ICMP || code != ALL_ICMP) {
+            icmpv6match.setIcmpv6Type(type);
+            icmpv6match.setIcmpv6Code(code);
+        }
+        matchBuilder.setIcmpv6Match(icmpv6match.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param dstip        String containing an IPv4 prefix
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createDstL3IPv4Match(MatchBuilder matchBuilder, Ipv4Prefix dstip) {
+
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        eth.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(eth.build());
+
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        ipv4match.setIpv4Destination(dstip);
+
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param dstip        String containing an IPv4 prefix
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createArpDstIpv4Match(MatchBuilder matchBuilder, Ipv4Prefix dstip) {
+        ArpMatchBuilder arpDstMatch = new ArpMatchBuilder();
+        arpDstMatch.setArpTargetTransportAddress(dstip)
+                .setArpOp(FlowUtils.ARP_OP_REQUEST);
+        matchBuilder.setLayer3Match(arpDstMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Builds the arp match with src and destintion mac address.
+     * @param matchBuilder the match builder
+     * @param srcMac the src mac address , will not be added to match if null.
+     * @param dstMac the destination mac address, will not be added to match if null.
+     * @return the match builder with the matches
+     */
+    public static MatchBuilder addArpMacMatch(MatchBuilder matchBuilder, String srcMac, String dstMac) {
+        ArpMatchBuilder arpMatch = new ArpMatchBuilder();
+        if (null != srcMac) {
+            ArpSourceHardwareAddressBuilder arpSrc = new ArpSourceHardwareAddressBuilder();
+            arpSrc.setAddress(new MacAddress(srcMac));
+            arpMatch.setArpSourceHardwareAddress(arpSrc.build());
+        }
+        if (null != dstMac) {
+            ArpTargetHardwareAddressBuilder arpDst = new ArpTargetHardwareAddressBuilder();
+            arpDst.setAddress(new MacAddress(dstMac));
+            arpMatch.setArpTargetHardwareAddress(arpDst.build());
+        }
+        matchBuilder.setLayer3Match(arpMatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param srcip        String containing an IPv4 prefix
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createSrcL3IPv4Match(MatchBuilder matchBuilder, Ipv4Prefix srcip) {
+
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        eth.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(eth.build());
+
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        ipv4match.setIpv4Source(srcip);
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Create Source TCP Port Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param tcpport      Integer representing a source TCP port
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createSetSrcTcpMatch(MatchBuilder matchBuilder, PortNumber tcpport) {
+
+        EthernetMatchBuilder ethType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethType.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        TcpMatchBuilder tcpmatch = new TcpMatchBuilder();
+        tcpmatch.setTcpSourcePort(tcpport);
+        matchBuilder.setLayer4Match(tcpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Create Destination TCP Port Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param tcpDstPort   Integer representing a destination TCP port
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createSetDstTcpMatch(MatchBuilder matchBuilder, PortNumber tcpDstPort) {
+
+        EthernetMatchBuilder ethType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethType.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        TcpMatchBuilder tcpmatch = new TcpMatchBuilder();
+        tcpmatch.setTcpDestinationPort(tcpDstPort);
+        matchBuilder.setLayer4Match(tcpmatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Test match for TCP_Flags
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param tcpPort  PortNumber representing a destination TCP port
+     * @param tcpFlag  int representing a tcp_flag
+     * @return match containing TCP_Flag (), IP Protocol (TCP), TCP_Flag (SYN)
+     * <p>
+     * Defined TCP Flag values in OVS v2.1+
+     * TCP_FIN 0x001 / TCP_SYN 0x002 / TCP_RST 0x004
+     * TCP_PSH 0x008 / TCP_ACK 0x010 / TCP_URG 0x020
+     * TCP_ECE 0x040 / TCP_CWR 0x080 / TCP_NS  0x100
+     */
+    public static MatchBuilder createTcpFlagMatch(MatchBuilder matchBuilder, PortNumber tcpPort, int tcpFlag) {
+
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createMetadataMatch(MatchBuilder matchBuilder, BigInteger metaData,  BigInteger metaDataMask) {
+
+        // metadata matchbuilder
+        MetadataBuilder metadata = new MetadataBuilder();
+        metadata.setMetadata(metaData);
+        // Optional metadata mask
+        if (metaDataMask != null) {
+            metadata.setMetadataMask(metaDataMask);
+        }
+        matchBuilder.setMetadata(metadata.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create  TCP Port Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param ipProtocol   Integer representing the IP protocol
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createIpProtocolMatch(MatchBuilder matchBuilder, short ipProtocol) {
+
+        EthernetMatchBuilder ethType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethType.build());
+
+        IpMatchBuilder ipMmatch = new IpMatchBuilder();
+        if (ipProtocol == TCP_SHORT) {
+            ipMmatch.setIpProtocol(TCP_SHORT);
+        }
+        else if (ipProtocol == UDP_SHORT) {
+            ipMmatch.setIpProtocol(UDP_SHORT);
+        }
+        else if (ipProtocol == ICMP_SHORT) {
+            ipMmatch.setIpProtocol(ICMP_SHORT);
+        }
+        matchBuilder.setIpMatch(ipMmatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create  TCP Port Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param ipProtocol   Integer representing the IP protocol
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createIpv6ProtocolMatch(MatchBuilder matchBuilder, short ipProtocol) {
+
+        EthernetMatchBuilder ethType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x86DDL));
+        ethType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethType.build());
+
+        IpMatchBuilder ipMmatch = new IpMatchBuilder();
+        if (ipProtocol == TCP_SHORT) {
+            ipMmatch.setIpProtocol(TCP_SHORT);
+        }
+        else if (ipProtocol == UDP_SHORT) {
+            ipMmatch.setIpProtocol(UDP_SHORT);
+        }
+        else if (ipProtocol == ICMP_SHORT) {
+            ipMmatch.setIpProtocol(ICMP_SHORT);
+        }
+        matchBuilder.setIpMatch(ipMmatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create tcp syn with proto match.
+     *
+     * @param matchBuilder the match builder
+     * @return matchBuilder match builder
+     */
+    public static MatchBuilder createTcpSynWithProtoMatch(MatchBuilder matchBuilder) {
+
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create tcp proto syn match.
+     *
+     * @param matchBuilder the match builder
+     * @return matchBuilder match builder
+     */
+    public static MatchBuilder createTcpProtoSynMatch(MatchBuilder matchBuilder) {
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac tcp port with flag match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return match containing TCP_Flag (), IP Protocol (TCP), TCP_Flag (SYN)
+     */
+    public static MatchBuilder createDmacTcpPortWithFlagMatch(MatchBuilder matchBuilder,
+            String attachedMac, Integer tcpFlag, String tunnelID) {
+        return createDmacTcpPortIpSaWithFlagMatch(matchBuilder, attachedMac, tcpFlag, null, tunnelID);
+    }
+
+    /**
+     * Create dmac ipSa match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param ipPrefix the src ipPrefix
+     * @param tunnelID the tunnel iD
+     * @return match containing TCP_Flag (), IP Protocol (TCP), TCP_Flag (SYN), Ip Source Address (IPsa)
+     */
+    public static MatchBuilder createDmacIpSaMatch(
+            MatchBuilder matchBuilder, String attachedMac, Ipv4Prefix ipPrefix, String tunnelID) {
+        return createDmacTcpPortIpSaWithFlagMatch(matchBuilder, attachedMac, null, ipPrefix, tunnelID);
+    }
+
+    /**
+     * Create dmac tcp port ipSa with flag match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpFlag the tcp flag
+     * @param ipPrefix the src ipPrefix
+     * @param tunnelID the tunnel iD
+     * @return match containing TCP_Flag (), IP Protocol (TCP), TCP_Flag (SYN), Ip Source Address (IPsa)
+     */
+    public static MatchBuilder createDmacTcpPortIpSaWithFlagMatch(
+            MatchBuilder matchBuilder, String attachedMac, Integer tcpFlag, Ipv4Prefix ipPrefix, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        if (attachedMac != null) {
+            EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+            ethDestinationBuilder.setAddress(new MacAddress(attachedMac));
+            ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+            matchBuilder.setEthernetMatch(ethernetMatch.build());
+        }
+
+        if (tcpFlag != null) {
+            // TCP Protocol Match
+            IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+            ipMatch.setIpProtocol(TCP_SHORT);
+            matchBuilder.setIpMatch(ipMatch.build());
+
+            TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+            tcpFlagMatch.setTcpFlag(tcpFlag);
+            matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+        }
+
+        if (tunnelID != null) {
+            TunnelBuilder tunnelBuilder = new TunnelBuilder();
+            tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+            matchBuilder.setTunnel(tunnelBuilder.build());
+        }
+
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Source(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac tcp syn match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return the match builder
+     */
+    public static MatchBuilder createDmacTcpSynMatch(MatchBuilder matchBuilder,
+            String attachedMac, PortNumber tcpPort, Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac tcp syn dst ip prefix tcp port.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param segmentationId the segmentation id
+     * @param dstIp the dst ip
+     * @return the match builder
+     */
+    public static MatchBuilder createDmacTcpSynDstIpPrefixTcpPort(MatchBuilder matchBuilder,
+            MacAddress attachedMac, PortNumber tcpPort,  Integer tcpFlag, String segmentationId,
+            Ipv4Prefix dstIp) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(attachedMac);
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        ipv4match.setIpv4Destination(dstIp);
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(segmentationId));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac ip tcp syn match.
+     *
+     * @param matchBuilder the match builder
+     * @param dMacAddr the d mac addr
+     * @param mask the mask
+     * @param ipPrefix the ip prefix
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createDmacIpTcpSynMatch(MatchBuilder matchBuilder,
+            MacAddress dMacAddr, MacAddress mask, Ipv4Prefix ipPrefix) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetDestinationBuilder ethDestBuilder = new EthernetDestinationBuilder();
+        ethDestBuilder.setAddress(dMacAddr);
+        if (mask != null) {
+            ethDestBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetDestination(ethDestBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Destination(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+        // TCP Flag Match
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac tcp syn dst ip prefix tcp port.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param segmentationId the segmentation id
+     * @param dstIp the dst ip
+     * @return the match builder
+     */
+    public static MatchBuilder createSmacTcpSynDstIpPrefixTcpPort(MatchBuilder matchBuilder, MacAddress attachedMac,
+            PortNumber tcpPort, Integer tcpFlag, String segmentationId, Ipv4Prefix dstIp) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(attachedMac);
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        ipv4match.setIpv4Destination(dstIp);
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(segmentationId));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac tcp port with flag match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return matchBuilder
+     */
+    public static MatchBuilder createSmacTcpPortWithFlagMatch(MatchBuilder matchBuilder, String attachedMac,
+            Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetSourceBuilder ethSrcBuilder = new EthernetSourceBuilder();
+        ethSrcBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetSource(ethSrcBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac ip tcp syn match.
+     *
+     * @param matchBuilder the match builder
+     * @param dMacAddr the d mac addr
+     * @param mask the mask
+     * @param ipPrefix the ip prefix
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createSmacIpTcpSynMatch(MatchBuilder matchBuilder, MacAddress dMacAddr,
+            MacAddress mask, Ipv4Prefix ipPrefix) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetSourceBuilder ethSrcBuilder = new EthernetSourceBuilder();
+        ethSrcBuilder.setAddress(dMacAddr);
+        if (mask != null) {
+            ethSrcBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetSource(ethSrcBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Destination(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+        // TCP Flag Match
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac tcp syn.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return the match builder
+     */
+    public static MatchBuilder createSmacTcpSyn(MatchBuilder matchBuilder,
+            String attachedMac, PortNumber tcpPort, Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetSourceBuilder ethSrcBuilder = new EthernetSourceBuilder();
+        ethSrcBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetSource(ethSrcBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createMacSrcIpTcpSynMatch(MatchBuilder matchBuilder,
+            MacAddress dMacAddr,  MacAddress mask, Ipv4Prefix ipPrefix) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(dMacAddr);
+        if (mask != null) {
+            ethDestinationBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Source(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+        // TCP Flag Match
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create a DHCP match with port provided.
+     *
+     * @param matchBuilder the match builder
+     * @param srcPort the source port
+     * @param dstPort the destination port
+     * @return the DHCP match
+     */
+    public static MatchBuilder createDhcpMatch(MatchBuilder matchBuilder,
+                                               int srcPort, int dstPort) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol(UDP_SHORT);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(new PortNumber(srcPort));
+        udpmatch.setUdpDestinationPort(new PortNumber(dstPort));
+        matchBuilder.setLayer4Match(udpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Create a DHCP match with port provided.
+     *
+     * @param matchBuilder the match builder
+     * @param srcPort the source port
+     * @param dstPort the destination port
+     * @return the DHCP match
+     */
+    public static MatchBuilder createDhcpv6Match(MatchBuilder matchBuilder,
+                                                 int srcPort, int dstPort) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x86DDL));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol(UDP_SHORT);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(new PortNumber(srcPort));
+        udpmatch.setUdpDestinationPort(new PortNumber(dstPort));
+        matchBuilder.setLayer4Match(udpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Creates DHCP server packet match with DHCP mac address and port.
+     *
+     * @param matchBuilder the matchbuilder
+     * @param dhcpServerMac MAc address of the DHCP server of the subnet
+     * @param srcPort the source port
+     * @param dstPort the destination port
+     * @return the DHCP server match
+     */
+    public static MatchBuilder createDhcpServerMatch(MatchBuilder matchBuilder, String dhcpServerMac, int srcPort,
+            int dstPort) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(new MacAddress(dhcpServerMac));
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol(UDP_SHORT);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(new PortNumber(srcPort));
+        udpmatch.setUdpDestinationPort(new PortNumber(dstPort));
+        matchBuilder.setLayer4Match(udpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Creates DHCPv6 server packet match with DHCP mac address and port.
+     *
+     * @param matchBuilder the matchbuilder
+     * @param dhcpServerMac MAc address of the DHCP server of the subnet
+     * @param srcPort the source port
+     * @param dstPort the destination port
+     * @return the DHCP server match
+     */
+    public static MatchBuilder createDhcpv6ServerMatch(MatchBuilder matchBuilder, String dhcpServerMac, int srcPort,
+            int dstPort) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x86DDL));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(new MacAddress(dhcpServerMac));
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol(UDP_SHORT);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(new PortNumber(srcPort));
+        udpmatch.setUdpDestinationPort(new PortNumber(dstPort));
+        matchBuilder.setLayer4Match(udpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Creates a Match with src ip address mac address set.
+     * @param matchBuilder MatchBuilder Object
+     * @param srcip String containing an IPv4 prefix
+     * @param srcMac The source macAddress
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createSrcL3Ipv4MatchWithMac(MatchBuilder matchBuilder, Ipv4Prefix srcip, MacAddress srcMac) {
+
+        Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder();
+        ipv4MatchBuilder.setIpv4Source(srcip);
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        eth.setEthernetType(ethTypeBuilder.build());
+        eth.setEthernetSource(new EthernetSourceBuilder()
+                .setAddress(srcMac)
+                .build());
+
+        matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
+        matchBuilder.setEthernetMatch(eth.build());
+        return matchBuilder;
+
+    }
+
+    /**
+     * Creates a Match with src ip address mac address set.
+     * @param matchBuilder MatchBuilder Object
+     * @param srcip String containing an IPv6 prefix
+     * @param srcMac The source macAddress
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createSrcL3Ipv6MatchWithMac(MatchBuilder matchBuilder, Ipv6Prefix srcip, MacAddress srcMac) {
+
+        Ipv6MatchBuilder ipv6MatchBuilder = new Ipv6MatchBuilder();
+        ipv6MatchBuilder.setIpv6Source(srcip);
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x86DDL));
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        eth.setEthernetType(ethTypeBuilder.build());
+        eth.setEthernetSource(new EthernetSourceBuilder()
+                .setAddress(srcMac)
+                .build());
+
+        matchBuilder.setLayer3Match(ipv6MatchBuilder.build());
+        matchBuilder.setEthernetMatch(eth.build());
+        return matchBuilder;
+
+    }
+
+    /**
+     * Creates a ether net match with ether type set to 0x0800L.
+     * @param matchBuilder MatchBuilder Object
+     * @param srcMac The source macAddress
+     * @param dstMac The destination mac address
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createV4EtherMatchWithType(MatchBuilder matchBuilder,String srcMac, String dstMac, Long type)
+    {
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(type));
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        eth.setEthernetType(ethTypeBuilder.build());
+        if (null != srcMac) {
+            eth.setEthernetSource(new EthernetSourceBuilder()
+            .setAddress(new MacAddress(srcMac)).build());
+        }
+        if (null != dstMac) {
+            eth.setEthernetDestination(new EthernetDestinationBuilder()
+                           .setAddress(new MacAddress(dstMac)).build());
+        }
+        matchBuilder.setEthernetMatch(eth.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Creates a ether net match with ether type set to 0x86DDL.
+     * @param matchBuilder MatchBuilder Object
+     * @param srcMac The source macAddress
+     * @param dstMac The destination mac address
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createV6EtherMatchWithType(MatchBuilder matchBuilder,String srcMac, String dstMac)
+    {
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x86DDL));
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        eth.setEthernetType(ethTypeBuilder.build());
+        if (null != srcMac) {
+            eth.setEthernetSource(new EthernetSourceBuilder()
+            .setAddress(new MacAddress(srcMac)).build());
+        }
+        if (null != dstMac) {
+            eth.setEthernetDestination(new EthernetDestinationBuilder()
+                           .setAddress(new MacAddress(dstMac)).build());
+        }
+        matchBuilder.setEthernetMatch(eth.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Adds remote Ip prefix to existing match.
+     * @param matchBuilder The match builder
+     * @param sourceIpPrefix The source IP prefix
+     * @param destIpPrefix The destination IP prefix
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder addRemoteIpPrefix(MatchBuilder matchBuilder,
+                                          Ipv4Prefix sourceIpPrefix,Ipv4Prefix destIpPrefix) {
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        if (null != sourceIpPrefix) {
+            ipv4match.setIpv4Source(sourceIpPrefix);
+        }
+        if (null != destIpPrefix) {
+            ipv4match.setIpv4Destination(destIpPrefix);
+        }
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Adds remote Ipv6 prefix to existing match.
+     * @param matchBuilder The match builder
+     * @param sourceIpPrefix The source IP prefix
+     * @param destIpPrefix The destination IP prefix
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder addRemoteIpv6Prefix(MatchBuilder matchBuilder,
+                                                   Ipv6Prefix sourceIpPrefix,Ipv6Prefix destIpPrefix) {
+        Ipv6MatchBuilder ipv6match = new Ipv6MatchBuilder();
+        if (null != sourceIpPrefix) {
+            ipv6match.setIpv6Source(sourceIpPrefix);
+        }
+        if (null != destIpPrefix) {
+            ipv6match.setIpv6Destination(destIpPrefix);
+        }
+        matchBuilder.setLayer3Match(ipv6match.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Add a DSCP match to an existing match
+     * @param matchBuilder Map matchBuilder MatchBuilder Object with a match
+     * @param dscpValue
+     * @return {@link MatchBuilder}
+     */
+    public static MatchBuilder addDscp(MatchBuilder matchBuilder, short dscpValue) {
+        createEtherTypeMatch(matchBuilder, new EtherType(ETHERTYPE_IPV4));
+        return matchBuilder.setIpMatch(
+                new IpMatchBuilder()
+                        .setIpDscp(new Dscp(dscpValue))
+                        .build());
+    }
+
+    /**
+     * Add a layer4 match to an existing match
+     *
+     * @param matchBuilder Map matchBuilder MatchBuilder Object with a match
+     * @param protocol The layer4 protocol
+     * @param srcPort The src port
+     * @param destPort The destination port
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder addLayer4Match(MatchBuilder matchBuilder,
+                                              int protocol, int srcPort, int destPort) {
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        if (TCP_SHORT == protocol) {
+            ipmatch.setIpProtocol(TCP_SHORT);
+            TcpMatchBuilder tcpmatch = new TcpMatchBuilder();
+            if (0 != srcPort) {
+                tcpmatch.setTcpSourcePort(new PortNumber(srcPort));
+            }
+            if (0 != destPort) {
+                tcpmatch.setTcpDestinationPort(new PortNumber(destPort));
+            }
+            matchBuilder.setLayer4Match(tcpmatch.build());
+        } else if (UDP_SHORT == protocol) {
+            ipmatch.setIpProtocol(UDP_SHORT);
+            UdpMatchBuilder udpMatch = new UdpMatchBuilder();
+            if (0 != srcPort) {
+                udpMatch.setUdpSourcePort(new PortNumber(srcPort));
+            }
+            if (0 != destPort) {
+                udpMatch.setUdpDestinationPort(new PortNumber(destPort));
+            }
+            matchBuilder.setLayer4Match(udpMatch.build());
+        } else if (SCTP_SHORT == protocol) {
+            ipmatch.setIpProtocol(SCTP_SHORT);
+            SctpMatchBuilder sctpMatchBuilder = new SctpMatchBuilder();
+            if (0 != srcPort) {
+                sctpMatchBuilder.setSctpSourcePort(new PortNumber(srcPort));
+            }
+            if (0 != destPort) {
+                sctpMatchBuilder.setSctpDestinationPort(new PortNumber(destPort));
+            }
+            matchBuilder.setLayer4Match(sctpMatchBuilder.build());
+        }
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Add a layer4 match to an existing match with mask
+     *
+     * @param matchBuilder Map matchBuilder MatchBuilder Object with a match.
+     * @param protocol The layer4 protocol
+     * @param srcPort The src port
+     * @param destPort The destination port
+     * @param mask the mask for the port
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder addLayer4MatchWithMask(MatchBuilder matchBuilder,
+                                                      int protocol, int srcPort, int destPort,int mask) {
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+
+        NxAugMatchNodesNodeTableFlow nxAugMatch = null;
+        GeneralAugMatchNodesNodeTableFlow genAugMatch = null;
+        if (protocol == TCP_SHORT) {
+            ipmatch.setIpProtocol(TCP_SHORT);
+            if (0 != srcPort) {
+                NxmOfTcpSrcBuilder tcpSrc = new NxmOfTcpSrcBuilder();
+                tcpSrc.setPort(new PortNumber(srcPort));
+                tcpSrc.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfTcpSrc(tcpSrc.build()).build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfTcpSrcKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            } else if (0 != destPort) {
+                NxmOfTcpDstBuilder tcpDst = new NxmOfTcpDstBuilder();
+                tcpDst.setPort(new PortNumber(destPort));
+                tcpDst.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmOfTcpDst(tcpDst.build())
+                .build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfTcpDstKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            }
+
+        } else if (UDP_SHORT == protocol) {
+            ipmatch.setIpProtocol(UDP_SHORT);
+            UdpMatchBuilder udpMatch = new UdpMatchBuilder();
+            if (0 != srcPort) {
+                NxmOfUdpSrcBuilder udpSrc = new NxmOfUdpSrcBuilder();
+                udpSrc.setPort(new PortNumber(srcPort));
+                udpSrc.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfUdpSrc(udpSrc.build()).build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfUdpSrcKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            } else if (0 != destPort) {
+                NxmOfUdpDstBuilder udpDst = new NxmOfUdpDstBuilder();
+                udpDst.setPort(new PortNumber(destPort));
+                udpDst.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmOfUdpDst(udpDst.build())
+                .build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfUdpDstKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            }
+        }
+        matchBuilder.setIpMatch(ipmatch.build());
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, genAugMatch);
+        return matchBuilder;
+    }
+
+    public static MatchBuilder addCtState(MatchBuilder matchBuilder,int ct_state, int mask) {
+        NxmNxCtStateBuilder ctStateBuilder = new NxmNxCtStateBuilder();
+        ctStateBuilder.setCtState((long)ct_state);
+        ctStateBuilder.setMask((long)mask);
+        NxAugMatchNodesNodeTableFlow nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+        .setNxmNxCtState(ctStateBuilder.build())
+        .build();
+        GeneralAugMatchNodesNodeTableFlow genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+        .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmNxCtStateKey.class)
+                                           .setExtension(new ExtensionBuilder()
+                                           .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                         .build()).build())).build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, genAugMatch);
+        return matchBuilder;
+    }
+
+    public static MatchBuilder addCtZone(MatchBuilder matchBuilder,int ct_zone) {
+        NxmNxCtZoneBuilder ctZoneBuilder = new NxmNxCtZoneBuilder();
+        ctZoneBuilder.setCtZone(ct_zone);
+        NxAugMatchNodesNodeTableFlow nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+        .setNxmNxCtZone(ctZoneBuilder.build())
+        .build();
+        GeneralAugMatchNodesNodeTableFlow genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+        .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmNxCtZoneKey.class)
+                                           .setExtension(new ExtensionBuilder()
+                                           .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                         .build()).build())).build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, genAugMatch);
+        return matchBuilder;
+    }
+
+    public static class RegMatch {
+        final Class<? extends NxmNxReg> reg;
+        final Long value;
+        public RegMatch(Class<? extends NxmNxReg> reg, Long value) {
+            super();
+            this.reg = reg;
+            this.value = value;
+        }
+        public static RegMatch of(Class<? extends NxmNxReg> reg, Long value) {
+            return new RegMatch(reg, value);
+        }
+    }
+
+    public static MatchBuilder addNxRegMatch(MatchBuilder matchBuilder, RegMatch... matches) {
+        List<ExtensionList> extensions = new ArrayList<>();
+        for (RegMatch rm : matches) {
+            Class<? extends ExtensionKey> key;
+            if (NxmNxReg0.class.equals(rm.reg)) {
+                key = NxmNxReg0Key.class;
+            } else if (NxmNxReg1.class.equals(rm.reg)) {
+                key = NxmNxReg1Key.class;
+            } else if (NxmNxReg2.class.equals(rm.reg)) {
+                key = NxmNxReg2Key.class;
+            } else if (NxmNxReg3.class.equals(rm.reg)) {
+                key = NxmNxReg3Key.class;
+            } else if (NxmNxReg4.class.equals(rm.reg)) {
+                key = NxmNxReg4Key.class;
+            } else if (NxmNxReg5.class.equals(rm.reg)) {
+                key = NxmNxReg5Key.class;
+            } else if (NxmNxReg6.class.equals(rm.reg)) {
+                key = NxmNxReg6Key.class;
+            } else {
+                key = NxmNxReg7Key.class;
+            }
+            NxAugMatchNodesNodeTableFlow am =
+                    new NxAugMatchNodesNodeTableFlowBuilder()
+                            .setNxmNxReg(new NxmNxRegBuilder()
+                                    .setReg(rm.reg)
+                                    .setValue(rm.value)
+                                    .build())
+                            .build();
+            extensions.add(new ExtensionListBuilder()
+                    .setExtensionKey(key)
+                    .setExtension(new ExtensionBuilder()
+                            .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                            .build())
+                    .build());
+        }
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(extensions)
+                .build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+        return matchBuilder;
+    }
+
+    public static MatchBuilder addNxTunIdMatch(MatchBuilder matchBuilder, int tunId) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmNxTunId(new NxmNxTunIdBuilder()
+                        .setValue(BigInteger.valueOf(tunId))
+                        .build())
+                .build();
+        GeneralAugMatchNodesNodeTableFlow m =
+                new GeneralAugMatchNodesNodeTableFlowBuilder()
+                        .setExtensionList(ImmutableList.of(new ExtensionListBuilder()
+                                .setExtensionKey(NxmNxTunIdKey.class)
+                                .setExtension(new ExtensionBuilder()
+                                        .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                                        .build())
+                                .build()))
+                        .build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+        return matchBuilder;
+    }
+
+    public static MatchBuilder addNxNspMatch(MatchBuilder matchBuilder, long nsp) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmNxNsp(new NxmNxNspBuilder()
+                        .setValue(nsp)
+                        .build())
+                .build();
+        addExtension(matchBuilder, NxmNxNspKey.class, am);
+        return matchBuilder;
+    }
+
+    public static MatchBuilder addNxNsiMatch(MatchBuilder matchBuilder, short nsi) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmNxNsi(new NxmNxNsiBuilder()
+                        .setNsi(nsi)
+                        .build())
+                .build();
+        addExtension(matchBuilder, NxmNxNsiKey.class, am);
+        return matchBuilder;
+    }
+
+    private static void addExtension(MatchBuilder matchBuilder, Class<? extends ExtensionKey> extensionKey,
+                                     NxAugMatchNodesNodeTableFlow am) {
+        GeneralAugMatchNodesNodeTableFlow existingAugmentations =
+                matchBuilder.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class);
+        List<ExtensionList> extensions = null;
+        if (existingAugmentations != null ) {
+            extensions = existingAugmentations.getExtensionList();
+        }
+        if (extensions == null) {
+            extensions = Lists.newArrayList();
+        }
+
+        extensions.add(new ExtensionListBuilder()
+                .setExtensionKey(extensionKey)
+                .setExtension(new ExtensionBuilder()
+                        .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                        .build())
+                .build());
+
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(extensions)
+                .build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
+    public static EthernetMatch ethernetMatch(MacAddress srcMac,
+                                              MacAddress dstMac,
+                                              Long etherType) {
+        EthernetMatchBuilder emb = new  EthernetMatchBuilder();
+        if (srcMac != null) {
+            emb.setEthernetSource(new EthernetSourceBuilder()
+                .setAddress(srcMac)
+                .build());
+        }
+        if (dstMac != null) {
+            emb.setEthernetDestination(new EthernetDestinationBuilder()
+                .setAddress(dstMac)
+                .build());
+        }
+        if (etherType != null) {
+            emb.setEthernetType(new EthernetTypeBuilder()
+                .setType(new EtherType(etherType))
+                .build());
+        }
+        return emb.build();
+    }
+
+    /**
+     * Create ipv4 prefix from ipv4 address, by appending /32 mask
+     *
+     * @param ipv4AddressString the ip address, in string format
+     * @return Ipv4Prefix with ipv4Address and /32 mask
+     */
+    public static Ipv4Prefix iPv4PrefixFromIPv4Address(String ipv4AddressString) {
+        return new Ipv4Prefix(ipv4AddressString + "/32");
+    }
+
+    /**
+     * Create ipv6 prefix from ipv6 address, by appending /128 mask
+     *
+     * @param ipv6AddressString the ip address, in string format
+     * @return Ipv6Prefix with ipv6Address and /128 mask
+     */
+    public static Ipv6Prefix iPv6PrefixFromIPv6Address(String ipv6AddressString) {
+        return new Ipv6Prefix(ipv6AddressString + "/128");
+    }
+
+    /**
+     * Converts port range into a set of masked port ranges.
+     *
+     * @param portMin the strating port of the range.
+     * @param portMax the ending port of the range.
+     * @return the map contianing the port no and their mask.
+     *
+     */
+    public static Map<Integer,Integer>  getLayer4MaskForRange(int portMin, int portMax) {
+        int [] offset = {32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1};
+        int[] mask = {0x8000,0xC000,0xE000,0xF000,0xF800,0xFC00,0xFE00,0xFF00,
+            0xFF80,0xFFC0,0xFFE0,0xFFF0,0xFFF8,0xFFFC,0xFFFE,0xFFFF};
+        int noOfPorts = portMax - portMin + 1;
+        String binaryNoOfPorts = Integer.toBinaryString(noOfPorts);
+        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;
+            }
+        }
+        Map<Integer,Integer> portMap = new HashMap<Integer,Integer>();
+        int tempMedian = 0;
+        int currentMedain = median;
+        for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
+            tempMedian = currentMedain - offset[tempMedianOffset];
+            if (portMin <= tempMedian) {
+                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];
+            if (portMax >= tempMedian - 1) {
+                for (;portMax >= tempMedian - 1;) {
+                    portMap.put(currentMedain, mask[tempMedianOffset]);
+                    currentMedain = tempMedian;
+                    tempMedian = tempMedian  + offset[tempMedianOffset];
+                }
+            }
+        }
+        return portMap;
+    }
+
+    /**
+     * Return Long that represents OF port for strings where OF is explicitly provided
+     *
+     * @param ofPortIdentifier the string with encoded OF port (example format "OFPort|999")
+     * @return the OFport or null
+     */
+    public static Long parseExplicitOFPort(String ofPortIdentifier) {
+        if (ofPortIdentifier != null) {
+            String[] pair = ofPortIdentifier.split("\\|");
+            if ((pair.length > 1) && (pair[0].equalsIgnoreCase("OFPort"))) {
+                return new Long(pair[1]);
+            }
+        }
+        return null;
+    }
+}
diff --git a/utils/mdsal-openflow/src/test/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtilsTest.java b/utils/mdsal-openflow/src/test/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtilsTest.java
new file mode 100644 (file)
index 0000000..05ca4b5
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *  Copyright (C) 2014 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
+ *
+ *  Authors : Sam Hague
+ */
+package org.opendaylight.netvirt.utils.mdsal.openflow;
+
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class MatchUtilsTest {
+
+    @Test
+    public void testCreateInPortMatch () {
+        assertTrue(true);
+    }
+}
diff --git a/utils/mdsal-utils/pom.xml b/utils/mdsal-utils/pom.xml
new file mode 100644 (file)
index 0000000..21b2ff7
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>utils.mdsal-utils</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <developers>
+    <developer>
+      <name>Anil Vishnoi</name>
+      <email>vishnoianil@gmail.com</email>
+      <url>https://github.com/vishnoianil</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.netvirt.utils.mdsal.utils
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/utils/mdsal-utils/src/main/java/org/opendaylight/netvirt/utils/mdsal/utils/MdsalUtils.java b/utils/mdsal-utils/src/main/java/org/opendaylight/netvirt/utils/mdsal/utils/MdsalUtils.java
new file mode 100644 (file)
index 0000000..a243f60
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015 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.utils.mdsal.utils;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MdsalUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalUtils.class);
+    private DataBroker databroker = null;
+
+    /**
+     * Class constructor setting the data broker.
+     *
+     * @param dataBroker the {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}
+     */
+    public MdsalUtils(DataBroker dataBroker) {
+        this.databroker = dataBroker;
+    }
+
+    /**
+     * Executes delete as a blocking transaction.
+     *
+     * @param store {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} to read from
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean delete(
+            final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
+        boolean result = false;
+        final WriteTransaction transaction = databroker.newWriteOnlyTransaction();
+        transaction.delete(store, path);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.checkedGet();
+            result = true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to delete {} ", path, e);
+        }
+        return result;
+    }
+
+    /**
+     * Executes merge as a blocking transaction.
+     *
+     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean merge(
+            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data)  {
+        boolean result = false;
+        final WriteTransaction transaction = databroker.newWriteOnlyTransaction();
+        transaction.merge(logicalDatastoreType, path, data, true);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.checkedGet();
+            result = true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to merge {} ", path, e);
+        }
+        return result;
+    }
+
+    /**
+     * Executes put as a blocking transaction.
+     *
+     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean put(
+            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data)  {
+        boolean result = false;
+        final WriteTransaction transaction = databroker.newWriteOnlyTransaction();
+        transaction.put(logicalDatastoreType, path, data, true);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.checkedGet();
+            result = true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to put {} ", path, e);
+        }
+        return result;
+    }
+
+    /**
+     * Executes read as a blocking transaction.
+     *
+     * @param store {@link LogicalDatastoreType} to read
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result as the data object requested
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> D read(
+            final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
+        D result = null;
+        final ReadOnlyTransaction transaction = databroker.newReadOnlyTransaction();
+        Optional<D> optionalDataObject;
+        CheckedFuture<Optional<D>, ReadFailedException> future = transaction.read(store, path);
+        try {
+            optionalDataObject = future.checkedGet();
+            if (optionalDataObject.isPresent()) {
+                result = optionalDataObject.get();
+            } else {
+                LOG.debug("{}: Failed to read {}",
+                        Thread.currentThread().getStackTrace()[1], path);
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read {} ", path, e);
+        }
+        transaction.close();
+        return result;
+    }
+}
diff --git a/utils/mdsal-utils/src/main/java/org/opendaylight/netvirt/utils/mdsal/utils/NotifyingDataChangeListener.java b/utils/mdsal-utils/src/main/java/org/opendaylight/netvirt/utils/mdsal/utils/NotifyingDataChangeListener.java
new file mode 100644 (file)
index 0000000..66049b4
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 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.utils.mdsal.utils;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+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;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class provides methods for checking or waiting for various md-sal operations to complete.
+ * Once an instance is created one must invoke the registerDataChangeListener method
+ * with a DataBroker.
+ */
+public class NotifyingDataChangeListener implements AutoCloseable, DataChangeListener {
+    private static final Logger LOG = LoggerFactory.getLogger(NotifyingDataChangeListener.class);
+    private LogicalDatastoreType type;
+    private final Set<InstanceIdentifier<?>> createdIids = new HashSet<>();
+    private final Set<InstanceIdentifier<?>> removedIids = new HashSet<>();
+    private final Set<InstanceIdentifier<?>> updatedIids = new HashSet<>();
+    private InstanceIdentifier<?> iid;
+    private final int RETRY_WAIT = 100;
+    private final int MDSAL_TIMEOUT = 1000;
+    private ListenerRegistration<?> listenerRegistration;
+    private List<NotifyingDataChangeListener> waitList = null;
+
+    /**
+     * Create a new NotifyingDataChangeListener
+     * @param type
+     * @param iid of the md-sal object we're waiting for
+     * @param waitList for tracking outstanding changes
+     */
+    public NotifyingDataChangeListener(LogicalDatastoreType type,
+                                        InstanceIdentifier<?> iid, List<NotifyingDataChangeListener> waitList) {
+        this.type = type;
+        this.iid = iid;
+        this.waitList = waitList;
+        if(this.waitList != null) {
+            this.waitList.add(this);
+        }
+    }
+
+    /**
+     * Completely reset the state of this NotifyingDataChangeListener.
+     * @param type
+     * @param iid of the md-sal object we're waiting for
+     * @throws Exception
+     */
+    private void modify(LogicalDatastoreType type, InstanceIdentifier<?> iid) throws Exception {
+        this.close();
+        this.clear();
+        this.type = type;
+        this.iid = iid;
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+        LOG.info("{} DataChanged: created {}", type, asyncDataChangeEvent.getCreatedData().keySet());
+        LOG.info("{} DataChanged: updated {}", type, asyncDataChangeEvent.getUpdatedData().keySet());
+        LOG.info("{} DataChanged: removed {}", type, asyncDataChangeEvent.getRemovedPaths());
+        createdIids.addAll(asyncDataChangeEvent.getCreatedData().keySet());
+        removedIids.addAll(asyncDataChangeEvent.getRemovedPaths());
+        updatedIids.addAll(asyncDataChangeEvent.getUpdatedData().keySet());
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    public boolean isCreated(InstanceIdentifier<?> iid) {
+        return createdIids.remove(iid);
+    }
+
+    public boolean isUpdated(InstanceIdentifier<?> iid) {
+        return updatedIids.remove(iid);
+    }
+
+    public boolean isRemoved(InstanceIdentifier<?> iid) {
+        return removedIids.remove(iid);
+    }
+
+    public void clear() {
+        createdIids.clear();
+        removedIids.clear();
+        updatedIids.clear();
+    }
+
+    public void registerDataChangeListener(DataBroker dataBroker) {
+        listenerRegistration = dataBroker.registerDataChangeListener(type, iid, this,
+                AsyncDataBroker.DataChangeScope.SUBTREE);
+    }
+
+    public void waitForCreation() throws InterruptedException {
+        waitForCreation(MDSAL_TIMEOUT);
+    }
+
+    public void waitForCreation(long timeout) throws InterruptedException {
+        synchronized (this) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for {} DataChanged creation on {}", type, iid);
+            while (!isCreated(iid) && (System.currentTimeMillis() - _start) < timeout) {
+                wait(RETRY_WAIT);
+            }
+            LOG.info("Woke up, waited {}ms for creation of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    public void waitForUpdate() throws InterruptedException {
+        waitForUpdate(MDSAL_TIMEOUT);
+    }
+
+    public void waitForUpdate(long timeout) throws InterruptedException {
+        synchronized (this) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for {} DataChanged update on {}", type, iid);
+            while (!isUpdated(iid) && (System.currentTimeMillis() - _start) < timeout) {
+                wait(RETRY_WAIT);
+            }
+            LOG.info("Woke up, waited {}ms for update of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    public void waitForDeletion() throws InterruptedException {
+        waitForDeletion(MDSAL_TIMEOUT);
+    }
+
+    public void waitForDeletion(long timeout) throws InterruptedException {
+        synchronized (this) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for {} DataChanged deletion on {}", type, iid);
+            while (!isRemoved(iid) && (System.currentTimeMillis() - _start) < timeout) {
+                wait(RETRY_WAIT);
+            }
+            LOG.info("Woke up, waited {}ms for deletion of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception ex) {
+                LOG.warn("Failed to close registration {}, iid {}", listenerRegistration, iid, ex);
+            }
+        }
+        if (waitList != null) {
+            waitList.remove(this);
+        }
+        listenerRegistration = null;
+    }
+}
diff --git a/utils/mdsal-utils/src/test/java/org/opendaylight/netvirt/utils/mdsal/utils/MdsalUtilsTest.java b/utils/mdsal-utils/src/test/java/org/opendaylight/netvirt/utils/mdsal/utils/MdsalUtilsTest.java
new file mode 100644 (file)
index 0000000..38b1c9d
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015 Inocybe 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.utils.mdsal.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Unit test for class {@link MdsalUtils}
+ *
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings({ "unchecked", "rawtypes" })
+public class MdsalUtilsTest {
+
+    @InjectMocks private MdsalUtils mdsalUtils;
+
+    @Mock private DataBroker databroker;
+
+    @Test
+    public void testDelete() {
+        WriteTransaction writeTransaction = mock(WriteTransaction.class);
+        when(databroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        CheckedFuture<Void, TransactionCommitFailedException> future = mock(CheckedFuture.class);
+        when(writeTransaction.submit()).thenReturn(future );
+
+        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, mock(InstanceIdentifier.class));
+
+        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(writeTransaction, times(1)).submit();
+
+        assertTrue("Error, the delete transaction failed", result);
+    }
+
+    @Test
+    public void testMerge() {
+        WriteTransaction writeTransaction = mock(WriteTransaction.class);
+        when(databroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        CheckedFuture<Void, TransactionCommitFailedException> future = mock(CheckedFuture.class);
+        when(writeTransaction.submit()).thenReturn(future );
+
+        boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, mock(InstanceIdentifier.class), mock(DataObject.class));
+
+        verify(writeTransaction, times(1)).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+
+        assertTrue("Error, the merge transaction failed", result);
+    }
+
+    @Test
+    public void testPut() {
+        WriteTransaction writeTransaction = mock(WriteTransaction.class);
+        when(databroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        CheckedFuture<Void, TransactionCommitFailedException> future = mock(CheckedFuture.class);
+        when(writeTransaction.submit()).thenReturn(future );
+
+        boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, mock(InstanceIdentifier.class), mock(DataObject.class));
+
+        verify(writeTransaction, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class), anyBoolean());
+        verify(writeTransaction, times(1)).submit();
+
+        assertTrue("Error, the put transaction failed", result);
+    }
+
+    @Test
+    public void testRead() throws ReadFailedException {
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(databroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        CheckedFuture<Optional, ReadFailedException> future = mock(CheckedFuture.class);
+        Optional opt = mock(Optional.class);
+        when(opt.isPresent()).thenReturn(true);
+        DataObject obj = mock(DataObject.class);
+        when(opt.get()).thenReturn(obj );
+        when(future.checkedGet()).thenReturn(opt);
+        when(readOnlyTransaction.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(future);
+
+        DataObject result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, mock(InstanceIdentifier.class));
+
+        verify(readOnlyTransaction, times(1)).read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(readOnlyTransaction, times(1)).close();
+
+        assertEquals("Error, the read transaction failed", obj, result);
+    }
+}
diff --git a/utils/netvirt-it-utils/pom.xml b/utils/netvirt-it-utils/pom.xml
new file mode 100644 (file)
index 0000000..64f65ad
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>utils.netvirt-it-utils</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <properties>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+  </properties>
+
+  <dependencies>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-api</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>utils.mdsal-utils</artifactId>
+          <version>${project.version}</version>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>utils.neutron-utils</artifactId>
+          <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.ovsdb</groupId>
+        <artifactId>utils.mdsal-utils</artifactId>
+        <version>${ovsdb.version}</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.ovsdb</groupId>
+          <artifactId>southbound-api</artifactId>
+          <version>${ovsdb.version}</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.ovsdb</groupId>
+          <artifactId>utils.southbound-utils</artifactId>
+          <version>${project.version}</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.netvirt</groupId>
+          <artifactId>utils.mdsal-openflow</artifactId>
+          <version>${project.version}</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.mdsal.model</groupId>
+          <artifactId>ietf-inet-types</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.mdsal.model</groupId>
+          <artifactId>ietf-topology</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+          <scope>compile</scope>
+      </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>
+              utils.mdsal-openflow;groupId=org.opendaylight.netvirt;type=!pom;inline=false
+            </Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+            <Export-Package>
+              org.opendaylight.netvirt.utils.netvirt.it.utils
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/ItConstants.java b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/ItConstants.java
new file mode 100644 (file)
index 0000000..eac8a97
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 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.utils.netvirt.it.utils;
+
+/**
+ * Constants for SouthboundIT.
+ */
+public final class ItConstants {
+    private ItConstants() {
+        throw new AssertionError("This class should not be instantiated.");
+    }
+
+    public static final String ORG_OPS4J_PAX_LOGGING_CFG = "etc/org.ops4j.pax.logging.cfg";
+    public static final String CUSTOM_PROPERTIES = "etc/custom.properties";
+    public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
+    public static final String SERVER_PORT = "ovsdbserver.port";
+    public static final String CONTROLLER_IPADDRESS = "ovsdb.controller.address";
+    public static final String USERSPACE_ENABLED = "ovsdb.userspace.enabled";
+    public static final String SERVER_EXTRAS = "ovsdbserver.extras";
+    public static final String CONNECTION_TYPE = "ovsdbserver.connection";
+    public static final String CONNECTION_TYPE_ACTIVE = "active";
+    public static final String CONNECTION_TYPE_PASSIVE = "passive";
+    public static final int CONNECTION_INIT_TIMEOUT = 10000;
+    public static final String DEFAULT_SERVER_IPADDRESS = "127.0.0.1";
+    public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String DEFAULT_OPENFLOW_PORT = "6653";
+    public static final String DEFAULT_SERVER_EXTRAS = "false";
+    public static final String BRIDGE_NAME = "brtest";
+    public static final String PORT_NAME = "porttest";
+    public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+    public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
+    public static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
+}
diff --git a/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java
new file mode 100644 (file)
index 0000000..41dcb05
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 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.utils.netvirt.it.utils;
+
+import static org.junit.Assert.assertNotNull;
+
+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.BindingAwareBroker;
+import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.NotifyingDataChangeListener;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+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.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class contains various utility methods used in netvirt integration tests (IT).
+ */
+public class NetvirtItUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtItUtils.class);
+    MdsalUtils mdsalUtils;
+    SouthboundUtils southboundUtils;
+    DataBroker dataBroker;
+
+    /**
+     * Create a new NetvirtItUtils instance.
+     * @param dataBroker  md-sal data broker
+     */
+    public NetvirtItUtils(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        mdsalUtils = new MdsalUtils(dataBroker);
+        southboundUtils = new SouthboundUtils(mdsalUtils);
+    }
+
+    /**
+     * Check that the netvirt topology is in the operational mdsal.
+     * @return true if the netvirt topology was successfully retrieved
+     */
+    public Boolean getNetvirtTopology() {
+        LOG.info("getNetvirtTopology: looking for {}...", ItConstants.NETVIRT_TOPOLOGY_ID);
+        final TopologyId topologyId = new TopologyId(new Uri(ItConstants.NETVIRT_TOPOLOGY_ID));
+        InstanceIdentifier<Topology> path =
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+        NotifyingDataChangeListener waitForIt = new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                path, null);
+        waitForIt.registerDataChangeListener(dataBroker);
+        try {
+            waitForIt.waitForCreation(60 * 1000);
+        } catch (InterruptedException e) {
+            LOG.info("getNetvirtTopology: InterruptedException while wait(ing)ForCreation");
+        }
+
+        boolean found = null != mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+
+        LOG.info("getNetvirtTopology: found {} == {}", ItConstants.NETVIRT_TOPOLOGY_ID, found);
+
+        return found;
+    }
+
+    /**
+     * Verify that the given flow was installed in a table. This method will wait 10 seconds for the flows
+     * to appear in each of the md-sal CONFIGURATION and OPERATIONAL data stores
+     * @param datapathId dpid where flow is installed
+     * @param flowId The "name" of the flow, e.g., "TunnelFloodOut_100"
+     * @param table integer value of table
+     * @throws InterruptedException if interrupted while waiting for flow to appear in mdsal
+     */
+    public void verifyFlow(long datapathId, String flowId, short table) throws InterruptedException {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+                FlowUtils.createNodeBuilder(datapathId);
+        FlowBuilder flowBuilder =
+                FlowUtils.initFlowBuilder(new FlowBuilder(), flowId, table);
+        InstanceIdentifier<Flow> iid = FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
+
+        NotifyingDataChangeListener waitForIt = new NotifyingDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                iid, null);
+        waitForIt.registerDataChangeListener(dataBroker);
+        waitForIt.waitForCreation(10000);
+
+        Flow flow = FlowUtils.getFlow(flowBuilder, nodeBuilder,
+                        dataBroker.newReadOnlyTransaction(), LogicalDatastoreType.CONFIGURATION);
+        assertNotNull("Could not find flow in config: " + flowBuilder.build() + "--" + nodeBuilder.build(), flow);
+
+        waitForIt = new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, iid, null);
+        waitForIt.registerDataChangeListener(dataBroker);
+        waitForIt.waitForCreation(10000);
+
+        flow = FlowUtils.getFlow(flowBuilder, nodeBuilder,
+                        dataBroker.newReadOnlyTransaction(), LogicalDatastoreType.OPERATIONAL);
+        assertNotNull("Could not find flow in operational: " + flowBuilder.build() + "--" + nodeBuilder.build(),
+                flow);
+    }
+
+    /**
+     * Log the flows in a given table.
+     * @param datapathId dpid
+     * @param tableNum table number
+     * @param store configuration or operational
+     */
+    public void logFlows(long datapathId, short tableNum, LogicalDatastoreType store) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+                FlowUtils.createNodeBuilder(datapathId);
+        Table table = FlowUtils.getTable(nodeBuilder, tableNum, dataBroker.newReadOnlyTransaction(), store);
+        if (table == null) {
+            LOG.info("logFlows: Could not find table {} in {}", tableNum, store);
+        }
+        //TBD: Log table and store in one line, flows in following lines
+        for (Flow flow : table.getFlow()) {
+            LOG.info("logFlows: table {} flow {} in {}", tableNum, flow.getFlowName(), store);
+        }
+    }
+
+    /**
+     * Log the flows in a given table.
+     * @param datapathId dpid
+     * @param table table number
+     */
+    public void logFlows(long datapathId, short table) {
+        logFlows(datapathId, table, LogicalDatastoreType.CONFIGURATION);
+    }
+
+    /**
+     * Get a DataBroker and assert that it is not null.
+     * @param providerContext ProviderContext from which to retrieve the DataBroker
+     * @return the Databroker
+     */
+    public static DataBroker getDatabroker(BindingAwareBroker.ProviderContext providerContext) {
+        DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
+        assertNotNull("dataBroker should not be null", dataBroker);
+        return dataBroker;
+    }
+}
diff --git a/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java
new file mode 100644 (file)
index 0000000..2b5cdbf
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 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.utils.netvirt.it.utils;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.Vector;
+
+import com.google.common.collect.Maps;
+import org.junit.Assert;
+import org.opendaylight.netvirt.utils.neutron.utils.NeutronUtils;
+import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+/**
+ * A utility class used in integration tests that need to create neutron networks with some ports.
+ * Please see NetvirtIT#testNeutronNet for an example of how this class is used
+ */
+public class NeutronNetItUtil {
+
+    public final String tenantId;
+    public final String id;
+    public final String subnetId;
+    public NeutronNetwork neutronNetwork;
+    public NeutronSubnet neutronSubnet;
+    public String segId = "100";
+    public String macPfx;
+    public String ipPfx;
+    public String cidr;
+
+    public SouthboundUtils southboundUtils;
+    public NeutronUtils neutronUtils;
+    public Vector<NeutronPort> neutronPorts = new Vector();
+
+    /**
+     * Construct a new NeutronNetItUtil.
+     * @param southboundUtils used to create termination points
+     * @param tenantId tenant ID
+     */
+    public NeutronNetItUtil(SouthboundUtils southboundUtils, String tenantId) {
+        this(southboundUtils, tenantId, "101", "f7:00:00:0f:00:", "10.0.0.", "10.0.0.0/24");
+    }
+
+    /**
+     * Construct a new NeutronNetItUtil.
+     * @param southboundUtils used to create termination points
+     * @param tenantId tenant ID
+     * @param segId the segmentation id to use for the neutron network
+     * @param macPfx the first characters of the mac addresses generated for ports. Format is "f7:00:00:0f:00:"
+     * @param ipPfx the first characters of the ip addresses generated for ports. Format is "10.0.0."
+     * @param cidr the cidr for this network, e.g., "10.0.0.0/24"
+     */
+    public NeutronNetItUtil(SouthboundUtils southboundUtils, String tenantId,
+                            String segId, String macPfx, String ipPfx, String cidr) {
+        this.tenantId = tenantId;
+        this.segId = segId;
+        this.macPfx = macPfx;
+        this.ipPfx = ipPfx;
+        this.cidr = cidr;
+
+        this.id = UUID.randomUUID().toString();
+        this.subnetId = UUID.randomUUID().toString();
+
+        this.southboundUtils = southboundUtils;
+        neutronUtils = new NeutronUtils();
+        neutronNetwork = null;
+        neutronSubnet = null;
+    }
+
+    /**
+     * Create the network and subnet.
+     */
+    public void create() {
+        neutronNetwork = neutronUtils.createNeutronNetwork(id, tenantId, "vxlan", segId);
+        neutronSubnet = neutronUtils.createNeutronSubnet(subnetId, tenantId, id, "10.0.0.0/24");
+    }
+
+    /**
+     * Clean up all created neutron objects.
+     */
+    public void destroy() {
+        for (NeutronPort port : neutronPorts) {
+            neutronUtils.removeNeutronPort(port.getID());
+        }
+        neutronPorts.clear();
+
+        if (neutronSubnet != null) {
+            neutronUtils.removeNeutronSubnet(neutronSubnet.getID());
+            neutronSubnet = null;
+        }
+
+        if (neutronNetwork != null) {
+            neutronUtils.removeNeutronNetwork(neutronNetwork.getID());
+            neutronNetwork = null;
+        }
+    }
+
+    /**
+     * Create a port on the network. The deviceOwner will be set to "compute:None".
+     * @param bridge bridge where the port will be created on OVS
+     * @param portName name for this port
+     * @throws InterruptedException if we're interrupted while waiting for objects to be created
+     */
+    public void createPort(Node bridge, String portName) throws InterruptedException {
+        createPort(bridge, portName, "compute:None");
+    }
+
+    /**
+     * Create a port on the network. The deviceOwner will be set to "compute:None".
+     * @param bridge bridge where the port will be created on OVS
+     * @param portName name for this port
+     * @param owner deviceOwner, e.g., "network:dhcp"
+     * @throws InterruptedException if we're interrupted while waiting for objects to be created
+     */
+    public void createPort(Node bridge, String portName, String owner) throws InterruptedException {
+        long idx = neutronPorts.size() + 1;
+        Assert.assertTrue(idx < 256);
+        String mac = macFor(idx);
+        String ip = ipFor(idx);
+        String portId = UUID.randomUUID().toString();
+        neutronPorts.add(neutronUtils.createNeutronPort(id, subnetId, portId, owner, ip, mac));
+
+        //TBD: Use NotifyingDataChangeListener
+        Thread.sleep(1000);
+
+        Map<String, String> externalIds = Maps.newHashMap();
+        externalIds.put("attached-mac", mac);
+        externalIds.put("iface-id", portId);
+        southboundUtils.addTerminationPoint(bridge, portName, "internal", null, externalIds, idx);
+    }
+
+    /**
+     * Get the mac address for the n'th port created on this network (starts at 1).
+     * @param portNum index of port created
+     * @return the mac address
+     */
+    public String macFor(long portNum) {
+        return macPfx + String.format("%02x", portNum);
+    }
+
+    /**
+     * Get the ip address for the n'th port created on this network (starts at 1).
+     * @param portNum index of port created
+     * @return the mac address
+     */
+    public String ipFor(long portNum) {
+        return ipPfx + portNum;
+    }
+}
+
diff --git a/utils/neutron-utils/pom.xml b/utils/neutron-utils/pom.xml
new file mode 100644 (file)
index 0000000..c6bd5fa
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-parent</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+      <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.netvirt</groupId>
+    <artifactId>utils.neutron-utils</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <neutron.version>0.7.0-SNAPSHOT</neutron.version>
+    </properties>
+
+    <dependencies>
+    <!-- project specific dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>utils.mdsal-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>utils.servicehelper</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    <!-- neutron dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.neutron</groupId>
+            <artifactId>model</artifactId>
+            <version>0.7.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.neutron</groupId>
+            <artifactId>neutron-spi</artifactId>
+            <version>${neutron.version}</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronModelsDataStoreHelper.java b/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronModelsDataStoreHelper.java
new file mode 100644 (file)
index 0000000..fa78525
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015 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.utils.neutron.utils;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netvirt.utils.mdsal.utils.MdsalUtils;
+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.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
+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.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronModelsDataStoreHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalUtils.class);
+    private DataBroker databroker = null;
+    private MdsalUtils mdsalClient = null;
+
+    /**
+     * Class constructor setting the data broker.
+     *
+     * @param dataBroker the {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}
+     */
+    public NeutronModelsDataStoreHelper(DataBroker dataBroker) {
+        this.databroker = dataBroker;
+        this.mdsalClient = new MdsalUtils(this.databroker);
+    }
+
+    public Routers readAllNeutronRouters() {
+        Routers routers = this.mdsalClient.read(LogicalDatastoreType.CONFIGURATION, getNeutrounRoutersPath());
+        if(routers != null ) {
+            LOG.debug("{} routers present in data store", routers.getRouter()!=null? routers.getRouter().size():0);
+        }
+        return routers;
+    }
+
+    public Ports readAllNeutronPorts() {
+        Ports ports = this.mdsalClient.read(LogicalDatastoreType.CONFIGURATION, getNeutrounPortsPath());
+        if(ports != null ) {
+            LOG.debug("{} ports present in data store", ports.getPort()!=null? ports.getPort().size():0);
+        }
+        return ports;
+    }
+    public Port readNeutronPort(Uuid portId) {
+        Port mdsalPort = this.mdsalClient.read(LogicalDatastoreType.CONFIGURATION, getNeutronPortPath(portId));
+        if (mdsalPort != null) {
+            LOG.debug("Port {} fetched from config data store for router interface {}",mdsalPort, portId);
+        }
+        return mdsalPort;
+    }
+
+    public InstanceIdentifier<Routers> getNeutrounRoutersPath() {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Routers.class);
+    }
+
+    public InstanceIdentifier<Ports> getNeutrounPortsPath() {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Ports.class);
+    }
+
+    public InstanceIdentifier<Port> getNeutronPortPath(Uuid portId) {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Ports.class)
+                .child(Port.class,new PortKey(portId));
+    }
+
+    public InstanceIdentifier<Network> getNeutronNetworkPath(Uuid networkId) {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Networks.class)
+                .child(Network.class,new NetworkKey(networkId));
+    }
+}
diff --git a/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java b/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java
new file mode 100644 (file)
index 0000000..b7a48c5
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.utils.neutron.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
+import org.opendaylight.neutron.spi.INeutronPortCRUD;
+import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
+import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+
+public class NeutronUtils {
+    public NeutronPort createNeutronPort(String networkId, String subnetId,
+                                         String id, String owner, String ipaddr, String mac) {
+        INeutronPortCRUD iNeutronPortCRUD =
+                (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+        NeutronPort np = new NeutronPort();
+        np.initDefaults();
+        np.setID(id);
+        np.setDeviceOwner(owner);
+        np.setMacAddress(mac);
+        np.setNetworkUUID(networkId);
+        List<org.opendaylight.neutron.spi.Neutron_IPs> srcAddressList =
+                new ArrayList<>();
+        org.opendaylight.neutron.spi.Neutron_IPs nip = new org.opendaylight.neutron.spi.Neutron_IPs();
+        nip.setIpAddress(ipaddr);
+        nip.setSubnetUUID(subnetId);
+        srcAddressList.add(nip);
+        np.setFixedIPs(srcAddressList);
+        List<NeutronSecurityGroup> nsgs = new ArrayList<>();
+        np.setSecurityGroups(nsgs);
+        iNeutronPortCRUD.add(np);
+        return np;
+    }
+
+    public boolean removeNeutronPort(String uuid) {
+        INeutronPortCRUD iNeutronPortCRUD =
+                (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+        return iNeutronPortCRUD.removePort(uuid);
+    }
+
+    public NeutronSubnet createNeutronSubnet(String subnetId, String tenantId,
+                                              String networkId, String cidr) {
+        INeutronSubnetCRUD iNeutronSubnetCRUD =
+                (INeutronSubnetCRUD) ServiceHelper.getGlobalInstance(INeutronSubnetCRUD.class, this);
+        NeutronSubnet ns = new NeutronSubnet();
+        ns.setID(subnetId);
+        ns.setCidr(cidr);
+        ns.initDefaults();
+        ns.setNetworkUUID(networkId);
+        ns.setTenantID(tenantId);
+        iNeutronSubnetCRUD.add(ns);
+        return ns;
+    }
+
+    public boolean removeNeutronSubnet(String uuid) {
+        INeutronSubnetCRUD iNeutronSubnetCRUD =
+                (INeutronSubnetCRUD) ServiceHelper.getGlobalInstance(INeutronSubnetCRUD.class, this);
+        return iNeutronSubnetCRUD.removeSubnet(uuid);
+    }
+
+    public NeutronNetwork createNeutronNetwork(String uuid, String tenantID, String networkTypeVxlan, String segId) {
+        INeutronNetworkCRUD iNeutronNetworkCRUD =
+                (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+        NeutronNetwork nn = new NeutronNetwork();
+        nn.setID(uuid);
+        nn.initDefaults();
+        nn.setTenantID(tenantID);
+        nn.setProviderNetworkType(networkTypeVxlan);
+        nn.setProviderSegmentationID(segId);
+        iNeutronNetworkCRUD.addNetwork(nn);
+        return nn;
+    }
+
+    public boolean removeNeutronNetwork(String uuid) {
+        INeutronNetworkCRUD iNeutronNetworkCRUD =
+                (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+        return iNeutronNetworkCRUD.removeNetwork(uuid);
+
+    }
+}
diff --git a/utils/pom.xml b/utils/pom.xml
new file mode 100644 (file)
index 0000000..5e61d5f
--- /dev/null
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>utils</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <packaging>pom</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>config</module>
+    <module>mdsal-openflow</module>
+    <module>mdsal-utils</module>
+    <module>netvirt-it-utils</module>
+    <module>neutron-utils</module>
+    <module>servicehelper</module>
+  </modules>
+
+<!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/utils/servicehelper/pom.xml b/utils/servicehelper/pom.xml
new file mode 100644 (file)
index 0000000..746bf64
--- /dev/null
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netvirt</groupId>
+  <artifactId>utils.servicehelper</artifactId>
+  <version>1.3.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
+  <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  <licenses>
+    <license>
+      <name>Eclipse Public License v1.0</name>
+      <url>http://www.eclipse.org/legal/epl-v10.html</url>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <name>Sam Hague</name>
+      <email>shague@gmail.com</email>
+      <url>https://github.com/shague</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netvirt.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.osgi</groupId>
+      <artifactId>spring-osgi-mock</artifactId>
+      <version>1.2.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.netvirt.utils.servicehelper
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/utils/servicehelper/src/main/java/org/opendaylight/netvirt/utils/servicehelper/ServiceHelper.java b/utils/servicehelper/src/main/java/org/opendaylight/netvirt/utils/servicehelper/ServiceHelper.java
new file mode 100644 (file)
index 0000000..7b7e12d
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.utils.servicehelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The class helps to register and retrieve OSGi service registry
+ */
+public final class ServiceHelper {
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceHelper.class);
+    private static final Map<Class<?>, Object> OVERRIDES = new HashMap<>();
+
+    /**
+     * Override a global instance. This should generally only be used for testing.
+     *
+     * @param clazz The target class.
+     * @param instance The instance to return for the class.
+     */
+    public static <T> void overrideGlobalInstance(Class<T> clazz, T instance) {
+        ServiceHelper.OVERRIDES.put(clazz, instance);
+    }
+
+    /**
+     * Retrieve global instance of a class via OSGI registry, if
+     * there are many only the first is returned.
+     *
+     * @param clazz The target class
+     * @param bundle The caller
+     */
+    public static Object getGlobalInstance(Class<?> clazz, Object bundle) {
+        return getGlobalInstance(clazz, bundle, null);
+    }
+
+    /**
+     * Retrieve global instance of a class via OSGI registry, if
+     * there are many only the first is returned. On this version an LDAP
+     * type of filter is applied
+     *
+     * @param clazz The target class
+     * @param bundle The caller
+     * @param serviceFilter LDAP filter to be applied in the search
+     */
+    public static Object getGlobalInstance(Class<?> clazz, Object bundle,
+                                           String serviceFilter) {
+        if (OVERRIDES.containsKey(clazz)) {
+            return OVERRIDES.get(clazz);
+        }
+        Object[] instances = getGlobalInstances(clazz, bundle, serviceFilter);
+        if (instances != null && instances.length > 0) {
+            return instances[0];
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve all the Instances of a Service, optionally
+     * filtered via serviceFilter if non-null else all the results are
+     * returned if null
+     *
+     * @param clazz The target class
+     * @param bundle The caller
+     * @param serviceFilter LDAP filter to be applied in the search
+     */
+    private static Object[] getGlobalInstances(Class<?> clazz, Object bundle,
+                                              String serviceFilter) {
+        Object instances[] = null;
+        try {
+            Bundle ourBundle = FrameworkUtil.getBundle(bundle.getClass());
+            if (ourBundle != null) {
+                BundleContext bCtx = ourBundle.getBundleContext();
+
+                ServiceReference<?>[] services = bCtx.getServiceReferences(clazz
+                        .getName(), serviceFilter);
+
+                if (services != null) {
+                    instances = new Object[services.length];
+                    for (int i = 0; i < services.length; i++) {
+                        instances[i] = bCtx.getService(services[i]);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Error retrieving global instances of {} from caller {} with filter {}",
+                    clazz, bundle, serviceFilter, e);
+        }
+        return instances;
+    }
+}
diff --git a/utils/servicehelper/src/test/java/org/opendaylight/netvirt/utils/servicehelper/ServiceHelperTest.java b/utils/servicehelper/src/test/java/org/opendaylight/netvirt/utils/servicehelper/ServiceHelperTest.java
new file mode 100644 (file)
index 0000000..b06c68d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (C) 2015 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
+ *
+ *  Authors : Sam Hague
+ */
+package org.opendaylight.netvirt.utils.servicehelper;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.osgi.mock.MockBundle;
+
+/**
+ * JUnit test for
+ * {@link ServiceHelper}
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(FrameworkUtil.class)
+public class ServiceHelperTest {
+    @Test
+    /**
+     * Test method for
+     * {@link ServiceHelper#getGlobalInstance(Class, Object)}
+     */
+    public void getGlobalInstanceTest () {
+        Bundle bundle = new MockBundle();
+
+        PowerMockito.mockStatic(FrameworkUtil.class);
+
+        PowerMockito.when(FrameworkUtil.getBundle(any(Class.class)))
+                .thenReturn(null);
+        Object object = ServiceHelper.getGlobalInstance(Test.class, this);
+        assertNull("Service should be null", object);
+
+        PowerMockito.when(FrameworkUtil.getBundle(any(Class.class)))
+                .thenReturn(bundle);
+        object = ServiceHelper.getGlobalInstance(Test.class, this);
+        assertNotNull("Service should not be null", object);
+    }
+}
diff --git a/vpnservice/.gitignore b/vpnservice/.gitignore
new file mode 100644 (file)
index 0000000..bbbe4f2
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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
+#
+.classpath
+.project
+.settings
+.metadata
+target
+*.iml
+.idea
+bin
+xtend-gen
+target
+.DS_Store
+.checkstyle
+yang-gen-config
+yang-gen-sal
+classes
+maven-metadata-local.xml
+META-INF
diff --git a/vpnservice/.gitreview b/vpnservice/.gitreview
new file mode 100644 (file)
index 0000000..a959a5e
--- /dev/null
@@ -0,0 +1,5 @@
+[gerrit]
+host=git.opendaylight.org
+port=29418
+project=vpnservice.git
+defaultbranch=master
similarity index 100%
rename from arputil/pom.xml
rename to vpnservice/arputil/pom.xml
diff --git a/vpnservice/features/pom.xml b/vpnservice/features/pom.xml
new file mode 100644 (file)
index 0000000..dff7cec
--- /dev/null
@@ -0,0 +1,468 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>features-parent</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>vpnservice-features</artifactId>
+  <version>0.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <properties>
+    <mdsal.version>1.4.0-SNAPSHOT</mdsal.version>
+    <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
+    <restconf.version>1.4.0-SNAPSHOT</restconf.version>
+    <yangtools.version>1.0.0-SNAPSHOT</yangtools.version>
+    <mdsal.model.version>0.9.0-SNAPSHOT</mdsal.model.version>
+    <vpnservices.version>0.3.0-SNAPSHOT</vpnservices.version>
+    <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
+    <liblldp.version>0.11.0-SNAPSHOT</liblldp.version>
+    <neutron.version>0.7.0-SNAPSHOT</neutron.version>
+    <nic.version>1.2.0-SNAPSHOT</nic.version>
+    <arputil.version>${vpnservices.version}</arputil.version>
+    <mdsalutil.version>${vpnservices.version}</mdsalutil.version>
+    <vpnmanager.version>${vpnservices.version}</vpnmanager.version>
+    <interfacemgr.version>${vpnservices.version}</interfacemgr.version>
+    <elanmgr.version>${vpnservices.version}</elanmgr.version>
+    <nexthopmgr.version>${vpnservices.version}</nexthopmgr.version>
+    <fibmanager.version>${vpnservices.version}</fibmanager.version>
+    <lockmanager.version>${vpnservices.version}</lockmanager.version>
+    <idmanager.version>${vpnservices.version}</idmanager.version>
+    <itm.version>${vpnservices.version}</itm.version>
+    <neutronvpn.version>${vpnservices.version}</neutronvpn.version>
+    <fcaps.manager.version>${vpnservices.version}</fcaps.manager.version>
+    <fcaps.app.version>${vpnservices.version}</fcaps.app.version>
+  </properties>
+  <dependencyManagement>
+    <dependencies>
+      <!-- project specific dependencies -->
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>mdsal-artifacts</artifactId>
+        <version>${mdsal.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>restconf-artifacts</artifactId>
+        <version>${restconf.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-yangtools</artifactId>
+      <classifier>features</classifier>
+      <version>${yangtools.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-mdsal</artifactId>
+      <classifier>features</classifier>
+      <version>${mdsal.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>features-mdsal-model</artifactId>
+      <version>${mdsal.model.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>features-nic</artifactId>
+      <classifier>features</classifier>
+      <version>${nic.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>southbound-features</artifactId>
+      <version>${ovsdb.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>hwvtepsouthbound-features</artifactId>
+      <version>${ovsdb.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin</artifactId>
+      <classifier>features</classifier>
+      <version>${openflowplugin.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>features-restconf</artifactId>
+      <classifier>features</classifier>
+      <version>${restconf.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>features-neutron</artifactId>
+      <classifier>features</classifier>
+      <version>${neutron.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>dummyprovider</artifactId>
+      <version>${neutron.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnmanager-impl</artifactId>
+      <version>${vpnmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnmanager-impl</artifactId>
+      <version>${vpnmanager.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>mdsalutil-impl</artifactId>
+      <version>${mdsalutil.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>arputil-api</artifactId>
+      <version>${arputil.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>arputil-impl</artifactId>
+      <version>${arputil.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+     <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>arputil-impl</artifactId>
+      <version>${arputil.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>mdsalutil-impl</artifactId>
+      <version>${mdsalutil.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>mdsalutil-api</artifactId>
+      <version>${mdsalutil.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-impl</artifactId>
+      <version>${interfacemgr.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-impl</artifactId>
+      <version>${interfacemgr.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-api</artifactId>
+      <version>${interfacemgr.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-shell</artifactId>
+      <version>${interfacemgr.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>elanmanager-impl</artifactId>
+      <version>${elanmgr.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>elanmanager-impl</artifactId>
+      <version>${elanmgr.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>elanmanager-api</artifactId>
+      <version>${elanmgr.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>liblldp</artifactId>
+        <version>${liblldp.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>alivenessmonitor-impl</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>alivenessmonitor-impl</artifactId>
+      <version>${vpnservices.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>alivenessmonitor-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnmanager-api</artifactId>
+      <version>${vpnmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>bgpmanager-impl</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>bgpmanager-impl</artifactId>
+      <version>${vpnservices.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>bgpmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>model-bgp</artifactId>
+      <version>2013.07.15.9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fibmanager-impl</artifactId>
+      <version>${fibmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fibmanager-impl</artifactId>
+      <version>${fibmanager.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fibmanager-shell</artifactId>
+      <version>${fibmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fibmanager-api</artifactId>
+      <version>${fibmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>lockmanager-impl</artifactId>
+      <version>${lockmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>lockmanager-impl</artifactId>
+      <version>${lockmanager.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>lockmanager-api</artifactId>
+      <version>${lockmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>idmanager-impl</artifactId>
+      <version>${idmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>idmanager-impl</artifactId>
+      <version>${idmanager.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>idmanager-api</artifactId>
+      <version>${idmanager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>itm-impl</artifactId>
+      <version>${itm.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>itm-impl</artifactId>
+      <version>${itm.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>itm-api</artifactId>
+      <version>${itm.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>dhcpservice-impl</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>dhcpservice-impl</artifactId>
+      <version>${vpnservices.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>dhcpservice-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>natservice-impl</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>natservice-impl</artifactId>
+      <version>${vpnservices.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>natservice-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>neutronvpn-api</artifactId>
+      <version>${neutronvpn.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>neutronvpn-impl</artifactId>
+      <version>${neutronvpn.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>neutronvpn-impl</artifactId>
+      <version>${neutronvpn.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>neutronvpn-shell</artifactId>
+      <version>${neutronvpn.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.thrift</groupId>
+      <artifactId>libthrift</artifactId>
+      <version>0.9.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin-extension</artifactId>
+      <classifier>features</classifier>
+      <version>${openflowplugin.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-impl</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-impl</artifactId>
+      <version>${vpnservices.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>alarmmanager</artifactId>
+      <version>${fcaps.manager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>countermanager</artifactId>
+      <version>${fcaps.manager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fcaps-api</artifactId>
+      <version>${fcaps.manager.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fcapsapplication-jmxapi</artifactId>
+      <version>${fcaps.app.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>fcapsapplication-impl</artifactId>
+      <version>${fcaps.app.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/vpnservice/features/src/main/features/features.xml b/vpnservice/features/src/main/features/features.xml
new file mode 100644 (file)
index 0000000..ead3c81
--- /dev/null
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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
+-->
+<features name="odl-vpnservice-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+  <repository>mvn:org.opendaylight.yangtools/features-yangtools/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.netconf/features-restconf/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.ovsdb/southbound-features/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.neutron/features-neutron/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.nic/features-nic/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.ovsdb/hwvtepsouthbound-features/{{VERSION}}/xml/features</repository>
+  <feature name='odl-vpnservice-api' version='${project.version}' description='OpenDaylight :: vpnservice :: api '>
+    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
+    <feature version='${openflowplugin.version}'>odl-openflowplugin-nsf-model</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nxm-extensions</feature>
+    <feature version="${ovsdb.version}">odl-ovsdb-southbound-impl-rest</feature>
+    <feature version='${ovsdb.version}'>odl-ovsdb-hwvtepsouthbound-api</feature>
+    <bundle>mvn:org.opendaylight.controller/liblldp/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.neutron/model/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/model-bgp/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/lockmanager-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/idmanager-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/arputil-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/alivenessmonitor-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/fibmanager-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/itm-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/neutronvpn-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/dhcpservice-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/natservice-api/{{VERSION}}</bundle>
+  </feature>
+  <feature name='odl-vpnservice-impl' version='${project.version}' description='OpenDaylight :: vpnservice :: impl '>
+    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version="${ovsdb.version}">odl-ovsdb-southbound-impl-rest</feature>
+    <feature version='${ovsdb.version}'>odl-ovsdb-hwvtepsouthbound</feature>
+    <feature version='${project.version}'>odl-vpnservice-api</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-southbound</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
+    <bundle>mvn:commons-net/commons-net/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/lockmanager-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/idmanager-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/arputil-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-shell/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/fibmanager-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/fibmanager-shell/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/itm-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/neutronvpn-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/neutronvpn-shell/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/dhcpservice-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/elanmanager-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/elanmanager-impl/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/natservice-impl/{{VERSION}}</bundle>
+
+    <!--<bundle>mvn:org.opendaylight.vpnservice.third-party/org.apache.thriftlib/1.1.0-SNAPSHOT</bundle>-->
+    <bundle>wrap:mvn:org.apache.thrift/libthrift/0.9.1$overwrite=merge&amp;Bundle-Version=0.9.1&amp;Export-Package=*;-noimport:=true;version="0.9.1"</bundle>
+    <!--<bundle>wrap:mvn:javax.servlet/servlet-api/2.5</bundle>-->
+    <configfile finalname="lockmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/lockmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="idmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/idmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="idmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/idmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="bgpmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/bgpmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="mdsalutil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/mdsalutil-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="interfacemgr-impl-default-config.xml">mvn:org.opendaylight.vpnservice/interfacemgr-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="arputil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/arputil-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="alivenessmonitor-impl-default-config.xml">mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="vpnmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/vpnmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="fibmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/fibmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="itm-impl-default-config.xml">mvn:org.opendaylight.vpnservice/itm-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="neutronvpn-impl-default-config.xml">mvn:org.opendaylight.vpnservice/neutronvpn-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="dhcpservice-impl-default-config.xml">mvn:org.opendaylight.vpnservice/dhcpservice-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="elanmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/elanmanager-impl/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="natservice-impl-default-config.xml">mvn:org.opendaylight.vpnservice/natservice-impl/{{VERSION}}/xml/config</configfile>
+
+  </feature>
+  <feature name='odl-vpnservice-impl-rest' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: REST '>
+    <feature version="${project.version}">odl-vpnservice-impl</feature>
+    <feature version="${restconf.version}">odl-restconf</feature>
+  </feature>
+  <feature name='odl-vpnservice-impl-ui' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: UI'>
+    <feature version="${project.version}">odl-vpnservice-impl-rest</feature>
+    <feature version="${restconf.version}">odl-mdsal-apidocs</feature>
+    <feature version="${mdsal.version}">odl-mdsal-xsql</feature>
+  </feature>
+  <feature name='odl-vpnservice-core' version='${project.version}' description='OpenDaylight :: vpnservice :: core'>
+    <feature version="${neutron.version}">odl-neutron-service</feature>
+    <bundle>mvn:org.opendaylight.neutron/dummyprovider/{{VERSION}}</bundle>
+    <feature version="${project.version}">odl-vpnservice-impl-ui</feature>
+  </feature>
+  <feature name='odl-vpnservice-openstack' version='${project.version}' description='OpenDaylight :: vpnservice :: openstack'>
+    <feature version="${neutron.version}">odl-neutron-service</feature>
+    <bundle>mvn:org.opendaylight.neutron/dummyprovider/{{VERSION}}</bundle>
+    <feature version="${project.version}">odl-vpnservice-impl-rest</feature>
+  </feature>
+  <feature name='odl-vpnservice-intent' version='${project.version}' description='OpenDaylight :: vpnservice :: intent'>
+    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version='${nic.version}'>odl-nic-listeners</feature>
+    <bundle>mvn:org.opendaylight.vpnservice/vpnintent-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}</bundle>
+    <configfile finalname="vpnintent-impl-default-config.xml">mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}/xml/config</configfile>
+  </feature>
+  <feature name='odl-fcaps-framework' version='${project.version}' description='OpenDaylight :: fcapsframework'>
+    <bundle>mvn:org.opendaylight.vpnservice/fcaps-api/${fcaps.manager.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/alarmmanager/${fcaps.manager.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/countermanager/${fcaps.manager.version}</bundle>
+  </feature>
+  <feature name='odl-fcaps-application' version='${project.version}' description='OpenDaylight :: fcapsapp'>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-all</feature>
+    <bundle>mvn:org.opendaylight.vpnservice/fcapsapplication-jmxapi/${fcaps.app.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/fcapsapplication-impl/${fcaps.app.version}</bundle>
+    <configfile finalname="etc/opendaylight/karaf/73-fcaps-app.xml">mvn:org.opendaylight.vpnservice/fcapsapplication-impl/${fcaps.app.version}/xml/config    </configfile>
+  </feature>
+  </features>
similarity index 100%
rename from itm/pom.xml
rename to vpnservice/itm/pom.xml
diff --git a/vpnservice/pom.xml b/vpnservice/pom.xml
new file mode 100644 (file)
index 0000000..f24a35b
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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 INTERNAL
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>vpnservice</artifactId>
+  <version>0.3.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>commons/binding-parent</module>
+    <module>commons/config-parent</module>
+    <module>model-bgp</module>
+    <module>mdsalutil</module>
+    <module>lockmanager</module>
+    <module>idmanager</module>
+    <module>arputil</module>
+    <module>vpnmanager</module>
+    <module>interfacemgr</module>
+    <module>alivenessmonitor</module>
+    <module>elanmanager</module>
+    <module>fibmanager</module>
+    <module>bgpmanager</module>
+    <module>neutronvpn</module>
+    <module>dhcpservice</module>
+    <module>itm</module>
+    <module>natservice</module>
+    <module>distribution/karaf</module>
+    <module>features</module>
+    <module>vpnservice-artifacts</module>
+    <module>vpnintent</module>
+    <module>fcapsmanager</module>
+    <module>fcapsapplication</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/vpnservice.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/vpnservice.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/VPNService:Main</url>
+    <tag>HEAD</tag>
+  </scm>
+</project>
\ No newline at end of file