Merge "IDManager fixes for restart scenario"
authorVivek Srivastava <vivek.v.srivastava@ericsson.com>
Wed, 4 May 2016 12:16:34 +0000 (12:16 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 4 May 2016 12:16:34 +0000 (12:16 +0000)
200 files changed:
alivenessmonitor/alivenessmonitor-api/src/main/yang/aliveness-monitor.yang
alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AbstractAlivenessProtocolHandler.java
alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitor.java
alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerLLDP.java
dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPUtils.java
dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang [new file with mode: 0644]
dhcpservice/dhcpservice-impl/pom.xml
dhcpservice/dhcpservice-impl/src/main/config/default-config.xml
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java
dhcpservice/dhcpservice-impl/src/main/yang/dhcpservice-impl.yang
elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/utils/ElanL2GwCacheUtils.java
elanmanager/elanmanager-impl/pom.xml
elanmanager/elanmanager-impl/src/main/config/default-config.xml
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java
elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang
fcapsmanager/alarmmanager/pom.xml [new file with mode: 0644]
fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/Activator.java [new file with mode: 0644]
fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/AlarmNotificationListeners.java [new file with mode: 0644]
fcapsmanager/countermanager/pom.xml [new file with mode: 0644]
fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Activator.java [new file with mode: 0644]
fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/PMRegistrationListener.java [new file with mode: 0644]
fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Poller.java [new file with mode: 0644]
fcapsmanager/fcaps-api/pom.xml [new file with mode: 0644]
fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/Activator.java [new file with mode: 0644]
fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/AlarmServiceFacade.java [new file with mode: 0644]
fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/PMServiceFacade.java [new file with mode: 0644]
fcapsmanager/pom.xml [new file with mode: 0644]
features/pom.xml
features/src/main/features/features.xml
fibmanager/fibmanager-api/pom.xml
fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang [new file with mode: 0644]
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibConstants.java [new file with mode: 0644]
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManagerProvider.java
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibRpcServiceImpl.java [new file with mode: 0644]
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibUtil.java
fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/AlivenessMonitorUtils.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceManagerCommonUtils.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/AlivenessMonitorListener.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/HwVTEPTunnelsStateListener.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/TerminationPointStateListener.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/confighelpers/HwVTEPInterfaceConfigUpdateHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateRemoveHelper.java [new file with mode: 0644]
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/utilities/SouthboundUtils.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateUpdateHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateAddHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateRemoveHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceTopologyStateUpdateHelper.java
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/utilities/SouthboundUtils.java
interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/HwVTEPConfigurationTest.java
interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/InterfaceManagerTestUtil.java
interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/StateInterfaceTest.java
interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TopologyStateInterfaceTest.java
interfacemgr/interfacemgr-shell/src/main/java/org/opendaylight/vpnservice/interfacemgr/shell/IfmCLIUtil.java
itm/itm-api/src/main/java/org/opendaylight/vpnservice/itm/api/IITMProvider.java
itm/itm-api/src/main/java/org/opendaylight/vpnservice/itm/globals/ITMConstants.java
itm/itm-api/src/main/yang/itm-rpc.yang
itm/itm-api/src/main/yang/itm-state.yang
itm/itm-api/src/main/yang/itm.yang
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepCommandHelper.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/cli/TepShowState.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmExternalTunnelAddWorker.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmExternalTunnelDeleteWorker.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmInternalTunnelAddWorker.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmInternalTunnelDeleteWorker.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorIntervalWorker.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorToggleWorker.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmCache.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmProvider.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmUtils.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TransportZoneListener.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorChangeListener.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorIntervalListener.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/VtepConfigSchemaListener.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarm.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarmMBean.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/ItmTunnelEventListener.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/JMXAlarmAgent.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/rpc/ItmManagerRpcService.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/snd/ITMStatusMonitor.java
itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/snd/ITMStatusMonitorMBean.java
itm/itm-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/vpnservice/itm/impl/rev141210/ItmModule.java
itm/itm-impl/src/main/resources/OSGI-INF/blueprint/commands.xml [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java
natservice/natservice-api/pom.xml [new file with mode: 0644]
natservice/natservice-api/src/main/yang/odl-nat.yang [new file with mode: 0644]
natservice/natservice-impl/pom.xml [new file with mode: 0644]
natservice/natservice-impl/src/main/config/default-config.xml [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/DpnInVpnListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/EventDispatcher.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworkListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworksChangeListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalRoutersListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPHandler.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/IPAddress.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/InterfaceStateEventListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTEntryEvent.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTSwitchSelector.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptEventHandler.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptPacketInHandler.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptSwitchHA.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatConstants.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatNodeEventListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatServiceProvider.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatUtil.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterDpnChangeListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterPortsListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterToVpnListener.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SNATDefaultRouteProgrammer.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SessionAddress.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/VpnFloatingIpHandler.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModule.java [new file with mode: 0644]
natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModuleFactory.java [new file with mode: 0644]
natservice/natservice-impl/src/main/yang/natservice-impl.yang [new file with mode: 0644]
natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/ExternalNetworksChangeListenerTest.java [new file with mode: 0644]
natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/NaptManagerTest.java [new file with mode: 0644]
natservice/pom.xml [new file with mode: 0644]
neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/l2gw/utils/L2GatewayCacheUtils.java
neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java [new file with mode: 0644]
neutronvpn/neutronvpn-api/src/main/yang/neutronvpn.yang
neutronvpn/neutronvpn-impl/src/main/config/default-config.xml
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronNetworkChangeListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronPortChangeListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnManager.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnUtils.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java
neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang
pom.xml
vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang
vpnmanager/vpnmanager-api/src/main/yang/vpn-rpc.yang [new file with mode: 0644]
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/InterfaceStateChangeListener.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/RouterInterfaceListener.java [new file with mode: 0644]
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetRoutePacketInHandler.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnSubnetRouteHandler.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java
vpnmanager/vpnmanager-impl/src/test/java/org/opendaylight/vpnservice/test/VpnSubnetRouteHandlerTest.java

index 134288f6542e598977e164edf30d248c4c28f71e..3d521bfbb07ff452abfbddf1a430fe98e95fdd4a 100644 (file)
@@ -65,6 +65,17 @@ module aliveness-monitor {
         }
     }
 
+    rpc monitor-profile-get {
+            input {
+                container profile {
+                    uses monitor-profile-params;
+                }
+            }
+            output {
+                leaf profile-id { type uint32; }
+            }
+        }
+
     rpc monitor-start {
         input {
             container config {
index 9537a9f66147df651f4658b4e698ef3c8f4002fa..bfa2565462b1cd9721450401d7c96563784e4967 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -13,6 +13,7 @@ import java.util.concurrent.Future;
 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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetNodeconnectorIdFromInterfaceInputBuilder;
@@ -81,13 +82,22 @@ abstract class AbstractAlivenessProtocolHandler implements AlivenessProtocolHand
         return new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":")));
     }
 
-    protected byte[] getMacAddress(String interfaceName) {
-        InstanceIdentifier<NodeConnector> ncId = getNodeConnectorId(interfaceName);
-        if(ncId != null) {
-            String macAddress = inventoryReader.getMacAddress(ncId);
-            if(!Strings.isNullOrEmpty(macAddress)) {
-                return AlivenessMonitorUtil.parseMacAddress(macAddress);
-            }
+    protected org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceFromOperDS(String interfaceName){
+        InstanceIdentifier.InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
+                InstanceIdentifier.builder(InterfacesState.class).child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+                        new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceStateOptional = read(LogicalDatastoreType.OPERATIONAL, id);
+        if(interfaceStateOptional.isPresent()) {
+            return interfaceStateOptional.get();
+        }
+        return null;
+    }
+
+    protected byte[] getMacAddress(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState, String interfaceName) {
+        String macAddress = interfaceState.getPhysAddress().getValue();
+        if(!Strings.isNullOrEmpty(macAddress)) {
+            return AlivenessMonitorUtil.parseMacAddress(macAddress);
         }
         return null;
     }
index a00c7a64387fd4533b57f01978b6061e19e69a75..fb24cdaf64b3ced33c6c2695899819365ada8bc4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -52,6 +52,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStopInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorUnpauseInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitoringMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileGetInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileGetOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileGetOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629._interface.monitor.map.InterfaceMonitorEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629._interface.monitor.map.InterfaceMonitorEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629._interface.monitor.map.InterfaceMonitorEntryKey;
@@ -555,10 +558,13 @@ public class AlivenessMonitor implements AlivenessMonitorService, PacketProcessi
                 WriteTransaction tx = broker.newWriteOnlyTransaction();
 
                 tx.put(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId), monitoringInfo, CREATE_MISSING_PARENT);
+                LOG.debug("adding oper monitoring info {}", monitoringInfo);
 
                 tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitoringKey), monitoringState, CREATE_MISSING_PARENT);
+                LOG.debug("adding oper monitoring state {}", monitoringState);
 
                 tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorMapId(monitorId), mapEntry, CREATE_MISSING_PARENT);
+                LOG.debug("adding oper map entry {}", mapEntry);
 
                 Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
                     @Override
@@ -970,6 +976,36 @@ public class AlivenessMonitor implements AlivenessMonitorService, PacketProcessi
         return result;
     }
 
+
+    @Override
+    public Future<RpcResult<MonitorProfileGetOutput>> monitorProfileGet(MonitorProfileGetInput input){
+        LOG.debug("Monitor Profile Get operation for input profile- {}", input.getProfile());
+        RpcResultBuilder<MonitorProfileGetOutput> rpcResultBuilder;
+        try{
+            final Long profileId = getExistingProfileId(input);
+
+            MonitorProfileGetOutputBuilder output = new MonitorProfileGetOutputBuilder().setProfileId(profileId);
+            rpcResultBuilder = RpcResultBuilder.success();
+            rpcResultBuilder.withResult(output.build());
+        }catch(Exception e){
+            LOG.error("Retrieval of monitor profile ID for input {} failed due to {}" , input, e);
+            rpcResultBuilder = RpcResultBuilder.failed();
+        }
+        return Futures.immediateFuture(rpcResultBuilder.build());
+    }
+
+    private Long getExistingProfileId(MonitorProfileGetInput input){
+        org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.get.input.Profile profile = input.getProfile();
+        final Long failureThreshold = profile.getFailureThreshold();
+        final Long monitorInterval = profile.getMonitorInterval();
+        final Long monitorWindow = profile.getMonitorWindow();
+        final EtherTypes ethType = profile.getProtocolType();
+        LOG.debug("getExistingProfileId for profile : {}", input.getProfile());
+        String idKey = getUniqueProfileKey(failureThreshold, monitorInterval, monitorWindow, ethType);
+        LOG.debug("Obtained existing profile ID for profile : {}", input.getProfile());
+        return (Long.valueOf(getUniqueId(idKey)));
+    }
+
     private String getUniqueProfileKey(Long failureThreshold,Long monitorInterval,Long monitorWindow,EtherTypes ethType) {
         return new StringBuilder().append(failureThreshold).append(AlivenessMonitorConstants.SEPERATOR)
                                   .append(monitorInterval).append(AlivenessMonitorConstants.SEPERATOR)
index c1c045a474e65c94728dc7d48e57c6e7452316b7..1a4a42b77919d501a6384c20253ea8ec16c89772 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -23,6 +23,7 @@ import org.opendaylight.controller.liblldp.LLDPTLV;
 import org.opendaylight.controller.liblldp.LLDPTLV.TLVType;
 import org.opendaylight.controller.liblldp.Packet;
 import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.vpnservice.interfacemgr.globals.IfmConstants;
 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
 import org.opendaylight.vpnservice.mdsalutil.ActionType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
@@ -139,7 +140,8 @@ public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandl
         }
 
         //Get Mac Address for the source interface
-        byte[] sourceMac = getMacAddress(sourceInterface);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = getInterfaceFromOperDS(sourceInterface);
+        byte[] sourceMac = getMacAddress(interfaceState, sourceInterface);
         if(sourceMac == null) {
             LOG.error("Could not read mac address for the source interface {} from the Inventory. "
                     + "LLDP packet cannot be send.", sourceInterface);
@@ -150,26 +152,19 @@ public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandl
 
         long nodeId = -1, portNum = -1;
         try {
-            GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(sourceInterface).build();
-            Future<RpcResult<GetPortFromInterfaceOutput>> portOutput = interfaceService.getPortFromInterface(input);
-            RpcResult<GetPortFromInterfaceOutput> result = portOutput.get();
-            if(result.isSuccessful()) {
-                GetPortFromInterfaceOutput output = result.getResult();
-                nodeId = output.getDpid().longValue();
-                portNum = output.getPortno();
-            } else {
-                LOG.error("Could not retrieve port details for interface {}", sourceInterface);
-                return;
-            }
-        }catch(InterruptedException | ExecutionException e) {
-            LOG.error("Failed to retrieve interface service RPC Result ", e);
+            String lowerLayerIf = interfaceState.getLowerLayerIf().get(0);
+            NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
+            nodeId = Long.valueOf(getDpnFromNodeConnectorId(nodeConnectorId));
+            portNum = Long.valueOf(getPortNoFromNodeConnectorId(nodeConnectorId));
+        }catch(Exception e) {
+            LOG.error("Failed to retrieve node id and port number ", e);
             return;
         }
 
         Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, 0, sourceMac, sourceInterface);
 
         try {
-            List<ActionInfo> actions = getInterfaceActions(sourceInterface, portNum);
+            List<ActionInfo> actions = getInterfaceActions(interfaceState, portNum);
             if(actions.isEmpty()) {
                 LOG.error("No interface actions to send packet out over interface {}", sourceInterface);
                 return;
@@ -182,14 +177,27 @@ public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandl
         }
     }
 
-    private List<ActionInfo> getInterfaceActions(String interfaceName, long portNum) throws InterruptedException, ExecutionException {
+    public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
+        /*
+         * NodeConnectorId is of form 'openflow:dpnid:portnum'
+         */
+        String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
+        return split[1];
+    }
+
+    public static String getPortNoFromNodeConnectorId(NodeConnectorId portId) {
+        /*
+         * NodeConnectorId is of form 'openflow:dpnid:portnum'
+         */
+        String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
+        return split[2];
+    }
+    private List<ActionInfo> getInterfaceActions(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState,long portNum) throws InterruptedException, ExecutionException {
         Class<? extends InterfaceType> intfType;
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface interfaceInfo =
-                                                                                                     getInterfaceFromConfigDS(interfaceName);
-        if(interfaceInfo != null) {
-            intfType = interfaceInfo.getType();
+        if(interfaceState != null) {
+            intfType = interfaceState.getType();
         } else {
-            LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceName);
+            LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceState.getName());
             return Collections.emptyList();
         }
 
index 167e8077bf783fa9e4e1e28a0548f99931242ec0..99f7a7f6ecb56fdf479e5fc3f7033377c5ed735a 100644 (file)
@@ -86,4 +86,14 @@ public abstract class DHCPUtils {
         return result;
     }
 
+    public static String byteArrayToString(byte[] bytes) {
+        StringBuilder str = new StringBuilder();
+        for (byte b : bytes) {
+            str.append(Integer.toHexString((b >>> 4) & 0x0F));
+            str.append(Integer.toHexString(b & 0x0F));
+            str.append(":");
+        }
+        str.deleteCharAt(str.lastIndexOf(":"));
+        return str.toString();
+    }
 }
diff --git a/dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang b/dhcpservice/dhcpservice-api/src/main/yang/dhcp.yang
new file mode 100644 (file)
index 0000000..14b721c
--- /dev/null
@@ -0,0 +1,34 @@
+module vpnservice-dhcp {
+    namespace "urn:opendaylight:vpnservice:dhcp";
+    prefix "dhcp";
+
+    import ietf-inet-types {
+        prefix inet;
+        revision-date "2010-09-24";
+    }
+
+    revision "2016-04-28" {
+        description "It provides required datastore containers to handle DHCP requests
+                     coming from access or external tunnel ports";
+    }
+
+    container designated-switches-for-external-tunnels {
+        config true;
+        description "contains designated dataplane-node-identifier which handles DHCP requests for each external tunnel";
+        list designated-switch-for-tunnel {
+            key "tunnel-remote-ip-address elan-instance-name";
+            leaf tunnel-remote-ip-address {
+                description "remote end point ip address of external tunnel";
+                type inet:ip-address;
+            }
+            leaf elan-instance-name {
+                description "elan name indicates l2 network domain";
+                type string;
+            }
+            leaf dpId {
+                description "contains dataplane-node-identifier";
+                type int64;
+            }
+        }
+    }
+}
\ No newline at end of file
index cff44a5f53057800f367a9ff744883e538d758f4..a5a5ce67f0bdeaa16299a8f06389298a997957f9 100644 (file)
@@ -64,6 +64,21 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>interfacemgr-api</artifactId>
       <version>${vpnservices.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>elanmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>itm-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>hwvtepsouthbound-api</artifactId>
+      <version>${vpns.ovsdb.version}</version>
+    </dependency>
    </dependencies>
 
 </project>
index fe6008a4a2eb2258ca657388182d2e075625a286..988288d6fcc9d0823ef3acd1e143eb9f55c15545 100644 (file)
@@ -12,6 +12,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <capability>urn:opendaylight:params:xml:ns:yang:dhcpservice:impl?module=dhcpservice-impl&amp;revision=2015-07-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:mdsalutil:api?module=odl-mdsalutil&amp;revision=2015-04-10</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:config:distributed-entity-ownership-service?module=distributed-entity-ownership-service&amp;revision=2015-08-10</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:neutronvpn:api?module=neutronvpn-api&amp;revision=2015-08-12</capability>
   </required-capabilities>
   <configuration>
@@ -41,6 +42,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <type xmlns:neutronvpn="urn:opendaylight:params:xml:ns:yang:neutronvpn:api">neutronvpn:neutronvpn-api</type>
             <name>neutronvpn</name>
           </neutronvpn>
+          <entity-ownership-service>
+            <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
+            <name>entity-ownership-service</name>
+          </entity-ownership-service>
         </module>
       </modules>
     </data>
index 2d187055ac88bcdb7d548941eb7e24dab6065c6e..2fa8448a9740d8f717b461961cd96551d43b0b6e 100644 (file)
@@ -8,17 +8,15 @@
 package org.opendaylight.vpnservice.dhcpservice;
 
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
-
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
 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.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java
new file mode 100644 (file)
index 0000000..27de14d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+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.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerBase<DesignatedSwitchForTunnel, DhcpDesignatedDpnListener> implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpDesignatedDpnListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private DataBroker broker;
+
+    public DhcpDesignatedDpnListener(final DhcpExternalTunnelManager dhcpExternalTunnelManager, final DataBroker broker) {
+        super(DesignatedSwitchForTunnel.class, DhcpDesignatedDpnListener.class);
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.broker = broker;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DhcpDesignatedDpnListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.debug("DhcpDesignatedDpnListener Listener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel del) {
+        dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(del.getDpId()), del.getTunnelRemoteIpAddress(), del.getElanInstanceName());
+        dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(del.getElanInstanceName(), del.getTunnelRemoteIpAddress(), DhcpServiceUtils.getListOfDpns(broker));
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel original,
+            DesignatedSwitchForTunnel update) {
+        BigInteger designatedDpnId = BigInteger.valueOf(update.getDpId());
+        IpAddress tunnelRemoteIpAddress = update.getTunnelRemoteIpAddress();
+        String elanInstanceName = update.getElanInstanceName();
+        dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()), original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
+        dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+        if (elanDpns == null || elanDpns.isEmpty()) {
+            dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel add) {
+        BigInteger designatedDpnId = BigInteger.valueOf(add.getDpId());
+        IpAddress tunnelRemoteIpAddress = add.getTunnelRemoteIpAddress();
+        String elanInstanceName = add.getElanInstanceName();
+        dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+        if (elanDpns == null || elanDpns.isEmpty()) {
+            dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<DesignatedSwitchForTunnel> getWildCardPath() {
+        return InstanceIdentifier.create(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpDesignatedDpnListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
+    }
+}
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java
new file mode 100644 (file)
index 0000000..79e3482
--- /dev/null
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+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.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+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.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+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.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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+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.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.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class DhcpExternalTunnelManager {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpExternalTunnelManager.class);
+    public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+    private static final FutureCallback<Void> DEFAULT_CALLBACK =
+            new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(Void result) {
+                    logger.debug("Success in Datastore write operation");
+                }
+                @Override
+                public void onFailure(Throwable error) {
+                    logger.error("Error in Datastore write operation", error);
+                };
+            };
+    private final DataBroker broker;
+    private IMdsalApiManager mdsalUtil;
+
+    private ConcurrentMap<BigInteger, List<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache = new ConcurrentHashMap<BigInteger, List<Pair<IpAddress, String>>>();
+    private ConcurrentMap<Pair<IpAddress, String>, Set<String>> tunnelIpElanNameToVmMacCache = new ConcurrentHashMap<Pair<IpAddress, String>, Set<String>>();
+    private ConcurrentMap<Pair<BigInteger, String>, Port> vniMacAddressToPortCache = new ConcurrentHashMap<Pair<BigInteger, String>, Port>();
+    private ItmRpcService itmRpcService;
+    private EntityOwnershipService entityOwnershipService;
+
+    public DhcpExternalTunnelManager(DataBroker broker, IMdsalApiManager mdsalUtil, ItmRpcService itmRpcService, EntityOwnershipService entityOwnershipService) {
+        this.broker = broker;
+        this.mdsalUtil = mdsalUtil;
+        this.itmRpcService = itmRpcService;
+        this.entityOwnershipService = entityOwnershipService;
+        initilizeCaches();
+    }
+
+    private void initilizeCaches() {
+        logger.trace("Loading designatedDpnsToTunnelIpElanNameCache");
+        InstanceIdentifier<DesignatedSwitchesForExternalTunnels> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).build();
+        Optional<DesignatedSwitchesForExternalTunnels> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+        if (designatedSwitchForTunnelOptional.isPresent()) {
+            List<DesignatedSwitchForTunnel> list = designatedSwitchForTunnelOptional.get().getDesignatedSwitchForTunnel();
+            for (DesignatedSwitchForTunnel designatedSwitchForTunnel : list) {
+                List<Pair<IpAddress, String>> listOfTunnelIpElanNamePair = designatedDpnsToTunnelIpElanNameCache.get(designatedSwitchForTunnel.getDpId());
+                if (listOfTunnelIpElanNamePair == null) {
+                    listOfTunnelIpElanNamePair = new LinkedList<Pair<IpAddress, String>>();
+                }
+                Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(designatedSwitchForTunnel.getTunnelRemoteIpAddress(), designatedSwitchForTunnel.getElanInstanceName());
+                listOfTunnelIpElanNamePair.add(tunnelIpElanNamePair);
+                designatedDpnsToTunnelIpElanNameCache.put(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()), listOfTunnelIpElanNamePair);
+            }
+        }
+        logger.trace("Loading vniMacAddressToPortCache");
+        InstanceIdentifier<Ports> inst = InstanceIdentifier.builder(Neutron.class).child(Ports.class).build();
+        Optional<Ports> optionalPorts = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+        if (optionalPorts.isPresent()) {
+            List<Port> list = optionalPorts.get().getPort();
+            for (Port port : list) {
+                if(NeutronUtils.isPortVnicTypeNormal(port)) {
+                    continue;
+                }
+                String macAddress = port.getMacAddress();
+                Uuid networkId = port.getNetworkId();
+                String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+                if (segmentationId == null) {
+                    return;
+                }
+                updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
+            }
+        }
+
+    }
+
+
+    public BigInteger designateDpnId(IpAddress tunnelIp,
+            String elanInstanceName, List<BigInteger> dpns) {
+        BigInteger designatedDpnId = readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+        if (designatedDpnId != null && !designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            logger.trace("Dpn {} already designated for tunnelIp - elan : {} - {}", designatedDpnId, tunnelIp, elanInstanceName);
+            return designatedDpnId;
+        }
+        return chooseDpn(tunnelIp, elanInstanceName, dpns);
+    }
+
+    public void installDhcpFlowsForVms(IpAddress tunnelIp, String elanInstanceName, List<BigInteger> dpns,
+            BigInteger designatedDpnId, String vmMacAddress) {
+        installDhcpEntries(designatedDpnId, vmMacAddress, entityOwnershipService);
+        dpns.remove(designatedDpnId);
+        for (BigInteger dpn : dpns) {
+            installDhcpDropAction(dpn, vmMacAddress, entityOwnershipService);
+        }
+        updateLocalCache(tunnelIp, elanInstanceName, vmMacAddress);
+    }
+
+    public void installDhcpFlowsForVms(IpAddress tunnelIp,
+            String elanInstanceName, BigInteger designatedDpnId, Set<String> listVmMacAddress) {
+        for (String vmMacAddress : listVmMacAddress) {
+            installDhcpEntries(designatedDpnId, vmMacAddress);
+        }
+    }
+
+    public void unInstallDhcpFlowsForVms(String elanInstanceName, List<BigInteger> dpns, String vmMacAddress) {
+        for (BigInteger dpn : dpns) {
+            unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
+        }
+        removeFromLocalCache(elanInstanceName, vmMacAddress);
+    }
+
+    public BigInteger readDesignatedSwitchesForExternalTunnel(IpAddress tunnelIp, String elanInstanceName) {
+        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp)).build();
+        Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+        if (designatedSwitchForTunnelOptional.isPresent()) {
+            return BigInteger.valueOf(designatedSwitchForTunnelOptional.get().getDpId());
+        }
+        return null;
+    }
+
+    public void writeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
+        DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
+        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
+        DesignatedSwitchForTunnel designatedSwitchForTunnel = new DesignatedSwitchForTunnelBuilder().setDpId(dpnId.longValue()).setElanInstanceName(elanInstanceName).setTunnelRemoteIpAddress(tunnelIp).setKey(designatedSwitchForTunnelKey).build();
+        logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
+        MDSALDataStoreUtils.asyncUpdate(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, designatedSwitchForTunnel, DEFAULT_CALLBACK);
+    }
+
+    public void removeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
+        DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
+        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
+        logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
+        MDSALDataStoreUtils.asyncRemove(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, DEFAULT_CALLBACK);
+    }
+
+    public void installDhcpDropActionOnDpn(BigInteger dpId) {
+        List<String> vmMacs = getAllVmMacs();
+        logger.trace("Installing drop actions to this new DPN {} VMs {}", dpId, vmMacs);
+        for (String vmMacAddress : vmMacs) {
+            installDhcpDropAction(dpId, vmMacAddress);
+        }
+    }
+
+    private List<String> getAllVmMacs() {
+        List<String> vmMacs = new LinkedList<String>();
+        Collection<Set<String>> listOfVmMacs = tunnelIpElanNameToVmMacCache.values();
+        for (Set<String> list : listOfVmMacs) {
+            vmMacs.addAll(list);
+        }
+        return vmMacs;
+    }
+
+    public void updateLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
+        Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        List<Pair<IpAddress, String>> tunnelIpElanNameList;
+        tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
+        if (tunnelIpElanNameList == null) {
+            tunnelIpElanNameList = new LinkedList<Pair<IpAddress, String>>();
+        }
+        tunnelIpElanNameList.add(tunnelIpElanName);
+        designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
+    }
+
+    private void updateLocalCache(IpAddress tunnelIp, String elanInstanceName, String vmMacAddress) {
+        Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        Set<String> listExistingVmMacAddress;
+        listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanName);
+        if (listExistingVmMacAddress == null) {
+            listExistingVmMacAddress = new HashSet<String>();
+        }
+        listExistingVmMacAddress.add(vmMacAddress);
+        tunnelIpElanNameToVmMacCache.put(tunnelIpElanName, listExistingVmMacAddress);
+    }
+
+    public void handleDesignatedDpnDown(BigInteger dpnId, List<BigInteger> listOfDpns) {
+        logger.trace("In handleDesignatedDpnDown dpnId {}, listOfDpns {}", dpnId, listOfDpns);
+        try {
+            List<Pair<IpAddress, String>> listOfTunnelIpElanNamePairs = designatedDpnsToTunnelIpElanNameCache.get(dpnId);
+            if (!dpnId.equals(DHCPMConstants.INVALID_DPID)) {
+                List<String> listOfVms = getAllVmMacs();
+                for (String vmMacAddress : listOfVms) {
+                    unInstallDhcpEntries(dpnId, vmMacAddress);
+                }
+            }
+            if (listOfTunnelIpElanNamePairs == null || listOfTunnelIpElanNamePairs.isEmpty()) {
+                logger.trace("No tunnelIpElanName to handle for dpn {}. Returning", dpnId);
+                return;
+            }
+            for (Pair<IpAddress, String> pair : listOfTunnelIpElanNamePairs) {
+                updateCacheAndInstallNewFlows(dpnId, listOfDpns, pair);
+            }
+        } catch (Exception e) {
+            logger.error("Error in handleDesignatedDpnDown {}", e);
+        }
+    }
+
+    public void updateCacheAndInstallNewFlows(BigInteger dpnId,
+            List<BigInteger> listOfDpns, Pair<IpAddress, String> pair)
+            throws ExecutionException {
+        BigInteger newDesignatedDpn = chooseDpn(pair.getLeft(), pair.getRight(), listOfDpns);
+        if (newDesignatedDpn.equals(DHCPMConstants.INVALID_DPID)) {
+            return;
+        }
+        Set<String> listVmMacs = tunnelIpElanNameToVmMacCache.get(pair);
+        if (listVmMacs != null && !listVmMacs.isEmpty()) {
+            installDhcpFlowsForVms(pair.getLeft(), pair.getRight(), newDesignatedDpn, listVmMacs);
+        }
+    }
+
+    private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId) {
+        try {
+            Set<String> listVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
+            if (listVmMacAddress == null || listVmMacAddress.isEmpty()) {
+                return;
+            }
+            for (String vmMacAddress : listVmMacAddress) {
+                installDhcpDropAction(dpnId, vmMacAddress);
+            }
+        } catch (Exception e) {
+            logger.error("Error in uninstallExistingFlows {}", e);
+        }
+    }
+
+    /**
+     * Choose a dpn among the list of elanDpns such that it has lowest count of being the designated dpn.
+     * @param tunnelIp
+     * @param elanInstanceName
+     * @param dpns
+     * @return
+     */
+    private BigInteger chooseDpn(IpAddress tunnelIp, String elanInstanceName,
+            List<BigInteger> dpns) {
+        BigInteger designatedDpnId = DHCPMConstants.INVALID_DPID;
+        if (dpns != null && dpns.size() != 0) {
+            List<BigInteger> candidateDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+            candidateDpns.retainAll(dpns);
+            logger.trace("Choosing new dpn for tunnelIp {}, elanInstanceName {}, among elanDpns {}", tunnelIp, elanInstanceName, candidateDpns);
+            boolean elanDpnAvailableFlag = true;
+            if (candidateDpns == null || candidateDpns.isEmpty()) {
+                candidateDpns = dpns;
+                elanDpnAvailableFlag = false;
+            }
+            int size = 0;
+            L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+            if (device == null) {
+                logger.trace("Could not find any device for elanInstanceName {} and tunnelIp {}", elanInstanceName, tunnelIp);
+                handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
+                return designatedDpnId;
+            }
+            for (BigInteger dpn : candidateDpns) {
+                String hwvtepNodeId = device.getHwvtepNodeId();
+                if (!elanDpnAvailableFlag) {
+                    if (!isTunnelConfigured(dpn, hwvtepNodeId)) {
+                        logger.trace("Tunnel is not configured on dpn {} to TOR {}", dpn, hwvtepNodeId);
+                        continue;
+                    }
+                } else if (!isTunnelUp(hwvtepNodeId, dpn)) {
+                    logger.trace("Tunnel is not up between dpn {} and TOR {}", dpn, hwvtepNodeId);
+                    continue;
+                }
+                List<Pair<IpAddress, String>> tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(dpn);
+                if (tunnelIpElanNameList == null) {
+                    designatedDpnId = dpn;
+                    break;
+                }
+                if (size == 0 || tunnelIpElanNameList.size() < size) {
+                    size = tunnelIpElanNameList.size();
+                    designatedDpnId = dpn;
+                }
+            }
+            writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+            return designatedDpnId;
+        }
+        handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
+        return designatedDpnId;
+    }
+
+    private void handleUnableToDesignateDpn(IpAddress tunnelIp, String elanInstanceName) {
+        writeDesignatedSwitchForExternalTunnel(DHCPMConstants.INVALID_DPID, tunnelIp, elanInstanceName);
+    }
+
+    public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
+        DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
+    }
+
+    public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+        final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    installDhcpEntries(dpnId, vmMacAddress);
+                } else {
+                    logger.trace("Exiting installDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Error while fetching checkNodeEntityOwner", error);
+            }
+        });
+    }
+
+    public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress) {
+        DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
+    }
+
+    public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+        final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    unInstallDhcpEntries(dpnId, vmMacAddress);
+                } else {
+                    logger.trace("Exiting unInstallDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Error while fetching checkNodeEntityOwner", error);
+            }
+        });
+    }
+
+    public void installDhcpDropAction(BigInteger dpn, String vmMacAddress) {
+        DhcpServiceUtils.setupDhcpDropAction(dpn, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
+    }
+
+    public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+        final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    installDhcpDropAction(dpnId, vmMacAddress);
+                } else {
+                    logger.trace("Exiting installDhcpDropAction since this cluster node is not the owner for dpn {}", nodeId);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Error while fetching checkNodeEntityOwner", error);
+            }
+        });
+    }
+
+    public void handleTunnelStateDown(IpAddress tunnelIp, BigInteger interfaceDpn) {
+        logger.trace("In handleTunnelStateDown tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
+        if (interfaceDpn == null) {
+            return;
+        }
+        try {
+            List<Pair<IpAddress, String>> tunnelElanPairList = designatedDpnsToTunnelIpElanNameCache.get(interfaceDpn);
+            if (tunnelElanPairList == null || tunnelElanPairList.isEmpty()) {
+                return;
+            }
+            for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairList) {
+                IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
+                if (tunnelIpInDpn.equals(tunnelIp)) {
+                    List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
+                    dpns.remove(interfaceDpn);
+                    changeExistingFlowToDrop(tunnelElanPair, interfaceDpn);
+                    updateCacheAndInstallNewFlows(interfaceDpn, dpns, tunnelElanPair);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Error in handleTunnelStateDown {}", e.getMessage());
+            logger.trace("Exception details {}", e);
+        }
+    }
+
+    private void removeFromLocalCache(String elanInstanceName, String vmMacAddress) {
+        Set<Pair<IpAddress, String>> tunnelIpElanNameKeySet = tunnelIpElanNameToVmMacCache.keySet();
+        for (Pair<IpAddress, String> pair : tunnelIpElanNameKeySet) {
+            if (pair.getRight().trim().equalsIgnoreCase(elanInstanceName.trim())) {
+                Set<String> listExistingVmMacAddress;
+                listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
+                if (listExistingVmMacAddress == null || listExistingVmMacAddress.isEmpty()) {
+                    continue;
+                }
+                listExistingVmMacAddress.remove(vmMacAddress);
+                if (listExistingVmMacAddress.size() > 0) {
+                    tunnelIpElanNameToVmMacCache.put(pair, listExistingVmMacAddress);
+                    return;
+                }
+                tunnelIpElanNameToVmMacCache.remove(pair);
+            }
+        }
+    }
+
+    public void removeFromLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
+        Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        List<Pair<IpAddress, String>> tunnelIpElanNameList;
+        tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
+        if (tunnelIpElanNameList != null) {
+            tunnelIpElanNameList.remove(tunnelIpElanName);
+            if (tunnelIpElanNameList.size() != 0) {
+                designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
+            } else {
+                designatedDpnsToTunnelIpElanNameCache.remove(designatedDpnId);
+            }
+        }
+    }
+
+    public void updateVniMacToPortCache(BigInteger vni, String macAddress, Port port) {
+        if (macAddress == null) {
+            return;
+        }
+        Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+        logger.trace("Updating vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, port);
+        vniMacAddressToPortCache.put(vniMacAddressPair, port);
+    }
+
+    public void removeVniMacToPortCache(BigInteger vni, String macAddress) {
+        if (macAddress == null) {
+            return;
+        }
+        Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+        vniMacAddressToPortCache.remove(vniMacAddressPair);
+    }
+
+    public Port readVniMacToPortCache(BigInteger vni, String macAddress) {
+        if (macAddress == null) {
+            return null;
+        }
+        Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+        logger.trace("Reading vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, vniMacAddressToPortCache.get(vniMacAddressPair));
+        return vniMacAddressToPortCache.get(vniMacAddressPair);
+    }
+
+    public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+        String tunnelInterfaceName = null;
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+        try {
+            Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
+                    .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
+                            .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
+
+            RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
+            if (rpcResult.isSuccessful()) {
+                tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
+                logger.debug("Tunnel interface name: {}", tunnelInterfaceName);
+            } else {
+                logger.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}",
+                        rpcResult.getErrors());
+            }
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            logger.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}: {} ",
+                    sourceNode, dstNode, e);
+        }
+        return tunnelInterfaceName;
+    }
+
+    public static Optional<Node> getNode(DataBroker dataBroker, String physicalSwitchNodeId) {
+        InstanceIdentifier<Node> psNodeId = HwvtepSouthboundUtils
+                .createInstanceIdentifier(new NodeId(physicalSwitchNodeId));
+        Optional<Node> physicalSwitchOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, psNodeId, dataBroker);
+        return physicalSwitchOptional;
+    }
+
+    public RemoteMcastMacs createRemoteMcastMac(Node dstDevice, String logicalSwitchName, IpAddress internalTunnelIp) {
+        List<LocatorSet> locators = new ArrayList<>();
+        for (TerminationPoint tp : dstDevice.getTerminationPoint()) {
+            HwvtepPhysicalLocatorAugmentation aug = tp.getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
+            if (internalTunnelIp.getIpv4Address().equals(aug.getDstIp().getIpv4Address())) {
+                HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
+                        HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(dstDevice.getNodeId(), aug));
+                locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
+            }
+        }
+        HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(dstDevice.getNodeId(), new HwvtepNodeName(logicalSwitchName)));
+
+        RemoteMcastMacs remoteUcastMacs = new RemoteMcastMacsBuilder()
+                .setMacEntryKey(new MacAddress(UNKNOWN_DMAC))
+                .setLogicalSwitchRef(lsRef).setLocatorSet(locators).build();
+        return remoteUcastMacs;
+    }
+
+    private WriteTransaction putRemoteMcastMac(WriteTransaction transaction, String elanName, L2GatewayDevice device, IpAddress internalTunnelIp) {
+        Optional<Node> optionalNode = getNode(broker, device.getHwvtepNodeId());
+        Node dstNode = optionalNode.get();
+        if (dstNode == null) {
+            logger.debug("could not get device node {} ", device.getHwvtepNodeId());
+            return null;
+        }
+        RemoteMcastMacs macs = createRemoteMcastMac(dstNode, elanName, internalTunnelIp);
+        HwvtepUtils.putRemoteMcastMac(transaction, dstNode.getNodeId(), macs);
+        return transaction;
+    }
+
+    public void installRemoteMcastMac(final BigInteger designatedDpnId, final IpAddress tunnelIp, final String elanInstanceName) {
+        if (designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            return;
+        }
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    logger.info("Installing remote McastMac");
+                    L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+                    String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
+                    IpAddress internalTunnelIp = null;
+                    if (tunnelInterfaceName != null) {
+                        Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+                        if (tunnelInterface == null) {
+                            logger.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
+                            return;
+                        }
+                        internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
+                        WriteTransaction transaction = broker.newWriteOnlyTransaction();
+                        putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
+                        if (transaction != null) {
+                            transaction.submit();
+                        }
+                    }
+                } else {
+                      logger.info("Installing remote McastMac is not executed for this node.");
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Failed to install remote McastMac", error);
+            }
+        });
+    }
+
+    private L2GatewayDevice getDeviceFromTunnelIp(String elanInstanceName, IpAddress tunnelIp) {
+        ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
+        for (L2GatewayDevice device : devices.values()) {
+            if (device.getTunnelIp().equals(tunnelIp)) {
+                return device;
+            }
+        }
+        return null;
+    }
+
+    private boolean isTunnelUp(String nodeName, BigInteger dpn) {
+        boolean isTunnelUp = false;
+        String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), nodeName);
+        if (tunnelInterfaceName == null) {
+            logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+            return isTunnelUp;
+        }
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromOperationalDS(tunnelInterfaceName, broker);
+        if (tunnelInterface == null) {
+            logger.debug("Interface {} is not present in interface state", tunnelInterfaceName);
+            return isTunnelUp;
+        }
+        isTunnelUp = (tunnelInterface.getOperStatus() == OperStatus.Up) ? true :false;
+        return isTunnelUp;
+    }
+
+    public void handleTunnelStateUp(IpAddress tunnelIp, BigInteger interfaceDpn) {
+        logger.trace("In handleTunnelStateUp tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
+        try {
+            List<Pair<IpAddress, String>> tunnelIpElanPair = designatedDpnsToTunnelIpElanNameCache.get(DHCPMConstants.INVALID_DPID);
+            List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
+            if (tunnelIpElanPair == null || tunnelIpElanPair.isEmpty()) {
+                return;
+            }
+            for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
+                if (tunnelIp.equals(pair.getLeft())) {
+                    designateDpnId(tunnelIp, pair.getRight(), dpns);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Error in handleTunnelStateUp {}", e.getMessage());
+            logger.trace("Exception details {}", e);
+        }
+    }
+
+    private boolean isTunnelConfigured(BigInteger dpn, String hwVtepNodeId) {
+        String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), hwVtepNodeId);
+        if (tunnelInterfaceName == null) {
+            return false;
+        }
+        Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+        if (tunnelInterface == null) {
+            logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+            return false;
+        }
+        return true;
+    }
+
+    public void unInstallDhcpFlowsForVms(String elanInstanceName, IpAddress tunnelIp, List<BigInteger> dpns) {
+        Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+        Set<String> vmMacs = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
+        logger.trace("In unInstallFlowsForVms elanInstanceName {}, tunnelIp {}, dpns {}, vmMacs {}", elanInstanceName, tunnelIp, dpns, vmMacs);
+        if (vmMacs == null) {
+            return;
+        }
+        for (String vmMacAddress : vmMacs) {
+            for (BigInteger dpn : dpns) {
+                unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
+            }
+        }
+        tunnelIpElanNameToVmMacCache.remove(tunnelIpElanNamePair);
+    }
+}
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceConfigListener.java
new file mode 100644 (file)
index 0000000..1bb1dd7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.dhcpservice;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+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.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpInterfaceConfigListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceConfigListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DataBroker dataBroker;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+
+    public DhcpInterfaceConfigListener(DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        super(Interface.class);
+        this.dataBroker = dataBroker;
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        registerListener();
+    }
+
+    private void registerListener() {
+        try {
+            listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), DhcpInterfaceConfigListener.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e);
+            throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpInterfaceConfigListener Closed");
+    }
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
+        IfTunnel tunnelInterface = del.getAugmentation(IfTunnel.class);
+        if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+            IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+            ParentRefs interfce = del.getAugmentation(ParentRefs.class);
+            if (interfce != null) {
+                dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, interfce.getDatapathNodeIdentifier());
+            }
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+        // Handled in update () DhcpInterfaceEventListener
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
+        // Handled in add() DhcpInterfaceEventListener
+    }
+}
\ No newline at end of file
index 5cc245653a097bdf6d4f4ac3b5f59344a06fd34c..3550156fcca16bff3b527f6b81ceb3e7af86e2fa 100644 (file)
@@ -10,21 +10,27 @@ package org.opendaylight.vpnservice.dhcpservice;
 import java.math.BigInteger;
 import java.util.List;
 
+import org.apache.commons.lang3.tuple.ImmutablePair;
 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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+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.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 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.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -40,26 +46,30 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private DataBroker dataBroker;
     private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
+        @Override
         public void onSuccess(Void result) {
             logger.debug("Success in Datastore write operation");
         }
 
+        @Override
         public void onFailure(Throwable error) {
             logger.error("Error in Datastore write operation", error);
         }
     };
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
 
-    public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker) {
+    public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
         super(Interface.class);
         this.dhcpManager = dhcpManager;
         this.dataBroker = dataBroker;
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         registerListener();
     }
 
     private void registerListener() {
         try {
             listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
-                    getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE);
+                getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE);
         } catch (final Exception e) {
             logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e);
             throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e);
@@ -85,29 +95,100 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
 
 
     @Override
-    protected void remove(InstanceIdentifier<Interface> identifier,
-            Interface del) {
-        String interfaceName = del.getName();
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
         List<String> ofportIds = del.getLowerLayerIf();
+        if (ofportIds == null || ofportIds.isEmpty()) {
+            return;
+        }
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                DhcpServiceUtils.getInterfaceFromConfigDS(del.getName(), dataBroker);
+        if (iface != null) {
+            IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+            if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+                IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+                List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+                if (dpns.contains(dpId)) {
+                    dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId);
+                }
+                return;
+            }
+        }
+        String interfaceName = del.getName();
         logger.trace("Received remove DCN for interface {} dpId {}", interfaceName, dpId);
         unInstallDhcpEntries(interfaceName, dpId);
+        dhcpManager.removeInterfaceCache(interfaceName);
     }
 
     @Override
     protected void update(InstanceIdentifier<Interface> identifier,
             Interface original, Interface update) {
+        List<String> ofportIds = update.getLowerLayerIf();
+        if (ofportIds == null || ofportIds.isEmpty()) {
+            return;
+        }
+        NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
+        BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+        String interfaceName = update.getName();
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                DhcpServiceUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
+        if (iface == null) {
+            logger.trace("Interface {} is not present in the config DS", interfaceName);
+            return;
+        }
+        if (update.getType() == null) {
+            logger.trace("Interface type for interface {} is null", interfaceName);
+            return;
+        }
+        if ((original.getOperStatus().getIntValue() ^ update.getOperStatus().getIntValue()) == 0) {
+            logger.trace("Interface operstatus {} is same", update.getOperStatus());
+            return;
+        }
+        if (Tunnel.class.equals(update.getType())) {
+            IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+            if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+                IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+                List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+                if (dpns.contains(dpId)) {
+                    if (update.getOperStatus() == OperStatus.Down) {
+                        dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId);
+                    } else if (update.getOperStatus() == OperStatus.Up) {
+                        dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId);
+                    }
+                }
+            }
+            return;
+        }
     }
 
     @Override
     protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
         String interfaceName = add.getName();
         List<String> ofportIds = add.getLowerLayerIf();
+        if (ofportIds == null || ofportIds.isEmpty()) {
+            return;
+        }
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         logger.trace("Received add DCN for interface {}, dpid {}", interfaceName, dpId);
-        installDhcpEntries(interfaceName, dpId);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                DhcpServiceUtils.getInterfaceFromConfigDS(add.getName(), dataBroker);
+        if (iface != null) {
+            IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+            if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+                IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+                List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+                if (dpns.contains(dpId)) {
+                    dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId);
+                }
+                return;
+            }
+        }
+        if (!dpId.equals(DHCPMConstants.INVALID_DPID)) {
+            installDhcpEntries(interfaceName, dpId);
+            dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair<BigInteger, String>(dpId, add.getPhysAddress().getValue()));
+        }
     }
 
     private String getNeutronMacAddress(String interfaceName) {
@@ -116,7 +197,6 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
             logger.trace("Port found in neutron. Interface Name {}, port {}", interfaceName, port);
             return port.getMacAddress();
         }
-        logger.trace("Port not found in neutron. Interface Name {}", interfaceName);
         return null;
     }
 
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java
new file mode 100644 (file)
index 0000000..7118c72
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+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.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.L2gateways;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gateway;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gatewayKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeListenerBase<L2gatewayConnection,DhcpL2GatewayConnectionListener> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceEventListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private final DataBroker dataBroker;
+
+    public DhcpL2GatewayConnectionListener(DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        super(L2gatewayConnection.class, DhcpL2GatewayConnectionListener.class);
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.dataBroker = dataBroker;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<L2gatewayConnection> identifier,
+            L2gatewayConnection del) {
+        Uuid gatewayId = del.getL2gatewayId();
+        InstanceIdentifier<L2gateway> inst = InstanceIdentifier.create(Neutron.class).child(L2gateways.class)
+                .child(L2gateway.class, new L2gatewayKey(gatewayId));
+        Optional<L2gateway> l2Gateway = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, inst);
+        if (!l2Gateway.isPresent()) {
+            logger.trace("L2Gw not present id {}", gatewayId);
+            return;
+        }
+        Uuid networkUuid = del.getNetworkId();
+        boolean isLastConnection = isLastGatewayConnection(networkUuid);
+        if (!isLastConnection) {
+            logger.trace("Not the last L2GatewayConnection. Not removing flows.");
+            return;
+        }
+        List<Devices> l2Devices = l2Gateway.get().getDevices();
+        for (Devices l2Device : l2Devices) {
+            String l2DeviceName = l2Device.getDeviceName();
+            L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+            IpAddress tunnelIp = l2GatewayDevice.getTunnelIp();
+            BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, del.getNetworkId().getValue());
+            if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+                logger.error("Could not find desiganted DPN ID");
+                return;
+            }
+            dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, del.getNetworkId().getValue());
+        }
+    }
+
+    private boolean isLastGatewayConnection(Uuid networkUuid) {
+        boolean isLastConnection = true;
+        InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
+        Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
+        List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
+        for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
+            if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
+                isLastConnection = false;
+                break;
+            }
+        }
+        return isLastConnection;
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<L2gatewayConnection> identifier,
+            L2gatewayConnection original, L2gatewayConnection update) {
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<L2gatewayConnection> identifier,
+            L2gatewayConnection add) {
+
+    }
+
+    @Override
+    protected InstanceIdentifier<L2gatewayConnection> getWildCardPath() {
+        return InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class)
+                .child(L2gatewayConnection.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpL2GatewayConnectionListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpL2GatewayConnection listener Closed");
+    }
+}
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java
new file mode 100644 (file)
index 0000000..fef7085
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+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.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+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.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpLogicalSwitchListener extends AbstractDataChangeListener<LogicalSwitches> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpLogicalSwitchListener.class);
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DataBroker dataBroker;
+
+    public DhcpLogicalSwitchListener(DhcpExternalTunnelManager dhcpManager, DataBroker dataBroker) {
+        super(LogicalSwitches.class);
+        this.dhcpExternalTunnelManager = dhcpManager;
+        this.dataBroker = dataBroker;
+        registerListener();
+    }
+
+    private void registerListener() {
+        try {
+            listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), DhcpLogicalSwitchListener.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            logger.error("DhcpLogicalSwitchListener DataChange listener registration fail!", e);
+            throw new IllegalStateException("DhcpLogicalSwitchListener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<LogicalSwitches> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                .child(Node.class).augmentation(HwvtepGlobalAugmentation.class)
+                .child(LogicalSwitches.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpLogicalSwitchListener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<LogicalSwitches> identifier,
+            LogicalSwitches del) {
+        logger.trace("Received LogicalSwitch remove DCN");
+        String elanInstanceName = del.getLogicalSwitchUuid().toString();
+        ConcurrentMap<String, L2GatewayDevice> devices  = L2GatewayCacheUtils.getCache();
+        String nodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+        L2GatewayDevice targetDevice = null;
+        for (L2GatewayDevice device : devices.values()) {
+            if (nodeId.equals(device.getHwvtepNodeId())) {
+                targetDevice = device;
+                break;
+            }
+        }
+        if (targetDevice == null) {
+            logger.error("Logical Switch Device with name {} is not present in L2GW cache", elanInstanceName);
+            return;
+        }
+        IpAddress tunnelIp = targetDevice.getTunnelIp();
+        handleLogicalSwitchRemove(elanInstanceName, tunnelIp);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<LogicalSwitches> identifier,
+            LogicalSwitches original, LogicalSwitches update) {
+        logger.trace("Received LogicalSwitch update DCN");
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<LogicalSwitches> identifier,
+            LogicalSwitches add) {
+        logger.trace("Received LogicalSwitch add DCN");
+        String elanInstanceName = add.getHwvtepNodeName().getValue();
+        ConcurrentMap<String, L2GatewayDevice> devices  = L2GatewayCacheUtils.getCache();
+        String nodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+        L2GatewayDevice targetDevice = null;
+        for (L2GatewayDevice device : devices.values()) {
+            if (nodeId.equals(device.getHwvtepNodeId())) {
+                targetDevice = device;
+                break;
+            }
+        }
+        if (targetDevice == null) {
+            logger.error("Logical Switch Device with name {} is not present in L2GW cache", elanInstanceName);
+            return;
+        }
+        IpAddress tunnelIp = targetDevice.getTunnelIp();
+        handleLogicalSwitchAdd(elanInstanceName, tunnelIp);
+
+    }
+
+    private void handleLogicalSwitchRemove(String elanInstanceName, IpAddress tunnelIp) {
+        BigInteger designatedDpnId;
+        designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+        if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            logger.info("Could not find designated DPN ID");
+            return;
+        }
+        dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+    }
+
+    private void handleLogicalSwitchAdd(String elanInstanceName, IpAddress tunnelIp) {
+        List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+        BigInteger designatedDpnId;
+        designatedDpnId = dhcpExternalTunnelManager.designateDpnId(tunnelIp, elanInstanceName, dpns);
+        if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            logger.info("Unable to designate a DPN");
+            return;
+        }
+    }
+}
\ No newline at end of file
index 2309defb00a5ad69c9b46bcd792508228718d20a..af36ca955d24949290f1b1a0b990fe13987fe5d2 100644 (file)
@@ -7,36 +7,22 @@
  */
 package org.opendaylight.vpnservice.dhcpservice;
 
-import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
-
-import com.google.common.base.Optional;
-
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
-import com.google.common.util.concurrent.FutureCallback;
-
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
-import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
-import org.opendaylight.vpnservice.mdsalutil.ActionType;
 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
 import org.slf4j.Logger;
@@ -53,16 +39,8 @@ public class DhcpManager implements AutoCloseable {
     private int dhcpOptRebindingTime = 0;
     private String dhcpOptDefDomainName;
     private INeutronVpnManager neutronVpnService;
-
-    private static final FutureCallback<Void> DEFAULT_CALLBACK =
-        new FutureCallback<Void>() {
-            public void onSuccess(Void result) {
-                logger.debug("Success in Datastore write operation");
-            }
-            public void onFailure(Throwable error) {
-                logger.error("Error in Datastore write operation", error);
-            };
-        };
+    // cache used to maintain DpnId and physical address for each interface.
+    private static HashMap<String, ImmutablePair<BigInteger, String>> interfaceToDpnIdMacAddress = new HashMap<String, ImmutablePair<BigInteger, String>>();
 
     /**
     * @param db - dataBroker reference
@@ -86,43 +64,6 @@ public class DhcpManager implements AutoCloseable {
         logger.info("DHCP Manager Closed");
     }
 
-    public void installDhcpEntries(BigInteger dpnId) {
-        logger.debug("Installing Default DHCP Flow tp DPN: {}", dpnId);
-        setupDefaultDhcpFlow(dpnId, NwConstants.DHCP_TABLE, NwConstants.ADD_FLOW);
-    }
-
-    private void setupDefaultDhcpFlow(BigInteger dpId,  short tableId, int addOrRemove) {
-
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-
-        matches.add(new MatchInfo(MatchFieldType.eth_type,
-                new long[] { NwConstants.ETHTYPE_IPV4 }));
-        matches.add(new MatchInfo(MatchFieldType.ip_proto,
-                new long[] { IPProtocols.UDP.intValue() }));
-        matches.add(new MatchInfo(MatchFieldType.udp_src,
-                new long[] { DHCPMConstants.dhcpClientPort }));
-        matches.add(new MatchInfo(MatchFieldType.udp_dst,
-                new long[] { DHCPMConstants.dhcpServerPort }));
-
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-
-        // Punt to controller
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
-                new String[] {}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions,
-                actionsInfos));
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                getDefaultDhcpFlowRef(dpId, tableId),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
-                DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
-        mdsalUtil.installFlow(flowEntity);
-    }
-
-    private String getDefaultDhcpFlowRef(BigInteger dpId, long tableId) {
-        return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX).append(dpId)
-                        .append(NwConstants.FLOWID_SEPARATOR).append(tableId).toString();
-    }
-
     public int setLeaseDuration(int leaseDuration) {
         configureLeaseDuration(leaseDuration);
         return getDhcpLeaseTime();
@@ -174,6 +115,8 @@ public class DhcpManager implements AutoCloseable {
     public Port getNeutronPort(String name) {
         try {
             return neutronVpnService.getNeutronPort(name);
+        } catch (IllegalArgumentException e) {
+            return null;
         } catch (Exception ex) {
             logger.trace("In getNeutronPort interface name passed {} exception message {}.", name, ex.getMessage());
             return null;
@@ -181,59 +124,11 @@ public class DhcpManager implements AutoCloseable {
     }
 
     public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
-        setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW);
-    }
-
-    private void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove) {
-        if (dpId == null || dpId == DHCPMConstants.INVALID_DPID || vmMacAddress == null) {
-            return;
-        }
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-
-        matches.add(new MatchInfo(MatchFieldType.eth_type,
-                new long[] { NwConstants.ETHTYPE_IPV4 }));
-        matches.add(new MatchInfo(MatchFieldType.ip_proto,
-                new long[] { IPProtocols.UDP.intValue() }));
-        matches.add(new MatchInfo(MatchFieldType.udp_src,
-                new long[] { DHCPMConstants.dhcpClientPort }));
-        matches.add(new MatchInfo(MatchFieldType.udp_dst,
-                new long[] { DHCPMConstants.dhcpServerPort }));
-        matches.add(new MatchInfo(MatchFieldType.eth_src,
-                new String[] { vmMacAddress }));
-
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-
-        // Punt to controller
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
-                new String[] {}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions,
-                actionsInfos));
-        if (addOrRemove == NwConstants.DEL_FLOW) {
-            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                    getDhcpFlowRef(dpId, tableId, vmMacAddress),
-                    DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
-                    DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
-            logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
-            mdsalUtil.removeFlow(flowEntity);
-        } else {
-            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                    getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
-                    DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
-            logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
-            mdsalUtil.installFlow(flowEntity);
-        }
-    }
-
-    private String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
-        return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
-                .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(vmMacAddress).toString();
+        DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
     }
 
     public void unInstallDhcpEntries(BigInteger dpId, String vmMacAddress) {
-        setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW);
+        DhcpServiceUtils.setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
     }
 
     public void setupTableMissForDhcpTable(BigInteger dpId) {
@@ -245,5 +140,29 @@ public class DhcpManager implements AutoCloseable {
                 0, "DHCP Table Miss Flow", 0, 0,
                 DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
         mdsalUtil.installFlow(flowEntity);
+        setupTableMissForHandlingExternalTunnel(dpId);
+    }
+
+    private void setupTableMissForHandlingExternalTunnel(BigInteger dpId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.EXTERNAL_TUNNEL_TABLE }));
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, "DHCPTableMissFlowForExternalTunnel",
+                0, "DHCP Table Miss Flow For External Tunnel", 0, 0,
+                DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+        mdsalUtil.installFlow(flowEntity);
+    }
+
+    public void updateInterfaceCache(String interfaceName, ImmutablePair<BigInteger, String> pair) {
+        interfaceToDpnIdMacAddress.put(interfaceName, pair);
+    }
+
+    public ImmutablePair<BigInteger, String> getInterfaceCache(String interfaceName) {
+        return interfaceToDpnIdMacAddress.get(interfaceName);
+    }
+
+    public void removeInterfaceCache(String interfaceName) {
+        interfaceToDpnIdMacAddress.remove(interfaceName);
     }
 }
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpNeutronPortListener.java
new file mode 100644 (file)
index 0000000..385d919
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpNeutronPortListener extends AsyncClusteredDataChangeListenerBase<Port, DhcpNeutronPortListener> implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpNeutronPortListener.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private DataBroker broker;
+
+    public DhcpNeutronPortListener(final DataBroker db, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        super(Port.class, DhcpNeutronPortListener.class);
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.broker = db;
+    }
+
+    @Override
+    protected InstanceIdentifier<Port> getWildCardPath() {
+        return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DhcpNeutronPortListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.debug("DhcpNeutronPortListener Listener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Port> identifier, Port del) {
+        LOG.trace("Port removed: {}", del);
+        if(NeutronUtils.isPortVnicTypeNormal(del)) {
+            return;
+        }
+        String macAddress = del.getMacAddress();
+        Uuid networkId = del.getNetworkId();
+        String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+        if (segmentationId == null) {
+            return;
+        }
+        List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+        dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(networkId.getValue(), listOfDpns, macAddress);
+        dhcpExternalTunnelManager.removeVniMacToPortCache(new BigInteger(segmentationId), macAddress);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
+        LOG.trace("Port changed to {}", update);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Port> identifier, Port add) {
+        LOG.trace("Port added {}", add);
+        if(NeutronUtils.isPortVnicTypeNormal(add)) {
+            LOG.trace("Port is normal {}", add);
+            return;
+        }
+        String macAddress = add.getMacAddress();
+        Uuid networkId = add.getNetworkId();
+        String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+        if (segmentationId == null) {
+            LOG.trace("segmentation id is null");
+            return;
+        }
+        dhcpExternalTunnelManager.updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, add);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpNeutronPortListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
+    }
+}
index 60d8bd729ec465a125968e3826dff8c2c37a0131..c74171a30ffe28c33b91a2e2fbd7dc9d3d6b6289 100644 (file)
@@ -13,7 +13,6 @@ import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -72,11 +71,12 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
     private final DataBroker dataBroker;
     private final DhcpManager dhcpMgr;
     private OdlInterfaceRpcService interfaceManagerRpc;
-    private static HashMap<String, ImmutablePair<BigInteger, String>> localCache = new HashMap<String, ImmutablePair<BigInteger, String>>();
     private boolean computeUdpChecksum = true;
     private PacketProcessingService pktService;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
 
-    public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager) {
+    public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.dataBroker = broker;
         dhcpMgr = dhcpManager;
     }
@@ -84,16 +84,15 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
     //TODO: Handle this in a separate thread
     @Override
     public void onPacketReceived(PacketReceived packet) {
-        LOG.trace("Pkt received: {}", packet);
         Class<? extends PacketInReason> pktInReason = packet.getPacketInReason();
-        short tableId = packet.getTableId().getValue();
         if (isPktInReasonSendtoCtrl(pktInReason)) {
             byte[] inPayload = packet.getPayload();
             Ethernet ethPkt = new Ethernet();
             try {
                 ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
             } catch (Exception e) {
-                LOG.warn("Failed to decode DHCP Packet", e);
+                LOG.warn("Failed to decode DHCP Packet {}", e);
+                LOG.trace("Received packet {}", packet);
                 return;
             }
             try {
@@ -101,29 +100,33 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
                 pktIn = getDhcpPktIn(ethPkt);
                 if (pktIn != null) {
                     LOG.trace("DHCPPkt received: {}", pktIn);
+                    LOG.trace("Received Packet: {}", packet);
                     BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
                     long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+                    String macAddress = DHCPUtils.byteArrayToString(ethPkt.getSourceMACAddress());
+                    BigInteger tunnelId = packet.getMatch().getTunnel() == null ? null : packet.getMatch().getTunnel().getTunnelId();
                     String interfaceName = getInterfaceNameFromTag(portTag);
                     ImmutablePair<BigInteger, String> pair = getDpnIdPhysicalAddressFromInterfaceName(interfaceName);
-                    DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName);
+                    DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, tunnelId);
                     byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, pair.getRight());
-                    sendPacketOut(pktOut, pair.getLeft(), interfaceName);
+                    sendPacketOut(pktOut, pair.getLeft(), interfaceName, tunnelId);
                 }
             } catch (Exception e) {
-                LOG.warn("Failed to get DHCP Reply {}", e);
+                LOG.warn("Failed to get DHCP Reply");
+                LOG.trace("Reason for failure {}", e);
             }
         }
     }
 
-    private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName) {
+    private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName, BigInteger tunnelId) {
         LOG.trace("Sending packet out DpId {}, portId {}, vlanId {}, interfaceName {}", dpnId, interfaceName);
-        List<Action> action = getEgressAction(interfaceName);
+        List<Action> action = getEgressAction(interfaceName, tunnelId);
         TransmitPacketInput output = MDSALUtil.getPacketOut(action, pktOut, dpnId);
         LOG.trace("Transmitting packet: {}",output);
         this.pktService.transmitPacket(output);
     }
 
-    private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName) {
+    private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, BigInteger tunnelId) {
         LOG.debug("DHCP pkt rcvd {}", dhcpPkt);
         byte msgType = dhcpPkt.getMsgType();
         if (msgType == DHCPConstants.MSG_DECLINE) {
@@ -133,8 +136,12 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
             LOG.debug("DHCPRELEASE received");
             return null;
         }
-
-        Port nPort = getNeutronPort(interfaceName);
+        Port nPort;
+        if (tunnelId != null) {
+            nPort = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
+        } else {
+            nPort = getNeutronPort(interfaceName);
+        }
         Subnet nSubnet = getNeutronSubnet(nPort);
         DhcpInfo dhcpInfo = getDhcpInfo(nPort, nSubnet);
         LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}",nPort, nSubnet, dhcpInfo);
@@ -160,13 +167,6 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
             dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
                 .setCidr(nSubnet.getCidr()).setHostRoutes(nSubnet.getHostRoutes())
                 .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
-        } else {
-            //FIXME: Delete this test code
-            LOG.error("TestOnly Code");
-            dhcpInfo = new DhcpInfo();
-            dhcpInfo.setClientIp("1.1.1.3").setServerIp("1.1.1.1")
-                .setCidr("1.1.1.0/24").addDnsServer("1.1.1.1");
-            LOG.warn("Failed to get Subnet info for DHCP reply");
         }
         return dhcpInfo;
     }
@@ -181,7 +181,6 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
 
     private DHCP getDhcpPktIn(Ethernet actualEthernetPacket) {
         Ethernet ethPkt = actualEthernetPacket;
-        LOG.trace("Inside getDhcpPktIn ethPkt {} \n getPayload {}", ethPkt, ethPkt.getPayload());
         if (ethPkt.getEtherType() == (short)NwConstants.ETHTYPE_802_1Q) {
             ethPkt = (Ethernet)ethPkt.getPayload();
         }
@@ -197,7 +196,8 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
                     try {
                         reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length);
                     } catch (PacketException e) {
-                        LOG.warn("Failed to deserialize DHCP pkt {}", e);
+                        LOG.warn("Failed to deserialize DHCP pkt");
+                        LOG.trace("Reason for failure {}", e);
                         return null;
                     }
                     return reply;
@@ -329,7 +329,6 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
             ether.setEtherType(EtherTypes.IPv4.shortValue());
             ether.setPayload(ip4Reply);
         }
-        //TODO: 
         ether.setSourceMACAddress(getServerMacAddress(phyAddrees));
         ether.setDestinationMACAddress(etherPkt.getSourceMACAddress());
 
@@ -577,12 +576,15 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
         return id;
     }
 
-    private List<Action> getEgressAction(String interfaceName) {
+    private List<Action> getEgressAction(String interfaceName, BigInteger tunnelId) {
         List<Action> actions = null;
         try {
+            GetEgressActionsForInterfaceInputBuilder egressAction = new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName);
+            if (tunnelId != null) {
+                egressAction.setTunnelKey(tunnelId.longValue());
+            }
             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
-                    interfaceManagerRpc.getEgressActionsForInterface(
-                            new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName).build());
+                    interfaceManagerRpc.getEgressActionsForInterface(egressAction.build());
             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
             if(!rpcResult.isSuccessful()) {
                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName, rpcResult.getErrors());
@@ -596,7 +598,7 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
     }
 
     private ImmutablePair<BigInteger, String> getDpnIdPhysicalAddressFromInterfaceName(String interfaceName) {
-        ImmutablePair<BigInteger, String> pair = localCache.get(interfaceName);
+        ImmutablePair<BigInteger, String> pair = dhcpMgr.getInterfaceCache(interfaceName);
         if (pair!=null && pair.getLeft() != null && pair.getRight() != null) {
             return pair;
         }
@@ -609,7 +611,7 @@ public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         String phyAddress = interfaceState==null ? "":interfaceState.getPhysAddress().getValue();
         pair = new ImmutablePair<BigInteger, String>(dpId, phyAddress);
-        localCache.put(interfaceName, pair);
-        return null;
+        dhcpMgr.updateInterfaceCache(interfaceName, pair);
+        return pair;
     }
 }
index 439d7352ada125065e56709c544c8a17d38d72f4..f86b46424ec7de44a7f67eb263f2a0ecf9dcb214 100644 (file)
@@ -7,15 +7,18 @@
  */
 package org.opendaylight.vpnservice.dhcpservice;
 
-import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
-import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,6 +35,15 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable {
     private DhcpConfigListener dhcpConfigListener;
     private OdlInterfaceRpcService interfaceManagerRpc;
     private DhcpInterfaceEventListener dhcpInterfaceEventListener;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private DhcpNeutronPortListener dhcpNeutronPortListener;
+    private DhcpLogicalSwitchListener dhcpLogicalSwitchListener;
+    private DhcpUCastMacListener dhcpUCastMacListener;
+    private ItmRpcService itmRpcService;
+    private DhcpInterfaceConfigListener dhcpInterfaceConfigListener;
+    private EntityOwnershipService entityOwnershipService;
+    private DhcpDesignatedDpnListener dhcpDesignatedDpnListener;
+    private DhcpL2GatewayConnectionListener dhcpL2GatewayConnectionListener;
 
     @Override
     public void onSessionInitiated(ProviderContext session) {
@@ -42,19 +54,29 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable {
             dhcpManager = new DhcpManager(dataBroker);
             dhcpManager.setMdsalManager(mdsalManager);
             dhcpManager.setNeutronVpnService(neutronVpnManager);
-            dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager);
+            dhcpExternalTunnelManager = new DhcpExternalTunnelManager(dataBroker, mdsalManager, itmRpcService, entityOwnershipService);
+            dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager, dhcpExternalTunnelManager);
             dhcpPktHandler.setPacketProcessingService(pktProcessingService);
             dhcpPktHandler.setInterfaceManagerRpc(interfaceManagerRpc);
             packetListener = notificationService.registerNotificationListener(dhcpPktHandler);
-            dhcpNodeListener = new NodeListener(dataBroker, dhcpManager);
+            dhcpNodeListener = new NodeListener(dataBroker, dhcpManager, dhcpExternalTunnelManager);
             dhcpConfigListener = new DhcpConfigListener(dataBroker, dhcpManager);
-            dhcpInterfaceEventListener = new DhcpInterfaceEventListener(dhcpManager, dataBroker);
+            dhcpInterfaceEventListener = new DhcpInterfaceEventListener(dhcpManager, dataBroker, dhcpExternalTunnelManager);
+            dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(dataBroker, dhcpExternalTunnelManager);
+            dhcpLogicalSwitchListener = new DhcpLogicalSwitchListener(dhcpExternalTunnelManager, dataBroker);
+            dhcpUCastMacListener = new DhcpUCastMacListener(dhcpExternalTunnelManager, dataBroker);
+            dhcpUCastMacListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+            dhcpNeutronPortListener = new DhcpNeutronPortListener(dataBroker, dhcpExternalTunnelManager);
+            dhcpNeutronPortListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            dhcpDesignatedDpnListener = new DhcpDesignatedDpnListener(dhcpExternalTunnelManager, dataBroker);
+            dhcpDesignatedDpnListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            dhcpL2GatewayConnectionListener = new DhcpL2GatewayConnectionListener(dataBroker, dhcpExternalTunnelManager);
+            dhcpL2GatewayConnectionListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
         } catch (Exception e) {
             LOG.error("Error initializing services {}", e);
         }
     }
 
-
     public void setMdsalManager(IMdsalApiManager mdsalManager) {
         this.mdsalManager = mdsalManager;
     }
@@ -84,4 +106,12 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable {
     public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
         this.interfaceManagerRpc = interfaceManagerRpc;
     }
+
+    public void setItmRpcService(ItmRpcService itmRpcService) {
+        this.itmRpcService = itmRpcService;
+    }
+
+    public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+        this.entityOwnershipService = entityOwnershipService;
+    }
 }
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java
new file mode 100644 (file)
index 0000000..b925646
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.LinkedList;
+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.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+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.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.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpServiceUtils {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpServiceUtils.class);
+
+    public static Interface getInterfaceFromConfigDS(String interfaceName, DataBroker dataBroker) {
+        InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
+        InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
+        Optional<Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, interfaceId, dataBroker);
+        if (!interfaceOptional.isPresent()) {
+            return null;
+        }
+        return interfaceOptional.get();
+    }
+
+    private static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
+        InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder =
+                InstanceIdentifier.builder(Interfaces.class).child(Interface.class, interfaceKey);
+        return interfaceInstanceIdentifierBuilder.build();
+    }
+
+    public static void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil) {
+        if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
+            return;
+        }
+        List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+
+        // Punt to controller
+        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
+                new String[] {}));
+        instructions.add(new InstructionInfo(InstructionType.write_actions,
+                actionsInfos));
+        if (addOrRemove == NwConstants.DEL_FLOW) {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),
+                    DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
+            logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.removeFlow(flowEntity);
+        } else {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+            logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.installFlow(flowEntity);
+        }
+    }
+
+    private static String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
+        return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
+                .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(vmMacAddress).toString();
+    }
+
+    public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil) {
+        if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
+            return;
+        }
+        List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
+
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+        // Drop Action
+        actionsInfos.add(new ActionInfo(ActionType.drop_action,
+                new String[] {}));
+        if (addOrRemove == NwConstants.DEL_FLOW) {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),
+                    DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
+            logger.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.removeFlow(flowEntity);
+        } else {
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+                    DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+            logger.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            mdsalUtil.installFlow(flowEntity);
+        }
+    }
+
+    private static List<MatchInfo> getDhcpMatch(String vmMacAddress) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { NwConstants.ETHTYPE_IPV4 }));
+        matches.add(new MatchInfo(MatchFieldType.ip_proto,
+                new long[] { IPProtocols.UDP.intValue() }));
+        matches.add(new MatchInfo(MatchFieldType.udp_src,
+                new long[] { DHCPMConstants.dhcpClientPort }));
+        matches.add(new MatchInfo(MatchFieldType.udp_dst,
+                new long[] { DHCPMConstants.dhcpServerPort }));
+        matches.add(new MatchInfo(MatchFieldType.eth_src,
+                new String[] { vmMacAddress }));
+        return matches;
+    }
+
+    public static List<BigInteger> getListOfDpns(DataBroker broker) {
+        List<BigInteger> dpnsList = new LinkedList<BigInteger>();
+        InstanceIdentifier<Nodes> nodesInstanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
+        Optional<Nodes> nodesOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, nodesInstanceIdentifier);
+        if (!nodesOptional.isPresent()) {
+            return dpnsList;
+        }
+        Nodes nodes = nodesOptional.get();
+        List<Node> nodeList = nodes.getNode();
+        for (Node node : nodeList) {
+            NodeId nodeId = node.getId();
+            if (nodeId == null) {
+                continue;
+            }
+            BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
+            dpnsList.add(dpnId);
+        }
+        return dpnsList;
+    }
+
+    public static List<BigInteger> getDpnsForElan(String elanInstanceName, DataBroker broker) {
+        List<BigInteger> elanDpns = new LinkedList<BigInteger>();
+        InstanceIdentifier<ElanDpnInterfacesList> elanDpnInstanceIdentifier = InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
+        Optional<ElanDpnInterfacesList> elanDpnOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInstanceIdentifier);
+        if (elanDpnOptional.isPresent()) {
+            List<DpnInterfaces> dpns = elanDpnOptional.get().getDpnInterfaces();
+            for (DpnInterfaces dpnInterfaces : dpns) {
+                elanDpns.add(dpnInterfaces.getDpId());
+            }
+        }
+        return elanDpns;
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceFromOperationalDS(String interfaceName, DataBroker dataBroker) {
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey interfaceKey = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName);
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceId = InstanceIdentifier.builder(InterfacesState.class).child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class, interfaceKey).build();
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, interfaceId, dataBroker);
+        if (!interfaceOptional.isPresent()) {
+            return null;
+        }
+        return interfaceOptional.get();
+    }
+
+
+    public static String getSegmentationId(Uuid networkId, DataBroker broker) {
+        InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class).child(Networks.class).child
+                (Network.class, new NetworkKey(networkId));
+        Optional<Network> optionalNetwork = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+        if (!optionalNetwork.isPresent()) {
+            return null;
+        }
+        Network network = optionalNetwork.get();
+        String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(network);
+        return segmentationId;
+    }
+
+    public static String getNodeIdFromDpnId(BigInteger dpnId) {
+        return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
+    }
+
+    public static String getTrunkPortMacAddress(String parentRefName,
+            DataBroker broker) {
+        InstanceIdentifier<Port> portInstanceIdentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
+        Optional<Port> trunkPort = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, portInstanceIdentifier);
+        if (!trunkPort.isPresent()) {
+            logger.warn("Trunk port {} not available for sub-port", parentRefName);
+            return null;
+        }
+        return trunkPort.get().getMacAddress();
+    }
+}
\ No newline at end of file
diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java
new file mode 100644 (file)
index 0000000..5d967e5
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.dhcpservice;
+
+import java.math.BigInteger;
+
+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.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+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.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+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.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpUCastMacListener extends AsyncClusteredDataChangeListenerBase<LocalUcastMacs, DhcpUCastMacListener> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DhcpUCastMacListener.class);
+    private DataBroker broker;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+
+    public DhcpUCastMacListener(DhcpExternalTunnelManager dhcpManager, DataBroker dataBroker) {
+        super(LocalUcastMacs.class, DhcpUCastMacListener.class);
+        this.broker = dataBroker;
+        this.dhcpExternalTunnelManager = dhcpManager;
+    }
+
+    @Override
+    protected InstanceIdentifier<LocalUcastMacs> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
+                .augmentation(HwvtepGlobalAugmentation.class).child(LocalUcastMacs.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        logger.info("DhcpUCastMacListener Closed");
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<LocalUcastMacs> identifier,
+            LocalUcastMacs del) {
+        // Flow removal for table 18 is handled in Neutron Port delete.
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<LocalUcastMacs> identifier,
+            LocalUcastMacs original, LocalUcastMacs update) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<LocalUcastMacs> identifier,
+            LocalUcastMacs add) {
+        NodeId torNodeId = identifier.firstKeyOf(Node.class).getNodeId();
+        InstanceIdentifier<LogicalSwitches> logicalSwitchRef = (InstanceIdentifier<LogicalSwitches>) add.getLogicalSwitchRef().getValue();
+        Optional<LogicalSwitches> logicalSwitchOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, logicalSwitchRef);
+        if ( !logicalSwitchOptional.isPresent() ) {
+            logger.error("Logical Switch ref doesn't have data {}", logicalSwitchRef);
+            return;
+        }
+        LogicalSwitches logicalSwitch = logicalSwitchOptional.get();
+        String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
+        String macAddress = add.getMacEntryKey().getValue();
+        BigInteger vni = new BigInteger(logicalSwitch.getTunnelKey());
+        Port port = dhcpExternalTunnelManager.readVniMacToPortCache(vni, macAddress);
+        if (port == null) {
+            logger.trace("No neutron port created for macAddress {}, tunnelKey {}", macAddress, vni);
+            return;
+        }
+        L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
+        if (device == null) {
+            logger.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
+            return;
+        }
+        IpAddress tunnelIp = device.getTunnelIp();
+        BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+        dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, macAddress);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return DhcpUCastMacListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return DataChangeScope.SUBTREE;
+    }
+}
\ No newline at end of file
index b7d0f2be5aa45994182b49eec67072a317b41892..11bbb71a04a3efdea40160626defb24404df0bf2 100644 (file)
@@ -7,14 +7,16 @@
  */
 package org.opendaylight.vpnservice.dhcpservice;
 
+import java.math.BigInteger;
+import java.util.List;
+
 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.LogicalDatastoreType;
 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
-import org.opendaylight.vpnservice.mdsalutil.*;
-import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 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;
@@ -23,30 +25,27 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-
 public class NodeListener extends AbstractDataChangeListener<Node> implements AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(NodeListener.class);
 
-    private IMdsalApiManager mdsalManager;
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker broker;
     private DhcpManager dhcpManager;
+    private DhcpExternalTunnelManager dhcpExternalTunnelManager;
 
-    public NodeListener(final DataBroker db, final DhcpManager dhcpMgr) {
+    public NodeListener(final DataBroker db, final DhcpManager dhcpMgr, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
         super(Node.class);
         broker = db;
         dhcpManager = dhcpMgr;
+        this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         registerListener(db);
     }
 
     private void registerListener(final DataBroker db) {
         try {
             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
-                    getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+            getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
         } catch (final Exception e) {
             LOG.error("NodeListener: DataChange listener registration fail!", e);
             throw new IllegalStateException("NodeListener: registration Listener failed.", e);
@@ -57,10 +56,12 @@ public class NodeListener extends AbstractDataChangeListener<Node> implements Au
         return InstanceIdentifier.create(Nodes.class).child(Node.class);
     }
 
-
     @Override
     protected void remove(InstanceIdentifier<Node> identifier, Node del) {
-
+        NodeId nodeId = del.getId();
+        BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
+        List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+        dhcpExternalTunnelManager.handleDesignatedDpnDown(dpnId, listOfDpns);
     }
 
     @Override
@@ -72,8 +73,15 @@ public class NodeListener extends AbstractDataChangeListener<Node> implements Au
     protected void add(InstanceIdentifier<Node> identifier, Node add) {
         NodeId nodeId = add.getId();
         String[] node =  nodeId.getValue().split(":");
+        if(node.length < 2) {
+            LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+            return;
+        }
         BigInteger dpId = new BigInteger(node[1]);
         dhcpManager.setupTableMissForDhcpTable(dpId);
+        dhcpExternalTunnelManager.installDhcpDropActionOnDpn(dpId);
+        List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+        dhcpExternalTunnelManager.handleDesignatedDpnDown(DHCPMConstants.INVALID_DPID, listOfDpns);
     }
 
     @Override
index 2fa746dce7abb10fa7790114cc113195af39aa74..01c99cf9bc62974653f70fc9cf32162448fc5484 100644 (file)
@@ -3,6 +3,7 @@ package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpser
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.vpnservice.dhcpservice.DhcpProvider;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 
 public class DhcpServiceImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.impl.rev150710.AbstractDhcpServiceImplModule {
     public DhcpServiceImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -26,6 +27,8 @@ public class DhcpServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open
         dhcpProvider.setMdsalManager(getMdsalutilDependency());
         dhcpProvider.setNeutronVpnManager(getNeutronvpnDependency());
         dhcpProvider.setInterfaceManagerRpc(rpcregistryDependency.getRpcService(OdlInterfaceRpcService.class));
+        dhcpProvider.setItmRpcService(rpcregistryDependency.getRpcService(ItmRpcService.class));
+        dhcpProvider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
         getBrokerDependency().registerProvider(dhcpProvider);
         return dhcpProvider;
     }
index 856b7716dc26a1244c8aa30f0618474184208ebc..9a05103f179bf69dcadd9f117ed6a3f5f43a858e 100644 (file)
@@ -7,6 +7,7 @@ module dhcpservice-impl {
     import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
     import odl-mdsalutil { prefix odl-mdsal; revision-date 2015-04-10;}
     import neutronvpn-api { prefix nvpn; revision-date 2015-08-12;}
+    import opendaylight-entity-ownership-service { prefix eos; revision-date 2015-08-10;}
 
     description
         "Service definition for dhcpservice project";
@@ -66,6 +67,15 @@ module dhcpservice-impl {
                     }
                 }
             }
+
+            container entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
+                }
+            }
         }
     }
 }
index 4022cc23f50c76eee4578853ae066eed75fa68b9..3072448f068e2a39d040bca121a9b4a03ee91b8c 100644 (file)
@@ -8,11 +8,10 @@
 
 package org.opendaylight.elanmanager.utils;
 
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.cache.CacheUtil;
@@ -57,32 +56,32 @@ public class ElanL2GwCacheUtils {
     }
 
 
-    public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String deviceName) {
+    public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
         ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
                 (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
                         ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
         ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
         if (deviceMap != null) {
-            L2GatewayDevice device = deviceMap.remove(deviceName);
+            L2GatewayDevice device = deviceMap.remove(l2gwDeviceNodeId);
             return device;
         } else {
             return null;
         }
     }
 
-    public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String deviceName) {
+    public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
         ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
                 (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
                         ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
         ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
         if (deviceMap != null) {
-            return deviceMap.get(deviceName);
+            return deviceMap.get(l2gwDeviceNodeId);
         } else {
             return null;
         }
     }
 
-    public static ConcurrentMap<String, L2GatewayDevice> getAllElanL2GatewayDevicesFromCache(String elanName) {
+    public static ConcurrentMap<String, L2GatewayDevice> getInvolvedL2GwDevices(String elanName) {
         ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap = (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil
                 .getCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
         ConcurrentMap<String, L2GatewayDevice> result = cachedMap.get(elanName);
index b7ea5772449886db8e910d4933e08c63d4fec1dd..2fa9b6c9373b93718a1fba09afffe5db9f35495a 100644 (file)
@@ -106,6 +106,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <version>${powermock.version}</version>
         <scope>test</scope>
     </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <version>${mdsal.version}</version>
+          <scope>test</scope>
+          <type>test-jar</type>
+      </dependency>
+      <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+          <scope>test</scope>
+      </dependency>
   </dependencies>
-
 </project>
index b34398e2f8d1987d0d41a6b4f9c83fe953e88d70..95ff81072992fd923dbd3d8f8a04fc7620510829 100644 (file)
@@ -52,10 +52,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
                         <name>entity-ownership-service</name>
                     </entity-ownership-service>
-                    <binding-normalized-node-serializer>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
-                        <name>runtime-mapping-singleton</name>
-                    </binding-normalized-node-serializer>
                 </module>
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
index f9954043b0f33105a9acfe2b8db1ae9e68ab34ee..d08347b7a47d5069d23544e74676e930cd99ec35 100644 (file)
@@ -85,7 +85,7 @@ public class L2GwUtilsCacheCli extends OsgiCommandSupport {
             return;
         }
         ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
         print(elanName, elanDevices);
     }
 
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java
new file mode 100644 (file)
index 0000000..3260581
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+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.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanDpnInterfaceClusteredListener
+        extends AsyncClusteredDataChangeListenerBase<DpnInterfaces, ElanDpnInterfaceClusteredListener>
+        implements AutoCloseable {
+    private DataBroker broker;
+    private ElanInterfaceManager elanInterfaceManager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    private static final Logger LOG = LoggerFactory.getLogger(ElanDpnInterfaceClusteredListener.class);
+
+    public ElanDpnInterfaceClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+        super(DpnInterfaces.class, ElanDpnInterfaceClusteredListener.class);
+        broker = db;
+        elanInterfaceManager = ifManager;
+        registerListener(db);
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), ElanDpnInterfaceClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+        } catch (final Exception e) {
+            LOG.error("DpnInterfaces DataChange listener registration fail!", e);
+        }
+    }
+
+    @Override
+    public InstanceIdentifier<DpnInterfaces> getWildCardPath() {
+        return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class)
+                .child(DpnInterfaces.class).build();
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return ElanDpnInterfaceClusteredListener.this;
+    }
+
+    @Override
+    protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.BASE;
+    }
+
+    void handleUpdate(InstanceIdentifier<DpnInterfaces> id, DpnInterfaces dpnInterfaces) {
+        final String elanName = getElanName(id);
+        if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+            LOG.debug("dpnInterface updation, no external l2 devices to update for elan {} with Dp Id:", elanName,
+                    dpnInterfaces.getDpId());
+            return;
+        }
+        ElanClusterUtils.runOnlyInLeaderNode(elanName, "updating mcast mac upon tunnel event",
+                new Callable<List<ListenableFuture<Void>>>() {
+                    @Override
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        return Lists.newArrayList(
+                                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+                    }
+                });
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+        // this is the last dpn interface on this elan
+        final String elanName = getElanName(identifier);
+        LOG.debug("Received ElanDpnInterface removed for for elan {} with Dp Id ", elanName,
+                dpnInterfaces.getDpId());
+
+        if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+            LOG.debug("dpnInterface removed, no external l2 devices to update for elan {} with Dp Id:", elanName,
+                    dpnInterfaces.getDpId());
+            return;
+        }
+        ElanClusterUtils.runOnlyInLeaderNode(elanName, "handling ElanDpnInterface removed",
+                new Callable<List<ListenableFuture<Void>>>() {
+                    @Override
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        // deleting Elan L2Gw Devices UcastLocalMacs From Dpn
+                        ElanL2GatewayUtils.deleteElanL2GwDevicesUcastLocalMacsFromDpn(elanName,
+                                dpnInterfaces.getDpId());
+                        // updating remote mcast mac on l2gw devices
+                        return Lists.newArrayList(
+                                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+                    }
+                });
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<DpnInterfaces> identifier, DpnInterfaces original,
+            final DpnInterfaces dpnInterfaces) {
+        LOG.debug("dpninterfaces update fired new size {}", dpnInterfaces.getInterfaces().size());
+        if (dpnInterfaces.getInterfaces().size() == 0) {
+            LOG.debug("dpninterfaces last dpn interface on this elan {} ", dpnInterfaces.getKey());
+            // this is the last dpn interface on this elan
+            handleUpdate(identifier, dpnInterfaces);
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+        if (dpnInterfaces.getInterfaces().size() == 1) {
+            LOG.debug("dpninterfaces first dpn interface on this elan {} {} ", dpnInterfaces.getKey(),
+                    dpnInterfaces.getInterfaces().get(0));
+            // this is the first dpn interface on this elan
+            handleUpdate(identifier, dpnInterfaces);
+        }
+    }
+
+    /**
+     * @param identifier
+     * @return
+     */
+    private String getElanName(InstanceIdentifier<DpnInterfaces> identifier) {
+        return identifier.firstKeyOf(ElanDpnInterfacesList.class).getElanInstanceName();
+    }
+}
index 89f707112ad31c1bbe2f6a3a33ed474913e20a62..f33321534d48ae5aa2b7f43d01ec50eaad998627 100644 (file)
@@ -13,6 +13,8 @@ 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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
@@ -39,6 +41,7 @@ public class ElanInstanceManager extends AbstractDataChangeListener<ElanInstance
     private ListenerRegistration<DataChangeListener> elanInstanceListenerRegistration;
     private IdManagerService idManager;
     private ElanInterfaceManager elanInterfaceManager;
+    private IInterfaceManager interfaceManager;
 
     private static final Logger logger = LoggerFactory.getLogger(ElanInstanceManager.class);
 
@@ -63,6 +66,10 @@ public class ElanInstanceManager extends AbstractDataChangeListener<ElanInstance
         this.elanInterfaceManager = elanInterfaceManager;
     }
 
+    public void setInterfaceManager(IInterfaceManager interfaceManager) {
+        this.interfaceManager = interfaceManager;
+    }
+
 
     /**
      * Starts listening for changes in elan.yang:elan-instance container
@@ -101,7 +108,8 @@ public class ElanInstanceManager extends AbstractDataChangeListener<ElanInstance
             if(elanInterfaces != null && !elanInterfaces.isEmpty()) {
                 for (String elanInterfaceName : elanInterfaces) {
                     InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName);
-                    elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName);
+                    InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName);
+                    elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName, interfaceInfo);
                     ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
                 }
             }
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java
new file mode 100644 (file)
index 0000000..b02e9e9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceAddWorker implements Callable<List<ListenableFuture<Void>>> {
+    private String key;
+    private ElanInterface elanInterface;
+    private ElanInstance elanInstance;
+    private InterfaceInfo interfaceInfo;
+    private ElanInterfaceManager dataChangeListener;
+
+    public ElanInterfaceAddWorker(String key, ElanInterface elanInterface, InterfaceInfo interfaceInfo,
+            ElanInstance elanInstance, ElanInterfaceManager dataChangeListener) {
+        super();
+        this.key = key;
+        this.elanInterface = elanInterface;
+        this.interfaceInfo = interfaceInfo;
+        this.elanInstance = elanInstance;
+        this.dataChangeListener = dataChangeListener;
+    }
+
+    @Override
+    public String toString() {
+        return "ElanInterfaceAddWorker [key=" + key + ", elanInterface=" + elanInterface + ", elanInstance="
+                + elanInstance + ", interfaceInfo=" + interfaceInfo + "]";
+    }
+
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        dataChangeListener.addElanInterface(elanInterface, interfaceInfo, elanInstance);
+        return futures;
+    }
+    
+    
+
+}
index 1b422c5d5b600c3baea4af94d20a1f72429312c1..83ba80101f672c7b39e5d145883c80ba00cf3f11 100644 (file)
@@ -18,29 +18,24 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-
+import org.apache.commons.lang3.StringUtils;
 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.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
-import org.opendaylight.vpnservice.itm.api.IITMProvider;
 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
 import org.opendaylight.vpnservice.mdsalutil.ActionType;
-import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
-import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
@@ -48,22 +43,18 @@ import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
-import org.opendaylight.vpnservice.itm.globals.ITMConstants;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.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.group.types.rev131018.group.buckets.Bucket;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.vpnservice.mdsalutil.*;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.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.types.rev131026.instruction.list.Instruction;
 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.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
@@ -88,6 +79,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.f
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -95,8 +88,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
 
 /**
  * Class in charge of handling creations, modifications and removals of ElanInterfaces.
@@ -183,20 +174,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
     protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
         String interfaceName =  del.getName();
         ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
-        removeElanInterface(elanInfo, interfaceName);
-    }
-
-    public void removeElanService(ElanInterface del, InterfaceInfo interfaceInfo) {
-        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
-        String interfaceName = del.getName();
-        removeElanInterface(elanInstance, interfaceInfo);
-        unbindService(elanInstance, interfaceName);
+        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+        String elanInstanceName = elanInfo.getElanInstanceName();
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        ElanInterfaceRemoveWorker configWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInfo, interfaceName, interfaceInfo, this);
+        coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
-    public void removeElanInterface(ElanInstance elanInfo, String interfaceName) {
+    public void removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo) {
         String elanName = elanInfo.getElanInstanceName();
-        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
-
         if (interfaceInfo == null) {
             // Interface does not exist in ConfigDS, so lets remove everything about that interface related to Elan
             ElanInterfaceMac elanInterfaceMac =  ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
@@ -228,6 +214,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
         BigInteger dpId = interfaceInfo.getDpId();
         String elanName = elanInfo.getElanInstanceName();
+        long elanTag = elanInfo.getElanTag();
         String interfaceName = interfaceInfo.getInterfaceName();
         Elan elanState = ElanUtils.getElanByName(elanName);
         logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
@@ -264,13 +251,13 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
                     DpnInterfaces dpnIfLists = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpnInterface.getDpId());
                     if (dpnIfLists.getInterfaces().contains(interfaceName)) {
                         logger.debug("deleting the elanInterface from the ElanDpnInterface cache in pre-provision scenario of elan:{} dpn:{} interfaceName:{}", elanName, dpId, interfaceName);
-                        removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+                        removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
                         break;
                     }
                 }
             }
         } else {
-            removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+            removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
         }
 
         removeStaticELanFlows(elanInfo, interfaceInfo);
@@ -290,21 +277,39 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName) {
+    private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName, long elanTag) {
         DpnInterfaces dpnInterfaces =  ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
         if(dpnInterfaces != null) {
             List<String> interfaceLists = dpnInterfaces.getInterfaces();
             interfaceLists.remove(interfaceName);
 
             if (interfaceLists == null || interfaceLists.isEmpty()) {
+                deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
                 deleteElanDpnInterface(elanName, dpId);
-                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName);
             } else {
                 updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
             }
         }
     }
 
+    private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
+        List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
+        for (DpnInterfaces dpnInterface : dpnInterfaces) {
+            BigInteger currentDpId = dpnInterface.getDpId();
+            if (!currentDpId.equals(dpId)) {
+                for (String elanInterface : dpnInterface.getInterfaces()) {
+                    ElanInterfaceMac macs = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+                    if (macs == null) {
+                        continue;
+                    }
+                    for (MacEntry mac : macs.getMacEntry())
+                        mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
+                            ElanUtils.getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, currentDpId, mac.getMacAddress().getValue(), elanTag)));
+                }
+            }
+        }
+    }
+
     @Override
     protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
         // updating the static-Mac Entries for the existing elanInterface
@@ -374,7 +379,10 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
             return;
         }
-        addElanInterface(elanInterfaceAdded, interfaceInfo, elanInstance);
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        ElanInterfaceAddWorker addWorker = new ElanInterfaceAddWorker(elanInstanceName, elanInterfaceAdded,
+                interfaceInfo, elanInstance, this);
+        coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
     void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
@@ -451,12 +459,12 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
                 if ( elanInstance.getVni() != null && elanInstance.getVni().longValue() != 0 ) {
                     setExternalTunnelTable(dpId, elanInstance);
                 }
-                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+                ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
             } else {
                 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
                 elanInterfaces.add(interfaceName);
                 if (elanInterfaces.size() == 1) {//1st dpn interface
-                    ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+                    ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
                 }
                 updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
             }
@@ -490,7 +498,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
             if( isInterfaceOperational ) {
                 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
-                ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, staticMacAddresses);
+                ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, staticMacAddresses);
             }
         }
     }
@@ -519,11 +527,12 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         if (isOperational(interfaceInfo)) {
 
             // LocalBroadcast Group creation with elan-Interfaces
-            setupElanBroadcastGroups(elanInfo, interfaceInfo);
+            setupElanBroadcastGroups(elanInfo, interfaceInfo.getDpId());
 
             setupLocalBroadcastGroups(elanInfo, interfaceInfo);
             //Terminating Service , UnknownDMAC Table.
             setupTerminateServiceTable(elanInfo, interfaceInfo);
+            ElanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager);
             setupUnknownDMacTable(elanInfo, interfaceInfo);
             setupFilterEqualsTable(elanInfo, interfaceInfo);
             // bind the Elan service to the Interface
@@ -588,9 +597,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return listBuckets;
     }
 
-    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo,
-                                                         InterfaceInfo interfaceInfo, int bucketId) {
-        BigInteger dpnId = interfaceInfo.getDpId();
+    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) {
         int elanTag = elanInfo.getElanTag().intValue();
         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
@@ -667,40 +674,6 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    private void updateRemoteBCGrouponDpnTunnelEvent(ElanInstance elanInfo,
-                                               InterfaceInfo interfaceInfo, BigInteger dstDpId) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
-        List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
-        if(elanDpns != null) {
-            for(DpnInterfaces dpnInterface : elanDpns) {
-                int bucketId = 0;
-                List<Bucket> remoteListBucket = new ArrayList<Bucket>();
-                if(ElanUtils.isDpnPresent(dstDpId) && dpnInterface.getDpId().equals(dstDpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
-                    try {
-                        List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(interfaceInfo.getDpId(), dstDpId, elanTag);
-                        remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-                        bucketId++;
-                    } catch (Exception ex) {
-                        logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), dstDpId);
-                        return;
-                    }
-                    List<Action> remoteListActionInfo = new ArrayList<Action>();
-                    remoteListActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}).buildAction());
-                    remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-
-                    List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dstDpId, bucketId);
-                    remoteListBucket.addAll(elanL2GwDevicesBuckets);
-
-                    Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucket));
-                    mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
-                    break;
-                }
-            }
-        }
-    }
-
-
     /**
      * Returns the bucket info with the given interface as the only bucket.
      */
@@ -842,17 +815,19 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    public void setupElanBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
         List<Bucket> listBucket = new ArrayList<Bucket>();
         int bucketId = 0;
-        BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
 
         DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
         for(String ifName : dpnInterfaces.getInterfaces()) {
             // In case if there is a InterfacePort in the cache which is not in
             // operational state, skip processing it
-            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
+            // FIXME: interfaceType to be obtained dynamically. It doesn't
+            // affect the functionality here as it is nowhere used.
+            InterfaceType interfaceType = InterfaceInfo.InterfaceType.VLAN_INTERFACE;
+            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceType);
             if (!isOperational(ifInfo)) {
                 continue;
             }
@@ -860,11 +835,11 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
         }
-        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, interfaceInfo, bucketId);
+        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnId, bucketId);
         listBucket.addAll(listBucketInfoRemote);
 
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
-        logger.trace("installing the localBroadCast Group:{}", group);
+        logger.trace("installing the remote BroadCast Group:{}", group);
         mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
     }
 
@@ -956,6 +931,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
         String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
         FlowEntity flowEntity = new FlowEntity(dpnId);
+        flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
         flowEntity.setFlowId(flowId);
         mdsalManager.removeFlow(flowEntity);
     }
@@ -999,6 +975,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             // No more Elan Interfaces in this DPN
             logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
             removeDefaultTermFlow(dpId, elanInfo.getElanTag());
+            removeDefaultTermFlow(dpId, interfaceInfo.getInterfaceTag());
             removeUnknownDmacFlow(dpId, elanInfo);
             removeElanBroadcastGroup(elanInfo, interfaceInfo);
             removeLocalBroadcastGroup(elanInfo, interfaceInfo);
@@ -1007,7 +984,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             }
             removeFilterEqualsTable(elanInfo, interfaceInfo);
         } else {
-            setupElanBroadcastGroups(elanInfo, interfaceInfo);
+            setupElanBroadcastGroups(elanInfo, dpId);
             setupLocalBroadcastGroups(elanInfo, interfaceInfo);
             removeFilterEqualsTable(elanInfo, interfaceInfo);
         }
@@ -1144,7 +1121,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         if (interfaceInfo == null) {
             return false;
         }
-        return ((interfaceInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP) && (interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED));
+        return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
     }
 
     protected void updatedIfPrimaryAttributeChanged(ElanInterface elanInterface, boolean isUpdated) {
@@ -1191,9 +1168,8 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    public void handleTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
+    public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
         ElanDpnInterfaces dpnInterfaceLists =  ElanUtils.getElanDpnInterfacesList();
-        Set<String> elanInstancesMap = new HashSet<>();
         if(dpnInterfaceLists == null) {
             return;
         }
@@ -1212,17 +1188,16 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             }
             if(cnt == 2) {
                 logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
+                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+                // update Remote BC Group
+                setupElanBroadcastGroups(elanInfo, srcDpId);
+
                 DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, srcDpId);
                 Set<String> interfaceLists = new HashSet<>();
-                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
                 interfaceLists.addAll(dpnInterface.getInterfaces());
                 for(String ifName : interfaceLists) {
                     InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
                     if (isOperational(interfaceInfo)) {
-                        if (interfaceInfo.getDpId().equals(srcDpId) && !elanInstancesMap.contains(elanDpns.getElanInstanceName())) {
-                            elanInstancesMap.add(elanDpns.getElanInstanceName());
-                            elanInterfaceManager.updateRemoteBCGrouponDpnTunnelEvent(elanInfo, interfaceInfo, dstDpId);
-                        }
                         elanInterfaceManager.installDMacAddressTables(elanInfo, interfaceInfo, dstDpId);
                     }
                 }
@@ -1231,6 +1206,93 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
+    /**
+     * Handle external tunnel state event.
+     *
+     * @param externalTunnel
+     *            the external tunnel
+     * @param intrf
+     *            the interface
+     */
+    public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+        if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
+            return;
+        }
+        // dpId/externalNodeId will be available either in source or destination
+        // based on the tunnel end point
+        BigInteger dpId = null;
+        NodeId externalNodeId = null;
+        if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
+            dpId = new BigInteger(externalTunnel.getSourceDevice());
+            externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
+        } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
+            dpId = new BigInteger(externalTunnel.getDestinationDevice());
+            externalNodeId = new NodeId(externalTunnel.getSourceDevice());
+        }
+        if (dpId == null || externalNodeId == null) {
+            logger.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
+            return;
+        }
+
+        ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
+        if (dpnInterfaceLists == null) {
+            return;
+        }
+        List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
+        for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
+            String elanName = elanDpns.getElanInstanceName();
+            ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+
+            DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+            if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
+                    || dpnInterfaces.getInterfaces().isEmpty()) {
+                continue;
+            }
+            logger.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
+
+            setupElanBroadcastGroups(elanInfo, dpId);
+            // install L2gwDevices local macs in dpn.
+            ElanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo);
+            // Install dpn macs on external device
+            ElanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
+                    externalNodeId);
+        }
+        logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
+    }
+
+    /**
+     * Validate external tunnel state event.
+     *
+     * @param externalTunnel
+     *            the external tunnel
+     * @param intrf
+     *            the intrf
+     * @return true, if successful
+     */
+    private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+        if (intrf.getOperStatus() == Interface.OperStatus.Up) {
+            String srcDevice = externalTunnel.getDestinationDevice();
+            String destDevice = externalTunnel.getSourceDevice();
+            ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
+                    LogicalDatastoreType.CONFIGURATION);
+            if (logger.isTraceEnabled()) {
+                logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
+                        otherEndPointExtTunnel);
+            }
+            if (otherEndPointExtTunnel != null) {
+                boolean otherEndPointInterfaceOperational = ElanUtils
+                        .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
+                if (otherEndPointInterfaceOperational) {
+                    return true;
+                } else {
+                    logger.debug("Other end [{}] of the external tunnel is not yet UP for {}",
+                            otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
+                }
+            }
+        }
+        return false;
+    }
+
     public void handleInterfaceUpdated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
         BigInteger dpId = interfaceInfo.getDpId();
         String elanName = elanInstance.getElanInstanceName();
@@ -1252,6 +1314,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             logger.trace("ElanInterface Service is installed for interface:{}", ifName);
             elanInterfaceManager.installFlowsAndGroups(elanInstance, interfaceInfo);
             elanInterfaceManager.installMacAddressTables(elanInstance, interfaceInfo);
+
+            if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
+                List<PhysAddress> macAddresses = ElanUtils
+                        .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
+                if (macAddresses != null && !macAddresses.isEmpty()) {
+                    ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(),
+                            dpId, macAddresses);
+                }
+            }
         } else {
 
             DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
@@ -1296,81 +1367,21 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return mkMatches;
     }
 
-    public void updateElanBroadcastGroup(ElanInstance elanInfo) {
-        int bucketId = 0;
-        long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
-
-        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo
-                .getElanInstanceName());
+    public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
+        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
         if (dpns == null) {
             return;
         }
         for (DpnInterfaces dpn : dpns) {
-            bucketId = 0;
-            List<Bucket> listBucket = new ArrayList<Bucket>();
-            bucketId = getLocalBcGroupBuckets(dpn, listBucket, bucketId);
-            getRemoteBCGroupBuckets(elanInfo, dpn.getDpId(), listBucket,
-                    bucketId);
-            Group group = MDSALUtil.buildGroup(groupId,
-                    elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
-                    MDSALUtil.buildBucketLists(listBucket));
-            logger.trace("installing the localBroadCast Group:{}", group);
-            mdsalManager.syncInstallGroup(dpn.getDpId(), group,
-                    ElanConstants.DELAY_TIME_IN_MILLISECOND);
-        }
-    }
-
-    private int getLocalBcGroupBuckets(DpnInterfaces dpn,
-            List<Bucket> listBucket, int bucketId) {
-        for (String intf : dpn.getInterfaces()) {
-            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfo(intf);
-            if (!isOperational(ifInfo)) {
-                continue;
-            }
-            listBucket.add(MDSALUtil.buildBucket(
-                    getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT,
-                    bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-            bucketId++;
-        }
-        return bucketId;
-    }
-
-    private void getRemoteBCGroupBuckets(ElanInstance elanInfo,
-            BigInteger dpnId, List<Bucket> listBucket, int bucketId) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        ElanDpnInterfacesList elanDpns = ElanUtils
-                .getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-        if (elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for (DpnInterfaces dpnInterface : dpnInterfaceses) {
-                if (ElanUtils.isDpnPresent(dpnInterface.getDpId())
-                        && dpnInterface.getDpId() != dpnId
-                        && dpnInterface.getInterfaces() != null
-                        && !dpnInterface.getInterfaces().isEmpty()) {
-                    try {
-                        List<Action> listActionInfo = ElanUtils
-                                .getInternalItmEgressAction(dpnId,
-                                        dpnInterface.getDpId(), elanTag);
-                        listBucket.add(MDSALUtil.buildBucket(listActionInfo, 0,
-                                bucketId, 0xffffffffL, 0xffffffffL));
-                        bucketId++;
-                    } catch (Exception ex) {
-                        logger.error(
-                                "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
-                                dpnId, dpnInterface.getDpId());
-                    }
-                }
-            }
+            setupElanBroadcastGroups(elanInfo, dpn.getDpId());
         }
-        List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
-        listBucket.addAll(elanL2GwDevicesBuckets);
     }
 
     public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
             int bucketId) {
         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanInfo.getElanInstanceName());
+                .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
         for (L2GatewayDevice device : map.values()) {
             String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
                     device.getHwvtepNodeId());
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java
new file mode 100644 (file)
index 0000000..1b3bf96
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+    private String key;
+    private ElanInstance elanInfo;
+    private String interfaceName;
+    private InterfaceInfo interfaceInfo;
+    private ElanInterfaceManager dataChangeListener;
+
+    public ElanInterfaceRemoveWorker(String key, ElanInstance elanInfo, String interfaceName,
+            InterfaceInfo interfaceInfo, ElanInterfaceManager dataChangeListener) {
+        super();
+        this.key = key;
+        this.elanInfo = elanInfo;
+        this.interfaceName = interfaceName;
+        this.interfaceInfo = interfaceInfo;
+        this.dataChangeListener = dataChangeListener;
+    }
+
+    @Override
+    public String toString() {
+        return "ElanInterfaceRemoveWorker [key=" + key + ", elanInfo=" + elanInfo +
+                ", interfaceName=" + interfaceName
+                + ", interfaceInfo=" + interfaceInfo + "]";
+    }
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        dataChangeListener.removeElanInterface(elanInfo, interfaceName, interfaceInfo);
+        return futures;
+    }
+
+}
index 470f6237bf29c32222404762844dce3b6a00bc93..f74e4b886a808385e4d9f5f84e26f6b2fa2d9325 100644 (file)
@@ -8,17 +8,20 @@
 package org.opendaylight.vpnservice.elan.internal;
 
 
-import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.List;
+
 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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
@@ -32,9 +35,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.List;
-
 public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
     private DataBroker broker;
     private IInterfaceManager interfaceManager;
@@ -67,24 +67,6 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
         this.interfaceManager = interfaceManager;
     }
 
-    private void handleVlanInterfaceOperationalStateChange(String interfaceName, boolean isStateUp) {
-        //fetching the elanInstanceName from elan-interface config data-store
-        ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
-        if (elanInterface == null) {
-            return;
-        }
-        ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanInterface.getElanInstanceName());
-        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName, 
-                InterfaceInfo.InterfaceType.VLAN_INTERFACE);
-        if (interfaceInfo == null) {
-            logger.warn("Interface {} doesn't exist in operational datastore", interfaceName);
-            return;
-        }
-
-        logger.trace("ElanService Interface Operational state has changes for Interface:{}", interfaceName);
-        elanInterfaceManager.handleInterfaceUpdated(interfaceInfo, elanInfo , isStateUp);
-    }
-
     @Override
     protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
         logger.trace("Received interface {} Down event", delIf);
@@ -100,34 +82,29 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
         interfaceInfo.setInterfaceName(interfaceName);
         interfaceInfo.setInterfaceType(InterfaceInfo.InterfaceType.VLAN_INTERFACE);
         interfaceInfo.setInterfaceTag(delIf.getIfIndex());
-        elanInterfaceManager.removeElanService(elanInterface, interfaceInfo);
+        String elanInstanceName = elanInterface.getElanInstanceName();
+        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        ElanInterfaceRemoveWorker removeWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInstance, 
+                interfaceName, interfaceInfo, elanInterfaceManager);
+        coordinator.enqueueJob(elanInstanceName, removeWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
     @Override
     protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
         logger.trace("Operation Interface update event - Old: {}, New: {}", original, update);
         String interfaceName = update.getName();
+        if (update.getType() == null) {
+            logger.trace("Interface type for interface {} is null", interfaceName);
+            return;
+        }
         if(update.getType().equals(Tunnel.class)) {
             if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
                 InternalTunnel internalTunnel = getTunnelState(interfaceName);
                 if (internalTunnel != null) {
-                    elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+                    elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
                 }
             }
-        } else if(update.getType().equals(L2vlan.class)) {
-            ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
-            if(elanInterface == null) {
-                logger.debug("No Elan Interface is created for the interface:{} ", interfaceName);
-                return;
-            }
-            if (update.getOperStatus().equals(Interface.OperStatus.Up) && update.getAdminStatus() == Interface.AdminStatus.Up) {
-                logger.trace("Operation Status for Interface:{}  event state UP ", interfaceName);
-                handleVlanInterfaceOperationalStateChange(interfaceName, true);
-            } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
-                logger.trace("Operation Status for Interface:{}  event state DOWN ", interfaceName);
-                handleVlanInterfaceOperationalStateChange(interfaceName, false);
-            }
-
         }
     }
 
@@ -141,7 +118,8 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
                 if(intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
                     InternalTunnel internalTunnel = getTunnelState(interfaceName);
                     if (internalTunnel != null) {
-                        elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+                        elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(),
+                                internalTunnel.getDestinationDPN());
                     }
                 }
             }
@@ -159,7 +137,7 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
     public  InternalTunnel getTunnelState(String interfaceName) {
         InternalTunnel internalTunnel = null;
         TunnelList tunnelList = ElanUtils.buildInternalTunnel(broker);
-        if (tunnelList.getInternalTunnel() != null) {
+        if (tunnelList != null && tunnelList.getInternalTunnel() != null) {
             List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
             for (InternalTunnel tunnel : internalTunnels) {
                 if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java
new file mode 100644 (file)
index 0000000..3ce6b9f
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ElanInterfaceStateClusteredListener extends
+        AsyncClusteredDataChangeListenerBase<Interface, ElanInterfaceStateClusteredListener> implements AutoCloseable {
+    private DataBroker broker;
+    private ElanInterfaceManager elanInterfaceManager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceStateClusteredListener.class);
+
+    public ElanInterfaceStateClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+        super(Interface.class, ElanInterfaceStateClusteredListener.class);
+        broker = db;
+        elanInterfaceManager = ifManager;
+        registerListener(db);
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), ElanInterfaceStateClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+        } catch (final Exception e) {
+            logger.error("Elan Interfaces DataChange listener registration fail!", e);
+            throw new IllegalStateException("ElanInterface registration Listener failed.", e);
+        }
+    }
+
+    @Override
+    public InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return ElanInterfaceStateClusteredListener.this;
+    }
+
+    @Override
+    protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.BASE;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, final Interface update) {
+        add(identifier, update);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, final Interface intrf) {
+        if (intrf.getType() != null && intrf.getType().equals(Tunnel.class)) {
+            if (intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
+                final String interfaceName = intrf.getName();
+
+                ElanClusterUtils.runOnlyInLeaderNode(new Runnable() {
+                    @Override
+                    public void run() {
+                        logger.debug("running external tunnel update job for interface {} added", interfaceName);
+                        handleExternalTunnelUpdate(interfaceName, intrf);
+                    }
+                });
+            }
+        }
+    }
+
+    private void handleExternalTunnelUpdate(String interfaceName, Interface update) {
+        ExternalTunnel externalTunnel = ElanUtils.getExternalTunnel(interfaceName, LogicalDatastoreType.CONFIGURATION);
+        if (externalTunnel != null) {
+            logger.debug("handling external tunnel update event for ext device dst {}  src {} ",
+                    externalTunnel.getDestinationDevice(), externalTunnel.getSourceDevice());
+            elanInterfaceManager.handleExternalTunnelStateEvent(externalTunnel, update);
+        } else {
+            logger.trace("External tunnel not found with interfaceName: {}", interfaceName);
+        }
+    }
+}
index dbf83ddc6021537469ddef6649222106c157598b..85ccf597887c45e92715bb59a45660d748fc6001 100755 (executable)
@@ -22,14 +22,11 @@ import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
 import org.opendaylight.vpnservice.mdsalutil.NWUtil;
 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.NoMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.interfacemgr.impl.rev150325.InterfacemgrImpl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.Elan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryBuilder;
@@ -40,9 +37,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import java.math.BigInteger;
+
 import java.util.Arrays;
-import java.util.List;
 
 @SuppressWarnings("deprecation")
 public class ElanPacketInHandler implements PacketProcessingListener {
@@ -134,7 +130,8 @@ public class ElanPacketInHandler implements PacketProcessingListener {
                 ElanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), elanInstance.getMacTimeout(), macAddress);
 
                 BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
-                ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, Arrays.asList(physAddress));
+                ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
+                        Arrays.asList(physAddress));
             } catch (Exception e) {
                 logger.trace("Failed to decode packet: {}", e);
             }
index af817b8595fd34ea60aef5f3c6d60f3a40072efa..6ad3df3b75c2c0e070a19bba1ca76402705de750 100644 (file)
@@ -22,9 +22,11 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.elanmanager.api.IElanService;
 import org.opendaylight.elanmanager.exceptions.MacNotFoundException;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.l2gw.internal.ElanL2GatewayProvider;
 import org.opendaylight.vpnservice.elan.statisitcs.ElanStatisticsImpl;
 import org.opendaylight.vpnservice.elan.statusanddiag.ElanStatusMonitor;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
@@ -59,7 +61,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev1512
 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.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -79,6 +80,8 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
     private ElanPacketInHandler elanPacketInHandler;
     private ElanSmacFlowEventListener elanSmacFlowEventListener;
     private ElanInterfaceStateChangeListener elanInterfaceStateChangeListener;
+    private ElanInterfaceStateClusteredListener infStateChangeClusteredListener;
+    private ElanDpnInterfaceClusteredListener elanDpnInterfaceClusteredListener;
     private ElanNodeListener elanNodeListener;
     private NotificationService notificationService;
     private RpcProviderRegistry rpcProviderRegistry;
@@ -88,9 +91,21 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
     private ElanL2GatewayProvider elanL2GatewayProvider;
 
     private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
 
     private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
+    public static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+        if (dataStoreJobCoordinator == null) {
+            dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+        }
+        return dataStoreJobCoordinator;
+    }
+
 
     public ElanServiceProvider(RpcProviderRegistry rpcRegistry) {
         rpcProviderRegistry = rpcRegistry;
@@ -107,6 +122,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         elanStatusMonitor.reportStatus("STARTING");
         try {
             createIdPool();
+            getDataStoreJobCoordinator();
             broker = session.getSALService(DataBroker.class);
 
             ElanUtils.setDataBroker(broker);
@@ -128,6 +144,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             elanInstanceManager.setDataBroker(broker);
             elanInstanceManager.setIdManager(idManager);
             elanInstanceManager.setElanInterfaceManager(elanInterfaceManager);
+            elanInstanceManager.setInterfaceManager(interfaceManager);
 
 
             elanNodeListener = new ElanNodeListener(broker, mdsalManager);
@@ -150,7 +167,11 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             elanInterfaceStateChangeListener = new ElanInterfaceStateChangeListener(broker, elanInterfaceManager);
             elanInterfaceStateChangeListener.setInterfaceManager(interfaceManager);
 
+            infStateChangeClusteredListener = new ElanInterfaceStateClusteredListener(broker, elanInterfaceManager);
 
+            elanDpnInterfaceClusteredListener = new ElanDpnInterfaceClusteredListener(broker, elanInterfaceManager);
+            ElanClusterUtils.setEntityOwnershipService(entityOwnershipService);
+            ElanClusterUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
             this.elanL2GatewayProvider = new ElanL2GatewayProvider(this);
 
             elanInterfaceManager.registerListener();
@@ -181,10 +202,6 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         this.entityOwnershipService = entityOwnershipService;
     }
 
-    public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
-    }
-
     public IInterfaceManager getInterfaceManager() {
         return this.interfaceManager;
     }
@@ -237,10 +254,6 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         return entityOwnershipService;
     }
 
-    public BindingNormalizedNodeSerializer getBindingNormalizedNodeSerializer() {
-        return bindingNormalizedNodeSerializer;
-    }
-
     private void createIdPool() {
         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
                 .setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE).build();
index 76bdb6e863da34888a828b67fdc2afa3de976388..65068970393207736224a075c245ac669e73712f 100644 (file)
@@ -9,19 +9,26 @@
 package org.opendaylight.vpnservice.elan.l2gw.internal;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
 import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
 import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLocalUcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepNodeListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.L2GatewayConnectionListener;
 import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
 import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.vpnservice.utils.clustering.EntityOwnerUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,7 +41,6 @@ public class ElanL2GatewayProvider implements AutoCloseable {
 
     private DataBroker broker;
     private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ItmRpcService itmRpcService;
     private ElanInstanceManager elanInstanceManager;
     private ElanInterfaceManager elanInterfaceManager;
@@ -42,6 +48,9 @@ public class ElanL2GatewayProvider implements AutoCloseable {
     private L2GatewayConnectionListener l2GwConnListener;
     private HwvtepNodeListener hwvtepNodeListener;
     private HwvtepLocalUcastMacListener torMacsListener;
+    private HwvtepPhysicalLocatorListener physicalLocatorListener;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
 
     /**
      * Instantiates a new elan l2 gateway provider.
@@ -52,11 +61,10 @@ public class ElanL2GatewayProvider implements AutoCloseable {
     public ElanL2GatewayProvider(ElanServiceProvider elanServiceProvider) {
         this.broker = elanServiceProvider.getBroker();
         this.entityOwnershipService = elanServiceProvider.getEntityOwnershipService();
-        this.bindingNormalizedNodeSerializer = elanServiceProvider.getBindingNormalizedNodeSerializer();
         this.itmRpcService = elanServiceProvider.getItmRpcService();
         this.elanInstanceManager = elanServiceProvider.getElanInstanceManager();
         this.elanInterfaceManager = elanServiceProvider.getElanInterfaceManager();
-
+        dataStoreJobCoordinator = elanServiceProvider.getDataStoreJobCoordinator();
         init();
 
         LOG.info("ElanL2GatewayProvider Initialized");
@@ -69,18 +77,33 @@ public class ElanL2GatewayProvider implements AutoCloseable {
         ElanL2GwCacheUtils.createElanL2GwDeviceCache();
         ElanL2GatewayUtils.setDataBroker(broker);
         ElanL2GatewayUtils.setItmRpcService(itmRpcService);
+        ElanL2GatewayUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
 
         ElanL2GatewayMulticastUtils.setBroker(broker);
         ElanL2GatewayMulticastUtils.setElanInstanceManager(elanInstanceManager);
         ElanL2GatewayMulticastUtils.setElanInterfaceManager(elanInterfaceManager);
+        ElanL2GatewayMulticastUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+        L2GatewayConnectionUtils.setElanInstanceManager(elanInstanceManager);
+        L2GatewayConnectionUtils.setBroker(broker);
+        L2GatewayConnectionUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
 
-        this.torMacsListener = new HwvtepLocalUcastMacListener(broker, entityOwnershipService,
-                bindingNormalizedNodeSerializer);
-        this.l2GwConnListener = new L2GatewayConnectionListener(broker, entityOwnershipService,
-                bindingNormalizedNodeSerializer, elanInstanceManager);
-        this.hwvtepNodeListener = new HwvtepNodeListener(broker, entityOwnershipService,
-                bindingNormalizedNodeSerializer, elanInstanceManager, itmRpcService);
+        HwvtepRemoteMcastMacListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+        HwvtepLogicalSwitchListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+        this.torMacsListener = new HwvtepLocalUcastMacListener(broker);
+        this.l2GwConnListener = new L2GatewayConnectionListener(broker, elanInstanceManager);
+        this.hwvtepNodeListener = new HwvtepNodeListener(broker, elanInstanceManager, itmRpcService);
         this.hwvtepNodeListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+
+        physicalLocatorListener = new HwvtepPhysicalLocatorListener(broker);
+        try {
+            EntityOwnerUtils.registerEntityCandidateForOwnerShip(entityOwnershipService,
+                    HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                    null/*listener*/);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.error("failed to register the entity");
+        }
     }
 
     /*
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java
new file mode 100644 (file)
index 0000000..946fb24
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class AssociateHwvtepToElanJob implements Callable<List<ListenableFuture<Void>>> {
+    DataBroker broker;
+    L2GatewayDevice l2GatewayDevice;
+    ElanInstance elanInstance;
+    Devices l2Device;
+    Integer defaultVlan;
+    boolean createLogicalSwitch;
+    private static final Logger LOG = LoggerFactory.getLogger(AssociateHwvtepToElanJob.class);
+
+    public AssociateHwvtepToElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+            Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
+        this.broker = broker;
+        this.l2GatewayDevice = l2GatewayDevice;
+        this.elanInstance = elanInstance;
+        this.l2Device = l2Device;
+        this.defaultVlan = defaultVlan;
+        this.createLogicalSwitch = createLogicalSwitch;
+        LOG.debug("created assosiate l2gw connection job for {} {} ", elanInstance.getElanInstanceName(),
+                l2GatewayDevice.getHwvtepNodeId());
+    }
+
+    public String getJobKey() {
+        return elanInstance.getElanInstanceName();
+    }
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+        String elanInstanceName = elanInstance.getElanInstanceName();
+        LOG.debug("running assosiate l2gw connection job for {} {} ", elanInstanceName, hwvtepNodeId);
+
+        // Create Logical Switch if it's not created already in the device
+        if (createLogicalSwitch) {
+            LOG.info("creating logical switch {} for {} ", elanInstanceName, hwvtepNodeId);
+
+            ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance);
+            futures.add(lsCreateFuture);
+        } else {
+            String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstanceName);
+            LOG.info("{} is already created in {}; adding remaining configurations", logicalSwitchName, hwvtepNodeId);
+
+            LogicalSwitchAddedJob logicalSwitchAddedJob = new LogicalSwitchAddedJob(logicalSwitchName, l2Device,
+                    l2GatewayDevice, defaultVlan);
+            return logicalSwitchAddedJob.call();
+        }
+
+        return futures;
+    }
+
+    private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance) {
+        final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(
+                elanInstance.getElanInstanceName());
+        String segmentationId = elanInstance.getVni().toString();
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("logical switch {} is created on {} with VNI {}", logicalSwitchName,
+                    l2GatewayDevice.getHwvtepNodeId(), segmentationId);
+        }
+        NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+        InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
+        LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
+                elanInstance.getDescription(), segmentationId);
+
+        ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
+        Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void noarg) {
+                // Listener will be closed after all configuration completed
+                // on hwvtep by
+                // listener itself
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
+            }
+        });
+        return lsCreateFuture;
+    }
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java
new file mode 100644 (file)
index 0000000..96170f6
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Job class to delete L2 gateway device local ucast macs from other Elan L2
+ * gateway devices.
+ */
+public class DeleteL2GwDeviceMacsFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+
+    /** The Constant JOB_KEY_PREFIX. */
+    private static final String JOB_KEY_PREFIX = "hwvtep:";
+
+    /** The Constant LOG. */
+    private static final Logger LOG = LoggerFactory.getLogger(DeleteL2GwDeviceMacsFromElanJob.class);
+
+    /** The broker. */
+    private final DataBroker broker;
+
+    /** The elan name. */
+    private final String elanName;
+
+    /** The l2 gw device. */
+    private final L2GatewayDevice l2GwDevice;
+
+    /** The mac addresses. */
+    private final List<MacAddress> macAddresses;
+
+    /**
+     * Instantiates a new delete l2 gw device macs from elan job.
+     *
+     * @param broker
+     *            the broker
+     * @param elanName
+     *            the elan name
+     * @param l2GwDevice
+     *            the l2 gw device
+     * @param macAddresses
+     *            the mac addresses
+     */
+    public DeleteL2GwDeviceMacsFromElanJob(DataBroker broker, String elanName, L2GatewayDevice l2GwDevice,
+            List<MacAddress> macAddresses) {
+        this.broker = broker;
+        this.elanName = elanName;
+        this.l2GwDevice = l2GwDevice;
+        this.macAddresses = macAddresses;
+    }
+
+    public String getJobKey() {
+        return JOB_KEY_PREFIX + this.elanName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public List<ListenableFuture<Void>> call() {
+        LOG.debug("Deleting l2gw device [{}] macs from other l2gw devices for elan [{}]",
+                this.l2GwDevice.getHwvtepNodeId(), this.elanName);
+        final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(this.elanName);
+
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(this.elanName);
+        List<ListenableFuture<Void>> futures = Lists.newArrayList();
+        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+            if (!otherDevice.getHwvtepNodeId().equals(this.l2GwDevice.getHwvtepNodeId())
+                    && !ElanL2GatewayUtils.areMLAGDevices(this.l2GwDevice, otherDevice)) {
+                final String hwvtepId = otherDevice.getHwvtepNodeId();
+                // never batch deletes
+                ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMacs(this.broker,
+                        new NodeId(hwvtepId), logicalSwitchName, this.macAddresses);
+                Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
+                    @Override
+                    public void onSuccess(Void noarg) {
+                        LOG.trace("Successful in initiating ucast_remote_macs deletion related to {} in {}",
+                                logicalSwitchName, hwvtepId);
+                    }
+
+                    @Override
+                    public void onFailure(Throwable error) {
+                        LOG.error(String.format("Failed removing ucast_remote_macs related to %s in %s",
+                                logicalSwitchName, hwvtepId), error);
+                    }
+                });
+                // TODO: why to create a new arraylist for uninstallFuture?
+                futures.addAll(Lists.newArrayList(uninstallFuture));
+            }
+        }
+        return futures;
+    }
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java
new file mode 100644 (file)
index 0000000..49e0c20
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class DisAssociateHwvtepFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+    DataBroker broker;
+    L2GatewayDevice l2GatewayDevice;
+    ElanInstance elanInstance;
+    Devices l2Device;
+    Integer defaultVlan;
+    boolean isLastL2GwConnDeleted;
+
+    private static final Logger LOG = LoggerFactory.getLogger(DisAssociateHwvtepFromElanJob.class);
+
+    public DisAssociateHwvtepFromElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+                                         Devices l2Device, Integer defaultVlan, boolean isLastL2GwConnDeleted) {
+        this.broker = broker;
+        this.l2GatewayDevice = l2GatewayDevice;
+        this.elanInstance = elanInstance;
+        this.l2Device = l2Device;
+        this.defaultVlan = defaultVlan;
+        this.isLastL2GwConnDeleted = isLastL2GwConnDeleted;
+        LOG.info("created disassosiate l2gw connection job for {} {}", elanInstance.getElanInstanceName(),
+                l2GatewayDevice.getHwvtepNodeId());
+    }
+
+    public String getJobKey() {
+        return elanInstance.getElanInstanceName();
+    }
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        String elanName = elanInstance.getElanInstanceName();
+        String strHwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+        NodeId hwvtepNodeId = new NodeId(strHwvtepNodeId);
+        LOG.info("running disassosiate l2gw connection job for {} {}", elanName, strHwvtepNodeId);
+
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+        // Remove remote MACs and vlan mappings from physical port
+        // Once all above configurations are deleted, delete logical
+        // switch
+        LOG.info("delete vlan bindings for {} {}", elanName, strHwvtepNodeId);
+        futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
+
+        if (isLastL2GwConnDeleted) {
+            LOG.info("delete remote ucast macs {} {}", elanName, strHwvtepNodeId);
+            futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
+
+            LOG.info("delete mcast mac for {} {}", elanName, strHwvtepNodeId);
+            futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
+                    l2GatewayDevice));
+
+            LOG.info("delete local ucast macs {} {}", elanName, strHwvtepNodeId);
+            futures.addAll(ElanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+
+            LOG.info("scheduled delete logical switch {} {}", elanName, strHwvtepNodeId);
+            ElanL2GatewayUtils.scheduleDeleteLogicalSwitch(hwvtepNodeId,
+                    ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+        }
+
+        return futures;
+    }
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java
new file mode 100644 (file)
index 0000000..e94d626
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepDeviceMcastMacUpdateJob implements Callable<List<ListenableFuture<Void>>> {
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceMcastMacUpdateJob.class);
+
+    String elanName;
+    L2GatewayDevice l2GatewayDevice;
+
+    public HwvtepDeviceMcastMacUpdateJob(String elanName, L2GatewayDevice l2GatewayDevice) {
+        this.l2GatewayDevice = l2GatewayDevice;
+        this.elanName = elanName;
+    }
+
+    public String getJobKey() {
+        return elanName;
+    }
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        LOG.info("running update mcast mac entry job for {} {}",
+                elanName, l2GatewayDevice.getHwvtepNodeId());
+        return Lists.newArrayList(
+                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevice(elanName, l2GatewayDevice));
+    }
+
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java
new file mode 100644 (file)
index 0000000..7ad1c45
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+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.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Class LogicalSwitchAddedWorker.
+ */
+public class LogicalSwitchAddedJob implements Callable<List<ListenableFuture<Void>>> {
+    /** The logical switch name. */
+    private String logicalSwitchName;
+
+    /** The physical device. */
+    private Devices physicalDevice;
+
+    /** The l2 gateway device. */
+    private L2GatewayDevice elanL2GwDevice;
+
+    /** The default vlan id. */
+    private Integer defaultVlanId;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchAddedJob.class);
+
+    public LogicalSwitchAddedJob(String logicalSwitchName, Devices physicalDevice, L2GatewayDevice l2GatewayDevice,
+            Integer defaultVlanId) {
+        this.logicalSwitchName = logicalSwitchName;
+        this.physicalDevice = physicalDevice;
+        this.elanL2GwDevice = l2GatewayDevice;
+        this.defaultVlanId = defaultVlanId;
+        LOG.debug("created logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+    }
+
+    public String getJobKey() {
+        return logicalSwitchName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        try {
+            LOG.debug("running logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
+
+            LOG.info("creating vlan bindings for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+            futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
+                    new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
+            LOG.info("creating mast mac entries for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+            futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
+
+            List<IpAddress> expectedPhyLocatorIps = Lists.newArrayList();
+            HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
+                    logicalSwitchName, elanL2GwDevice, expectedPhyLocatorIps,
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() {
+                            LOG.info("adding remote ucast macs for {} {}", logicalSwitchName,
+                                    elanL2GwDevice.getHwvtepNodeId());
+                            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                            futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
+                                    logicalSwitchName, elanL2GwDevice));
+                            return futures;
+                        }
+                    });
+
+            return futures;
+        } catch (Throwable e) {
+            LOG.error("failed to add ls ", e);
+            return null;
+        }
+    }
+
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java
new file mode 100644 (file)
index 0000000..f29e409
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * The Class LogicalSwitchDeletedJob.
+ */
+public class LogicalSwitchDeletedJob implements Callable<List<ListenableFuture<Void>>> {
+    private DataBroker broker;
+
+    /** The logical switch name. */
+    private String logicalSwitchName;
+
+    /** The physical device. */
+    private NodeId hwvtepNodeId;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchDeletedJob.class);
+
+    public LogicalSwitchDeletedJob(DataBroker broker, NodeId hwvtepNodeId, String logicalSwitchName) {
+        this.broker = broker;
+        this.hwvtepNodeId = hwvtepNodeId;
+        this.logicalSwitchName = logicalSwitchName;
+        LOG.debug("created logical switch deleted job for {} on {}", logicalSwitchName, hwvtepNodeId);
+    }
+
+    public String getJobKey() {
+        return logicalSwitchName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        try {
+            LOG.debug("running logical switch deleted job for {} in {}", logicalSwitchName, hwvtepNodeId);
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName));
+            return futures;
+        } catch (Throwable e) {
+            LOG.error("failed to delete ls ", e);
+            return null;
+        }
+    }
+}
index c2558fe51b9aa78d8c6492af4b46851bc73cc6eb..d0e9e2e75877f477d5a307c143f7f059b008b728 100644 (file)
@@ -7,29 +7,26 @@
  */
 package org.opendaylight.vpnservice.elan.l2gw.listeners;
 
+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.binding.api.ClusteredDataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
-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.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+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.InstanceIdentifier;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
-import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Lists;
+
 /**
  * A listener for Ucast MAC entries that are added/removed to/from an External Device (e.g., TOR).
  *
@@ -42,19 +39,14 @@ public class HwvtepLocalUcastMacListener extends
         AsyncClusteredDataChangeListenerBase<LocalUcastMacs, HwvtepLocalUcastMacListener> implements AutoCloseable {
 
     private DataBroker broker;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ListenerRegistration<DataChangeListener> lstnerRegistration;
 
     private static final Logger logger = LoggerFactory.getLogger(HwvtepLocalUcastMacListener.class);
 
-    public HwvtepLocalUcastMacListener(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+    public HwvtepLocalUcastMacListener(DataBroker broker) {
         super(LocalUcastMacs.class, HwvtepLocalUcastMacListener.class);
 
         this.broker = broker;
-        this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         registerListener();
     }
 
@@ -103,8 +95,9 @@ public class HwvtepLocalUcastMacListener extends
         // Remove MAC from cache
         elanL2GwDevice.removeUcastLocalMac(macRemoved);
 
-        ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
-                elanL2GwDevice, macRemoved);    }
+        ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elan, elanL2GwDevice,
+                Lists.newArrayList(macRemoved.getMacEntryKey()));
+    }
 
     @Override
     protected void update(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs original,
@@ -136,8 +129,7 @@ public class HwvtepLocalUcastMacListener extends
         // Cache MAC for furthur processing later
         elanL2GwDevice.addUcastLocalMac(macAdded);
 
-        ElanL2GatewayUtils.installL2GwUcastMacInElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
-                elanL2GwDevice, macAddress);
+        ElanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress);
     }
 
     @Override
index 9edbd86294f27b60d2d60d9790b8e2e6452de6b2..a0e4c6680d9f452a7f7346873e78cb971e14b859 100644 (file)
@@ -7,22 +7,16 @@
  */
 package org.opendaylight.vpnservice.elan.l2gw.listeners;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchAddedJob;
 import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
-import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.SystemPropertyReader;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+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.l2gateways.rev150712.l2gateway.attributes.Devices;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
@@ -31,8 +25,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.util.concurrent.ListenableFuture;
-
 /**
  * The listener class for listening to {@code LogicalSwitches}
  * add/delete/update.
@@ -60,6 +52,15 @@ public class HwvtepLogicalSwitchListener
     /** The default vlan id. */
     private Integer defaultVlanId;
 
+    /** Id of L2 Gateway connection responsible for this logical switch creation */
+    private Uuid l2GwConnId;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     /**
      * Instantiates a new hardware vtep logical switch listener.
      *
@@ -71,15 +72,18 @@ public class HwvtepLogicalSwitchListener
      *            the physical device
      * @param defaultVlanId
      *            the default vlan id
+     * @param l2GwConnId
+     *            the l2 gateway connection id
      */
     public HwvtepLogicalSwitchListener(L2GatewayDevice l2GatewayDevice, String logicalSwitchName,
-            Devices physicalDevice, Integer defaultVlanId) {
+            Devices physicalDevice, Integer defaultVlanId, Uuid l2GwConnId) {
         super(LogicalSwitches.class, HwvtepLogicalSwitchListener.class);
         this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
         this.logicalSwitchName = logicalSwitchName;
         this.physicalDevice = physicalDevice;
         this.l2GatewayDevice = l2GatewayDevice;
         this.defaultVlanId = defaultVlanId;
+        this.l2GwConnId = l2GwConnId;
     }
 
     /*
@@ -162,12 +166,12 @@ public class HwvtepLogicalSwitchListener
         LOG.debug("Received Add DataChange Notification for identifier: {}, LogicalSwitches: {}", identifier,
                 logicalSwitchNew);
         try {
-            L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice);
-            DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
-            LogicalSwitchAddedWorker logicalSwitchAddedWorker = new LogicalSwitchAddedWorker(nodeId, logicalSwitchNew);
-            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(),
-                    logicalSwitchNew.getHwvtepNodeName().getValue());
-            jobCoordinator.enqueueJob(jobKey, logicalSwitchAddedWorker,
+            L2GatewayDevice elanDevice = L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(
+                    logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice, l2GwConnId);
+
+            LogicalSwitchAddedJob logicalSwitchAddedWorker = new LogicalSwitchAddedJob(
+                    logicalSwitchName, physicalDevice, elanDevice, defaultVlanId);
+            dataStoreJobCoordinator.enqueueJob(logicalSwitchAddedWorker.getJobKey(), logicalSwitchAddedWorker,
                     SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
 
         } catch (Exception e) {
@@ -185,66 +189,4 @@ public class HwvtepLogicalSwitchListener
         }
     }
 
-    /**
-     * The Class LogicalSwitchAddedWorker.
-     */
-    private class LogicalSwitchAddedWorker implements Callable<List<ListenableFuture<Void>>> {
-        /** The logical switch new. */
-        LogicalSwitches logicalSwitchNew;
-
-        /**
-         * Instantiates a new logical switch added worker.
-         *
-         * @param nodeId
-         *            the node id
-         * @param logicalSwitchNew
-         *            the logical switch new
-         */
-        public LogicalSwitchAddedWorker(NodeId nodeId, LogicalSwitches logicalSwitchNew) {
-            this.logicalSwitchNew = logicalSwitchNew;
-        }
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see java.util.concurrent.Callable#call()
-         */
-        @Override
-        public List<ListenableFuture<Void>> call() throws Exception {
-            try {
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
-                final L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils
-                        .getL2GatewayDeviceFromCache(elan, l2GatewayDevice.getHwvtepNodeId());
-                if (elanL2GwDevice == null) {
-                    LOG.error("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache",
-                            l2GatewayDevice.getHwvtepNodeId());
-                    return null;
-                } else {
-                    LOG.trace("got logical switch device {}", elanL2GwDevice);
-                    futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
-                            new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
-                    futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
-
-                    HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
-                            logicalSwitchName, elanL2GwDevice,
-                            new Callable<List<ListenableFuture<Void>>>() {
-
-                            @Override
-                            public List<ListenableFuture<Void>> call() {
-                                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                                futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
-                                        logicalSwitchName, elanL2GwDevice));
-                                return futures;
-                            }}
-                        );
-                    return futures;
-                }
-            } catch (Throwable e) {
-                LOG.error("failed to add ls ", e);
-                return null;
-            }
-        }
-
-    }
 }
\ No newline at end of file
index 3891246bc8e36237a8ab624ff2c89b2493ebaf6a..1841823039c4f2f3ed850da6470cfc689c98b426 100644 (file)
@@ -12,7 +12,6 @@ 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.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -39,7 +38,6 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.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.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,18 +49,13 @@ public class HwvtepNodeListener
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepNodeListener.class);
 
     private DataBroker dataBroker;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ItmRpcService itmRpcService;
     ElanInstanceManager elanInstanceManager;
 
-    public HwvtepNodeListener(final DataBroker dataBroker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+    public HwvtepNodeListener(final DataBroker dataBroker, ElanInstanceManager elanInstanceManager,
             ItmRpcService itmRpcService) {
         super(Node.class, HwvtepNodeListener.class);
         this.dataBroker = dataBroker;
-        this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         this.itmRpcService = itmRpcService;
         this.elanInstanceManager = elanInstanceManager;
     }
@@ -85,43 +78,63 @@ public class HwvtepNodeListener
 
     @Override
     protected void remove(InstanceIdentifier<Node> key, Node nodeDeleted) {
-        LOG.debug("Received Node Remove Event: {}, {}", key, nodeDeleted.getNodeId().getValue());
+        String nodeId = nodeDeleted.getNodeId().getValue();
+        LOG.debug("Received Node Remove Event for {}", nodeId);
 
         PhysicalSwitchAugmentation psAugmentation = nodeDeleted.getAugmentation(PhysicalSwitchAugmentation.class);
         if (psAugmentation != null) {
             String psName = psAugmentation.getHwvtepNodeName().getValue();
+            LOG.info("Physical switch {} removed from node {} event received", psName, nodeId);
+
             L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
             if (l2GwDevice != null) {
                 if (!L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
                     L2GatewayCacheUtils.removeL2DeviceFromCache(psName);
+                    LOG.debug("{} details removed from L2Gateway Cache", psName);
+                } else {
+                    LOG.debug("{} details are not removed from L2Gateway Cache as it has L2Gateway refrence", psName);
                 }
+
                 l2GwDevice.setConnected(false);
                 ElanL2GwCacheUtils.removeL2GatewayDeviceFromAllElanCache(psName);
             } else {
                 LOG.error("Unable to find L2 Gateway details for {}", psName);
             }
+        } else {
+            LOG.trace("Received Node Remove Event for {} is not related to Physical switch; it's not processed",
+                    nodeId);
         }
     }
 
     @Override
     protected void update(InstanceIdentifier<Node> key, Node nodeBefore, Node nodeAfter) {
-        LOG.debug("Received Node Update Event: {}, {}, {}", key, nodeBefore, nodeAfter);
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Received Node Update Event: Node Before: {}, Node After: {}", nodeBefore, nodeAfter);
+        }
     }
 
     @Override
     protected void add(InstanceIdentifier<Node> key, Node nodeAdded) {
-        LOG.debug("Received Node Add Event: {}, {}", key, nodeAdded.getNodeId().getValue());
+        String nodeId = nodeAdded.getNodeId().getValue();
+        LOG.debug("Received Node Add Event for {}", nodeId);
 
         PhysicalSwitchAugmentation psAugmentation = nodeAdded.getAugmentation(PhysicalSwitchAugmentation.class);
         if (psAugmentation != null) {
             String psName = psAugmentation.getHwvtepNodeName().getValue();
+            LOG.info("Physical switch {} added to node {} event received", psName, nodeId);
+
             L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
             if (l2GwDevice == null) {
+                LOG.debug("{} details are not present in L2Gateway Cache; added now!", psName);
+
                 l2GwDevice = new L2GatewayDevice();
                 l2GwDevice.setDeviceName(psName);
                 L2GatewayCacheUtils.addL2DeviceToCache(psName, l2GwDevice);
+            } else {
+                LOG.debug("{} details are present in L2Gateway Cache and same reference used for updates", psName);
             }
 
+            l2GwDevice.setConnected(true);
             String hwvtepNodeId = getManagedByNodeId(psAugmentation.getManagedBy());
             l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
             List<TunnelIps> tunnelIps = psAugmentation.getTunnelIps();
@@ -130,6 +143,11 @@ public class HwvtepNodeListener
                     IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
                     l2GwDevice.addTunnelIp(tunnelIpAddr);
                     if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("L2Gateway {} associated for {} physical switch; creating ITM tunnels for {}",
+                                    l2GwDevice.getL2GatewayIds(), psName, tunnelIpAddr);
+                        }
+
                         // It's a pre-provision scenario
                         // Initiate ITM tunnel creation
                         ElanL2GatewayUtils.createItmTunnels(itmRpcService, hwvtepNodeId, psName, tunnelIpAddr);
@@ -139,15 +157,25 @@ public class HwvtepNodeListener
                         List<L2gatewayConnection> l2GwConns = getAssociatedL2GwConnections(dataBroker,
                                 l2GwDevice.getL2GatewayIds());
                         if (l2GwConns != null) {
+                            LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
+
                             for (L2gatewayConnection l2GwConn : l2GwConns) {
-                                L2GatewayConnectionUtils.addL2GatewayConnection(dataBroker, entityOwnershipService,
-                                        bindingNormalizedNodeSerializer, elanInstanceManager, l2GwConn, psName);
+                                LOG.trace("L2GatewayConnection {} changes executed on physical switch {}",
+                                        l2GwConn.getL2gatewayId(), psName);
+
+                                L2GatewayConnectionUtils.addL2GatewayConnection(l2GwConn, psName);
                             }
                         }
                         //TODO handle deleted l2gw connections while the device is offline
                     }
                 }
             }
+
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("L2Gateway cache updated with below details: {}", l2GwDevice);
+            }
+        } else {
+            LOG.trace("Received Node Add Event for {} is not related to Physical switch; it's not processed", nodeId);
         }
     }
 
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java
new file mode 100644 (file)
index 0000000..04f6304
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import com.google.common.collect.Lists;
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+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.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * Listener for physical locator presence in operational datastore
+ *
+ *
+ *
+ */
+public class HwvtepPhysicalLocatorListener extends
+        AsyncClusteredDataChangeListenerBase<TerminationPoint, HwvtepPhysicalLocatorListener> implements AutoCloseable {
+
+    private DataBroker broker;
+    private ListenerRegistration<DataChangeListener> lstnerRegistration;
+
+    private static final Logger logger = LoggerFactory.getLogger(HwvtepPhysicalLocatorListener.class);
+
+    public HwvtepPhysicalLocatorListener(DataBroker broker) {
+        super(TerminationPoint.class, HwvtepPhysicalLocatorListener.class);
+
+        this.broker = broker;
+        registerListener();
+        logger.debug("created HwvtepPhysicalLocatorListener");
+    }
+
+    static Map<InstanceIdentifier<TerminationPoint>, List<Runnable>> waitingJobsList = new ConcurrentHashMap<>();
+    static Map<InstanceIdentifier<TerminationPoint>, Boolean> teps = new ConcurrentHashMap<>();
+
+    public static void runJobAfterPhysicalLocatorIsAvialable(InstanceIdentifier<TerminationPoint> key, Runnable runnable) {
+        if (teps.get(key) != null) {
+            logger.debug("physical locator already available {} running job ", key);
+            runnable.run();
+            return;
+        }
+        synchronized (HwvtepPhysicalLocatorListener.class) {
+            List<Runnable> list = waitingJobsList.get(key);
+            if (list == null) {
+                waitingJobsList.put(key, Lists.newArrayList(runnable));
+            } else {
+                list.add(runnable);
+            }
+            logger.debug("added the job to wait list of physical locator {}", key);
+        }
+    }
+
+    protected void registerListener() {
+        try {
+            lstnerRegistration = this.broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+                            child(TerminationPoint.class), this, DataChangeScope.BASE);
+        } catch (final Exception e) {
+            logger.error("Hwvtep LocalUcasMacs DataChange listener registration failed !", e);
+            throw new IllegalStateException("Hwvtep LocalUcasMacs DataChange listener registration failed .", e);
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (lstnerRegistration != null) {
+            try {
+                lstnerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            lstnerRegistration = null;
+        }
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint del) {
+        logger.trace("physical locator removed {}", identifier);
+        teps.remove(identifier);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint original, TerminationPoint update) {
+        logger.trace("physical locator available {}", identifier);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint add) {
+        logger.trace("physical locator available {}", identifier);
+        teps.put(identifier, true);
+        List<Runnable> runnableList = null;
+        synchronized (HwvtepPhysicalLocatorListener.class) {
+            runnableList = waitingJobsList.get(identifier);
+            waitingJobsList.remove(identifier);
+        }
+        if (runnableList != null) {
+            logger.debug("physical locator available {} running jobs ", identifier);
+            for (Runnable r : runnableList) {
+                r.run();
+            }
+        } else {
+            logger.debug("no jobs are waiting for physical locator {}", identifier);
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<TerminationPoint> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+                child(TerminationPoint.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return HwvtepPhysicalLocatorListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return DataChangeScope.BASE;
+    }
+}
index 520462715c07d0d154d367ebeef0ab0567d13618..9f80390e499e1afcda5c342f31259cf38eef5e5b 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.vpnservice.elan.l2gw.listeners;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -23,9 +24,13 @@ import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.SystemPropertyReader;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -50,6 +55,8 @@ public class HwvtepRemoteMcastMacListener
     /** The node id. */
     private NodeId nodeId;
 
+    private List<IpAddress> expectedPhyLocatorIps;
+
     DataBroker broker;
 
     String logicalSwitchName;
@@ -57,37 +64,50 @@ public class HwvtepRemoteMcastMacListener
     AtomicBoolean executeTask = new AtomicBoolean(true);
 
     Callable<List<ListenableFuture<Void>>> taskToRun;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     /**
      * Instantiates a new remote mcast mac listener.
      *
      * @param broker
      *            the mdsal databroker reference
      * @param logicalSwitchName
+     *            the logical switch name
      * @param l2GatewayDevice
      *            the l2 gateway device
+     * @param expectedPhyLocatorIps
+     *            the expected phy locator ips
      * @param task
      *            the task to be run upon data presence
      * @throws Exception
+     *             the exception
      */
     public HwvtepRemoteMcastMacListener(DataBroker broker, String logicalSwitchName, L2GatewayDevice l2GatewayDevice,
-            Callable<List<ListenableFuture<Void>>> task) throws Exception {
+            List<IpAddress> expectedPhyLocatorIps, Callable<List<ListenableFuture<Void>>> task) throws Exception {
         super(RemoteMcastMacs.class, HwvtepRemoteMcastMacListener.class);
         this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
         this.broker = broker;
         this.taskToRun = task;
         this.logicalSwitchName = logicalSwitchName;
-        LOG.debug("registering the listener for mcast mac ");
+        this.expectedPhyLocatorIps = expectedPhyLocatorIps;
+        LOG.info("registering the listener for mcast mac ");
         registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+        LOG.info("registered the listener for mcast mac ");
         if (isDataPresentInOpDs(getWildCardPath())) {
-            LOG.debug("mcast mac already present running the task ");
+            LOG.info("mcast mac already present running the task ");
             if (executeTask.compareAndSet(true, false)) {
                 runTask();
             }
         }
     }
 
-    private boolean isDataPresentInOpDs(InstanceIdentifier<? extends DataObject> path) throws Exception {
-        Optional<? extends DataObject> mac = null;
+    private boolean isDataPresentInOpDs(InstanceIdentifier<RemoteMcastMacs> path) throws Exception {
+        Optional<RemoteMcastMacs> mac = null;
         try {
             mac = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path);
         } catch (Throwable e) {
@@ -95,6 +115,21 @@ public class HwvtepRemoteMcastMacListener
         if (mac == null || !mac.isPresent()) {
             return false;
         }
+        if (this.expectedPhyLocatorIps != null && !this.expectedPhyLocatorIps.isEmpty()) {
+            RemoteMcastMacs remoteMcastMac = mac.get();
+            if (remoteMcastMac.getLocatorSet() == null || remoteMcastMac.getLocatorSet().isEmpty()) {
+                return false;
+            }
+            for (IpAddress ip : this.expectedPhyLocatorIps) {
+                boolean ipExists = ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(this.nodeId,
+                        remoteMcastMac, ip);
+                if (!ipExists) {
+                    LOG.trace("IP [{}] not found in RemoteMcastMacs for node [{}]", String.valueOf(ip.getValue()),
+                            this.nodeId.getValue());
+                    return false;
+                }
+            }
+        }
         return true;
     }
 
@@ -175,8 +210,9 @@ public class HwvtepRemoteMcastMacListener
      */
     @Override
     protected void add(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs mcastMac) {
-        LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
-                mcastMac);
+        LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier, mcastMac);
+        // No isDataPresentInOpDs check is done as assuming all the expected phy
+        // locator ips will be available during add
         if (executeTask.compareAndSet(true, false)) {
             runTask();
         }
@@ -184,9 +220,9 @@ public class HwvtepRemoteMcastMacListener
 
     void runTask() {
         try {
-            DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
-            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), ElanConstants.UNKNOWN_DMAC);
-            jobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+
+            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), nodeId.getValue());
+            dataStoreJobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
         } catch (Exception e) {
             LOG.error("Failed to handle remote mcast mac - add: {}", e);
         } finally {
index 305bb1c0ac161cf752e0178affffc960fbaaf93f..ad6296a9251893579ff929f833378e2136af9f4d 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.vpnservice.elan.l2gw.listeners;
 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.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
 import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
@@ -19,7 +18,6 @@ import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -31,16 +29,11 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListene
 
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker broker;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ElanInstanceManager elanInstanceManager;
 
-    public L2GatewayConnectionListener(final DataBroker db, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager) {
+    public L2GatewayConnectionListener(final DataBroker db, ElanInstanceManager elanInstanceManager) {
         super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
         broker = db;
-        this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         this.elanInstanceManager = elanInstanceManager;
         registerListener(db);
     }
@@ -74,33 +67,30 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListene
     @Override
     protected void add(final InstanceIdentifier<L2gatewayConnection> identifier, final L2gatewayConnection input) {
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Adding L2gatewayConnection : key: " + identifier + ", value=" + input);
+            LOG.trace("Adding L2gatewayConnection: {}", input);
         }
 
         // Get associated L2GwId from 'input'
         // Create logical switch in each of the L2GwDevices part of L2Gw
         // Logical switch name is network UUID
         // Add L2GwDevices to ELAN
-        L2GatewayConnectionUtils.addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
-                elanInstanceManager, input);
+        L2GatewayConnectionUtils.addL2GatewayConnection(input);
     }
 
     @Override
     protected void remove(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection input) {
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Removing L2gatewayConnection : key: " + identifier + ", value=" + input);
+            LOG.trace("Removing L2gatewayConnection: {}", input);
         }
 
-        L2GatewayConnectionUtils.deleteL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
-                elanInstanceManager, input);
+        L2GatewayConnectionUtils.deleteL2GatewayConnection(input);
     }
 
     @Override
     protected void update(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection original,
             L2gatewayConnection update) {
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Updating L2gatewayConnection : key: " + identifier + ", original value=" + original
-                    + ", update value=" + update);
+            LOG.trace("Updating L2gatewayConnection : original value={}, updated value={}", original, update);
         }
     }
 
index 498530cebcb0de178d7a1a8cacff081df00221f7..ca700aadc4e5d1879df38c03dddd9c2acab434cc 100644 (file)
@@ -16,8 +16,10 @@ 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.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
 import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
@@ -36,9 +38,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.DesignatedSwitchesForExternalTunnels;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
@@ -68,6 +70,12 @@ public class ElanL2GatewayMulticastUtils {
     /** The elan interface manager. */
     private static ElanInterfaceManager elanInterfaceManager;
 
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     /**
      * Sets the broker.
      *
@@ -108,7 +116,7 @@ public class ElanL2GatewayMulticastUtils {
      * @return the listenable future
      */
     public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
-        return updateMcastMacs(elanName, device, true/* updateThisDevice */);
+        return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
     }
 
     /**
@@ -124,22 +132,9 @@ public class ElanL2GatewayMulticastUtils {
         SettableFuture<Void> future = SettableFuture.create();
         future.set(null);
         try {
-            ConcurrentMap<String, L2GatewayDevice> mapL2gwDevices = ElanL2GwCacheUtils
-                    .getAllElanL2GatewayDevicesFromCache(elanName);
-            if (mapL2gwDevices == null || mapL2gwDevices.isEmpty()) {
-                LOG.trace("No L2GatewayDevices to configure RemoteMcastMac for elan {}", elanName);
-                return future;
-            }
-            List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
-
-            // TODO revisit
-            L2GatewayDevice firstDevice = mapL2gwDevices.values().iterator().next();
-            List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(firstDevice, dpns);
-            List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(mapL2gwDevices);
-
             WriteTransaction transaction = broker.newWriteOnlyTransaction();
-            for (L2GatewayDevice device : mapL2gwDevices.values()) {
-                updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+            for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
+                prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
             }
             return transaction.submit();
         } catch (Throwable e) {
@@ -148,8 +143,40 @@ public class ElanL2GatewayMulticastUtils {
         return future;
     }
 
+    public static void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
+        HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(elanName,device);
+        dataStoreJobCoordinator.enqueueJob(job.getJobKey(), job);
+    }
+
     /**
-     * Update mcast macs.
+     * Update remote mcast mac on elan l2 gw device.
+     *
+     * @param elanName
+     *            the elan name
+     * @param device
+     *            the device
+     * @return the listenable future
+     */
+    public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
+        WriteTransaction transaction = broker.newWriteOnlyTransaction();
+        prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
+        return transaction.submit();
+    }
+
+    public static void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
+                                                           L2GatewayDevice device) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanName);
+        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+        List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
+        List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
+        preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+    }
+
+    /**
+     * Update mcast macs for this elan.
+     * for all dpns in this elan  recompute and update broadcast group
+     * for all l2gw devices in this elan recompute and update remote mcast mac entry
      *
      * @param elanName
      *            the elan name
@@ -159,19 +186,19 @@ public class ElanL2GatewayMulticastUtils {
      *            the update this device
      * @return the listenable future
      */
-    public static ListenableFuture<Void> updateMcastMacs(String elanName, L2GatewayDevice device,
-            boolean updateThisDevice) {
+    public static ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
+                                                                          boolean updateThisDevice) {
 
         SettableFuture<Void> ft = SettableFuture.create();
         ft.set(null);
 
         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
-        elanInterfaceManager.updateElanBroadcastGroup(elanInstance);
+        elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
 
         List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
 
         ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
 
         List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
         List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
@@ -182,14 +209,14 @@ public class ElanL2GatewayMulticastUtils {
 
         WriteTransaction transaction = broker.newWriteOnlyTransaction();
         if (updateThisDevice) {
-            updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+            preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
         }
 
         // TODO: Need to revisit below logic as logical switches might not be
-        // created to configure RemoteMcastMac entry
+        // present to configure RemoteMcastMac entry
         for (L2GatewayDevice otherDevice : devices.values()) {
             if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
-                updateRemoteMcastMac(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
+                preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
             }
         }
         return transaction.submit();
@@ -211,22 +238,21 @@ public class ElanL2GatewayMulticastUtils {
      *            the l2 gw devices tep ips
      * @return the write transaction
      */
-    private static WriteTransaction updateRemoteMcastMac(WriteTransaction transaction, String elanName,
-            L2GatewayDevice device, List<IpAddress> dpnsTepIps, List<IpAddress> l2GwDevicesTepIps) {
+    private static void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
+                                                    L2GatewayDevice device, List<IpAddress> dpnsTepIps,
+                                                    List<IpAddress> l2GwDevicesTepIps) {
         NodeId nodeId = new NodeId(device.getHwvtepNodeId());
         String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
 
-        ArrayList<IpAddress> otherTepIps = new ArrayList<>(l2GwDevicesTepIps);
-        otherTepIps.remove(device.getTunnelIp());
-
-        if (!dpnsTepIps.isEmpty()) {
-            otherTepIps.addAll(dpnsTepIps);
-        } else {
+        ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
+        remoteTepIps.remove(device.getTunnelIp());
+        remoteTepIps.addAll(dpnsTepIps);
+        if (dpnsTepIps.isEmpty()) {
             // If no dpns in elan, configure dhcp designated switch Tep Ip as a
             // physical locator in l2 gw device
             IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
             if (dhcpDesignatedSwitchTepIp != null) {
-                otherTepIps.add(dhcpDesignatedSwitchTepIp);
+                remoteTepIps.add(dhcpDesignatedSwitchTepIp);
 
                 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
                         .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
@@ -241,10 +267,9 @@ public class ElanL2GatewayMulticastUtils {
             }
         }
 
-        putRemoteMcastMac(transaction, nodeId, logicalSwitchName, otherTepIps);
+        putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
         LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
-                otherTepIps);
-        return transaction;
+                remoteTepIps);
     }
 
     /**
@@ -281,12 +306,10 @@ public class ElanL2GatewayMulticastUtils {
     /**
      * Gets all the tep ips of dpns.
      *
-     * @param device
+     * @param l2GwDevice
      *            the device
      * @param dpns
      *            the dpns
-     * @param devices
-     *            the devices
      * @return the all tep ips of dpns and devices
      */
     private static List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
@@ -327,7 +350,7 @@ public class ElanL2GatewayMulticastUtils {
      */
     public static List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
             L2GatewayDevice l2GatewayDevice) {
-        ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacs(elanInstance.getElanInstanceName(),
+        ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
                 l2GatewayDevice, false/* updateThisDevice */);
         ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
                 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
@@ -374,13 +397,12 @@ public class ElanL2GatewayMulticastUtils {
     public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
             String elanInstanceName) {
         IpAddress tepIp = null;
-     // TODO: Uncomment after DHCP changes are merged
-/*        DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
+        DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
                 elanInstanceName);
         if (desgSwitch != null) {
             tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
                     new NodeId(l2GwDevice.getHwvtepNodeId()));
-        }*/
+        }
         return tepIp;
     }
 
@@ -393,8 +415,7 @@ public class ElanL2GatewayMulticastUtils {
      *            the elan instance name
      * @return the designated switch for external tunnel
      */
-    // TODO: Uncomment after DHCP changes are merged
-/*    public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
+    public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
             String elanInstanceName) {
         InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
                 .builder(DesignatedSwitchesForExternalTunnels.class)
@@ -406,6 +427,6 @@ public class ElanL2GatewayMulticastUtils {
             return designatedSwitchForTunnelOptional.get();
         }
         return null;
-    }*/
+    }
 
 }
index e695055f90ae0e8a0a575dab076398e110af6dfb..4a18a9ae447813949be9e9613cd54a870490848e 100644 (file)
@@ -13,23 +13,29 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 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.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchDeletedJob;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.SystemPropertyReader;
-import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
@@ -40,10 +46,16 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 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.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
@@ -51,15 +63,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.e
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.AddL2GwDeviceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 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.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+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.opendaylight.yangtools.yang.common.RpcResult;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,7 +86,6 @@ import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
 
 /**
  * It gathers a set of utility methods that handle ELAN configuration in external Devices (where external means
@@ -81,9 +97,13 @@ import com.google.common.util.concurrent.SettableFuture;
  *
  */
 public class ElanL2GatewayUtils {
-
-    private static DataBroker         broker;
-    private static ItmRpcService      itmRpcService;
+    private static DataBroker broker;
+    private static ItmRpcService itmRpcService;
+    private static DataStoreJobCoordinator dataStoreJobCoordinator;
+    private static Timer LogicalSwitchDeleteJobTimer = new Timer();
+    private static final int LOGICAL_SWITCH_DELETE_DELAY = 120000;
+    private static ConcurrentMap<Pair<NodeId, String>, TimerTask> LogicalSwitchDeletedTasks =
+            new ConcurrentHashMap<Pair<NodeId, String>, TimerTask>();
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
 
@@ -108,69 +128,21 @@ public class ElanL2GatewayUtils {
     }
 
     /**
-     * Installs the given MAC as a remote mac in all external devices (as of
-     * now, TORs) that participate in the given Elan.
+     * Sets DataStoreJobCoordinator
      *
-     * @param elanInstance
-     *            Elan to which the interface belongs to
-     * @param dpId
-     *            Id of the DPN where the macs are located. Needed for selecting
-     *            the right tunnel
-     * @param macAddresses
-     *            the mac addresses
+     * @param dsJobCoordinator
+     *            the new dataStoreJobCoordinator
      */
-    public static void installMacsInElanExternalDevices(ElanInstance elanInstance, BigInteger dpId,
-            List<PhysAddress> macAddresses) {
-        String logicalSwitchName = getElanFromLogicalSwitch(elanInstance.getElanInstanceName());
-        ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
-        for (L2GatewayDevice externalDevice : elanDevices.values()) {
-            NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
-            IpAddress dpnTepIp = getSourceDpnTepIp(dpId, nodeId);
-            LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
-            if (dpnTepIp == null) {
-                LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
-                continue;
-            }
-            installMacsInExternalDeviceAsRemoteUcastMacs(externalDevice.getHwvtepNodeId(), macAddresses,
-                    logicalSwitchName, dpnTepIp);
-        }
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator dsJobCoordinator) {
+        dataStoreJobCoordinator = dsJobCoordinator;
     }
 
     /**
-     * Installs a list of Mac Addresses as remote Ucast address in an external
-     * device using the hwvtep-southbound.
-     *
-     * @param deviceNodeId
-     *            NodeId if the ExternalDevice where the macs must be installed
-     *            in.
-     * @param macAddresses
-     *            List of Mac addresses to be installed in the external device.
-     * @param logicalSwitchName
-     *            the logical switch name
-     * @param remoteVtepIp
-     *            VTEP's IP in this CSS used for the tunnel with external
-     *            device.
-     */
-    private static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String deviceNodeId,
-            List<PhysAddress> macAddresses, String logicalSwitchName, IpAddress remoteVtepIp) {
-        NodeId nodeId = new NodeId(deviceNodeId);
-        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
-                .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
-        List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
-        for (PhysAddress mac : macAddresses) {
-            // TODO: Query ARP cache to get IP address corresponding to
-            // the MAC
-            IpAddress ipAddress = null;
-            macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
-                    phyLocatorAug));
-        }
-        return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
-    }
-
-    /**
-     * Install macs in external device as remote ucast macs.
-     *
+     * Installs dpn macs in external device.
+     * first it checks if the physical locator towards this dpn tep is present or not
+     * if the physical locator is present go ahead and add the ucast macs
+     * otherwise update the mcast mac entry to include this dpn tep ip
+     * and schedule the job to put ucast macs once the physical locator is programmed in device
      * @param elanName
      *            the elan name
      * @param lstElanInterfaceNames
@@ -179,47 +151,110 @@ public class ElanL2GatewayUtils {
      *            the dpn id
      * @param externalNodeId
      *            the external node id
-     * @return the listenable future
      */
-    public static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String elanName,
-            Set<String> lstElanInterfaceNames, BigInteger dpnId, NodeId externalNodeId) {
-        SettableFuture<Void> future = SettableFuture.create();
-        future.set(null);
-        if (lstElanInterfaceNames == null || lstElanInterfaceNames.isEmpty()) {
-            return future;
+    public static void installDpnMacsInL2gwDevice(String elanName,  Set<String> lstElanInterfaceNames,
+                                                  BigInteger dpnId, NodeId externalNodeId) {
+        L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+                externalNodeId.getValue());
+        if (elanL2GwDevice == null) {
+            LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
+            return;
         }
-
         IpAddress dpnTepIp = getSourceDpnTepIp(dpnId, externalNodeId);
         if (dpnTepIp == null) {
-            return future;
+            LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}",
+                    dpnId, externalNodeId);
+            return;
         }
 
-        WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepUtils.getPhysicalLocator(broker,
-                LogicalDatastoreType.CONFIGURATION, externalNodeId, dpnTepIp);
-        if (phyLocatorAug == null) {
-            phyLocatorAug = HwvtepSouthboundUtils
-                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
-            HwvtepUtils.putPhysicalLocator(transaction, externalNodeId, phyLocatorAug);
+        String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+        RemoteMcastMacs remoteMcastMac = readRemoteMcastMac(externalNodeId, logicalSwitchName,
+                LogicalDatastoreType.OPERATIONAL);
+        boolean phyLocAlreadyExists = checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
+                dpnTepIp);
+        LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
+                phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
+        List<PhysAddress> staticMacs = null;
+        staticMacs = getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
+
+        if (phyLocAlreadyExists) {
+            scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+            return;
         }
+        ElanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
+        scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+    }
 
-        String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+    /**
+     * gets the macs addresses for elan interfaces
+     *
+     * @param lstElanInterfaceNames
+     *            the lst elan interface names
+     * @return the list
+     */
+    private static List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
+        List<PhysAddress> result = new ArrayList<>();
         for (String interfaceName : lstElanInterfaceNames) {
             ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
             if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
                 for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
-                    // TODO: Query ARP cache to get IP address corresponding to
-                    // the MAC
-                    IpAddress ipAddress = null;
-                    RemoteUcastMacs mac = HwvtepSouthboundUtils.createRemoteUcastMac(externalNodeId,
-                            macEntry.getMacAddress().getValue(), ipAddress, logicalSwitchName, phyLocatorAug);
-                    HwvtepUtils.putRemoteUcastMac(transaction, externalNodeId, mac);
+                    result.add(macEntry.getMacAddress());
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Check if phy locator already exists in remote mcast entry.
+     *
+     * @param nodeId
+     *            the node id
+     * @param remoteMcastMac
+     *            the remote mcast mac
+     * @param expectedPhyLocatorIp
+     *            the expected phy locator ip
+     * @return true, if successful
+     */
+    public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
+            RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
+        if (remoteMcastMac != null) {
+            HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
+                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
+            HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
+                    HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
+            if (remoteMcastMac.getLocatorSet() != null) {
+                for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
+                    if (locatorSet.getLocatorRef().equals(expectedPhyLocRef)) {
+                        LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
+                        return true;
+                    }
                 }
             }
         }
-        LOG.debug("Installing macs in external device [{}] for dpn [{}], elan [{}], no of interfaces [{}]",
-                externalNodeId.getValue(), dpnId, elanName, lstElanInterfaceNames.size());
-        return transaction.submit();
+        return false;
+    }
+
+    /**
+     * Gets the remote mcast mac.
+     *
+     * @param nodeId
+     *            the node id
+     * @param logicalSwitchName
+     *            the logical switch name
+     * @param datastoreType
+     *            the datastore type
+     * @return the remote mcast mac
+     */
+    public static RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
+                                                     LogicalDatastoreType datastoreType) {
+        InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
+        RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
+                new MacAddress(ElanConstants.UNKNOWN_DMAC));
+        RemoteMcastMacs remoteMcastMac = HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId,
+                remoteMcastMacsKey);
+        return remoteMcastMac;
     }
 
     /**
@@ -233,7 +268,7 @@ public class ElanL2GatewayUtils {
      */
     public static void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
+                .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
         for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
             removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
                     elanInstance.getElanInstanceName(), macAddresses);
@@ -291,228 +326,244 @@ public class ElanL2GatewayUtils {
      * @param elan
      *            the elan
      */
-    public static void installL2gwDeviceLocalMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
-        String elanName = elan.getElanInstanceName();
-        L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+    public static void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
+        L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
                 l2gwDeviceNodeId.getValue());
         if (l2gwDevice == null) {
             LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
             return;
         }
 
+        installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+    }
+
+    /**
+     * Install dmac flows on dpn.
+     *
+     * @param dpnId
+     *            the dpn id
+     * @param l2gwDevice
+     *            the l2gw device
+     * @param elan
+     *            the elan
+     */
+    public static void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan) {
+        String elanName = elan.getElanInstanceName();
+
         List<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
         if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
             for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
-                ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDeviceNodeId.getValue(), elan.getElanTag(),
+                //TODO batch these ops
+                ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDevice.getHwvtepNodeId(), elan.getElanTag(),
                         elan.getVni(), localUcastMac.getMacEntryKey().getValue(), elanName);
             }
+            LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
+                    l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
         }
-        LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
-                l2gwDeviceNodeId.getValue(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
     }
 
-    public static void installL2GwUcastMacInElan(EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
-            L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
+    /**
+     * Install elan l2gw devices local macs in dpn.
+     *
+     * @param dpnId
+     *            the dpn id
+     * @param elan
+     *            the elan
+     */
+    public static void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elan.getElanInstanceName());
+        if (elanL2GwDevicesFromCache != null) {
+            for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
+                installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+            }
+        } else {
+            LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
+        }
+    }
+
+    public static void installL2GwUcastMacInElan(final ElanInstance elan,
+            final L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
         final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
         final String elanInstanceName = elan.getElanInstanceName();
 
         // Retrieve all participating DPNs in this Elan. Populate this MAC in DMAC table.
         // Looping through all DPNs in order to add/remove mac flows in their DMAC table
-        List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
-        for (DpnInterfaces elanDpn : elanDpns) {
-            final BigInteger dpnId = elanDpn.getDpId();
-            final String nodeId = getNodeIdFromDpnId(dpnId);
-
-            ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                    entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
-            Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                @Override
-                public void onSuccess(Boolean isOwner) {
-                    if (isOwner) {
-                        LOG.info("Installing DMAC flows in {} connected to cluster node owner", dpnId.toString());
-
-                        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                        dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
-                            @Override
-                            public List<ListenableFuture<Void>> call() throws Exception {
-                                return ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId,
-                                        elan.getElanTag(), elan.getVni(), macToBeAdded, elanInstanceName);
+        final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
+        if (elanDpns != null && elanDpns.size() > 0) {
+            String jobKey = elan.getElanInstanceName() + ":" + macToBeAdded;
+            ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+                    "install l2gw mcas in dmac table",
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            List<ListenableFuture<Void>> fts = Lists.newArrayList();
+                            for (DpnInterfaces elanDpn : elanDpns) {
+                                //TODO batch the below call
+                                fts.addAll(ElanUtils.installDmacFlowsToExternalRemoteMac(elanDpn.getDpId(),
+                                        extDeviceNodeId, elan.getElanTag(), elan.getVni(), macToBeAdded,
+                                        elanInstanceName));
                             }
-                        }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                    } else {
-                        LOG.info("Install DMAC flows is not executed on the cluster node as this is not owner " +
-                                    "for the DPN {}", dpnId.toString());
-                    }
-                }
-
-                @Override
-                public void onFailure(Throwable error) {
-                    LOG.error("Failed to install DMAC flows", error);
-                }
-            });
+                            return fts;
+                        }
+                    });
         }
-
         final IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
         final List<PhysAddress> macList = new ArrayList<PhysAddress>();
         macList.add(new PhysAddress(macToBeAdded));
 
-        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
-                ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
-        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
-            if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
-                final String hwvtepId = otherDevice.getHwvtepNodeId();
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+        String jobKey = "hwvtep:"+elan.getElanInstanceName() + ":" + macToBeAdded;
+        ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+                "install remote ucast macs in l2gw device",
+                new Callable<List<ListenableFuture<Void>>>() {
                     @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("Adding DMAC entry in {} connected to cluster node owner", hwvtepId);
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
+                                ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName);
+
+                        List<ListenableFuture<Void>>  fts = Lists.newArrayList();
+                        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+                            if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
+                                    && !areMLAGDevices(extL2GwDevice, otherDevice)) {
+                                final String hwvtepId = otherDevice.getHwvtepNodeId();
+                                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(
+                                        new NodeId(hwvtepId));
+                                final String logicalSwitchName = elanInstanceName;
+
+                                ListenableFuture<Void> ft = HwvtepUtils.installUcastMacs(
+                                        broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
+                                //TODO batch the above call
+                                Futures.addCallback(ft, new FutureCallback<Void>() {
+                                    @Override
+                                    public void onSuccess(Void noarg) {
+                                        LOG.trace("Successful in initiating ucast_remote_macs addition" +
+                                                "related to {} in {}", logicalSwitchName, hwvtepId);
+                                    }
 
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
-                                @Override
-                                public List<ListenableFuture<Void>> call() throws Exception {
-                                    final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
-                                    ListenableFuture<Void> installFuture = installMacsInExternalDeviceAsRemoteUcastMacs(
-                                            hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
-
-                                    Futures.addCallback(installFuture, new FutureCallback<Void>() {
-                                        @Override
-                                        public void onSuccess(Void noarg) {
-                                            if (LOG.isTraceEnabled()) {
-                                                LOG.trace("Successful in initiating ucast_remote_macs addition" +
-                                                        "related to {} in {}", logicalSwitchName, hwvtepId);
-                                            }
-                                        }
-
-                                        @Override
-                                        public void onFailure(Throwable error) {
-                                            LOG.error(String.format("Failed adding ucast_remote_macs related to " +
-                                                    "%s in %s", logicalSwitchName, hwvtepId), error);
-                                        }
-                                    });
-
-                                    return Lists.newArrayList(installFuture);
-                                }
-                            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("DMAC entry addition is not executed on the cluster node as this is not owner for " +
-                                    "the Hwvtep {}", hwvtepId);
+                                    @Override
+                                    public void onFailure(Throwable error) {
+                                        LOG.error(String.format("Failed adding ucast_remote_macs related to " +
+                                                "%s in %s", logicalSwitchName, hwvtepId), error);
+                                    };
+                                });
+                                fts.add(ft);
+                            }
                         }
-                    }
+                        return fts;
+                    }});
+    }
 
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to install DMAC entry", error);
-                    }
-                });
+    /**
+     * Un install l2 gw ucast mac from elan.
+     *
+     * @param elan
+     *            the elan
+     * @param l2GwDevice
+     *            the l2 gw device
+     * @param macAddresses
+     *            the mac addresses
+     */
+    public static void unInstallL2GwUcastMacFromElan(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
+            final List<MacAddress> macAddresses) {
+        if (macAddresses == null || macAddresses.isEmpty()) {
+            return;
+        }
+        final String elanName = elan.getElanInstanceName();
+
+        // Retrieve all participating DPNs in this Elan. Populate this MAC in
+        // DMAC table. Looping through all DPNs in order to add/remove mac flows
+        // in their DMAC table
+        for (final MacAddress mac : macAddresses) {
+            final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+            if (elanDpns != null && !elanDpns.isEmpty()) {
+                String jobKey = elanName + ":" + mac.getValue();
+                ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            @Override
+                            public List<ListenableFuture<Void>> call() {
+                                List<ListenableFuture<Void>> fts = Lists.newArrayList();
+                                for (DpnInterfaces elanDpn : elanDpns) {
+                                    BigInteger dpnId = elanDpn.getDpId();
+                                    // never batch deletes
+                                    fts.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+                                            l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+                                }
+                                return fts;
+                            }
+                        });
             }
         }
-    }
 
-    public static void unInstallL2GwUcastMacFromElan(EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
-            L2GatewayDevice extL2GwDevice, final LocalUcastMacs macToBeRemoved) {
-        final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
-        final String elanInstanceName = elan.getElanInstanceName();
+        DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(broker, elanName, l2GwDevice,
+                macAddresses);
+        ElanClusterUtils.runOnlyInLeaderNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
+    }
 
-        // Retrieve all participating DPNs in this Elan. Populate this MAC in DMAC table.
-        // Looping through all DPNs in order to add/remove mac flows in their DMAC table
-        List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
-        for (DpnInterfaces elanDpn : elanDpns) {
-            final BigInteger dpnId = elanDpn.getDpId();
-            final String nodeId = getNodeIdFromDpnId(dpnId);
-
-            ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                    entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
-            Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                @Override
-                public void onSuccess(Boolean isOwner) {
-                    if (isOwner) {
-                        LOG.info("Uninstalling DMAC flows from {} connected to cluster node owner",
-                                dpnId.toString());
+    /**
+     * Delete elan l2 gateway devices ucast local macs from dpn.
+     *
+     * @param elanName
+     *            the elan name
+     * @param dpnId
+     *            the dpn id
+     */
+    public static void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
+        if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
+            LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
+            return;
+        }
+        final ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
+        if (elan == null) {
+            LOG.error("Could not find Elan by name: {}", elanName);
+            return;
+        }
+        LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
+
+        final Long elanTag = elan.getElanTag();
+        for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
+            List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GwDevice);
+            if (localMacs != null && !localMacs.isEmpty()) {
+                for (final MacAddress mac : localMacs) {
+                    String jobKey = elanName + ":" + mac.getValue();
+                    ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+                            new Callable<List<ListenableFuture<Void>>>() {
+                                @Override
+                                public List<ListenableFuture<Void>> call() {
+                                    List<ListenableFuture<Void>> futures = Lists.newArrayList();
 
-                        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                        dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
-                            @Override
-                            public List<ListenableFuture<Void>> call() throws Exception {
-                                return ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
-                                        extDeviceNodeId, macToBeRemoved.getMacEntryKey().getValue());
-                            }
-                        }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                    } else {
-                        LOG.info("Uninstall DMAC flows is not executed on the cluster node as this is not owner " +
-                                    "for the DPN {}", dpnId.toString());
-                    }
+                                    futures.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
+                                            l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+                                    return futures;
+                                }
+                            });
                 }
+            }
+        }
+    }
 
+    /**
+     * Gets the l2 gw device local macs.
+     *
+     * @param l2gwDevice
+     *            the l2gw device
+     * @return the l2 gw device local macs
+     */
+    public static List<MacAddress> getL2GwDeviceLocalMacs(L2GatewayDevice l2gwDevice) {
+        List<MacAddress> macs = new ArrayList<>();
+        if (l2gwDevice == null) {
+            return macs;
+        }
+        List<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
+        if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) {
+            macs = Lists.transform(lstUcastLocalMacs, new Function<LocalUcastMacs, MacAddress>() {
                 @Override
-                public void onFailure(Throwable error) {
-                    LOG.error("Failed to uninstall DMAC flows", error);
+                public MacAddress apply(LocalUcastMacs localUcastMac) {
+                    return (localUcastMac != null) ? localUcastMac.getMacEntryKey() : null;
                 }
             });
         }
-
-        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
-                ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
-        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
-            if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
-                final String hwvtepId = otherDevice.getHwvtepNodeId();
-                final NodeId hwvtepNodeId = new NodeId(hwvtepId);
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(hwvtepNodeId);
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                    @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("Removing DMAC entry from {} connected to cluster node owner", hwvtepId);
-
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
-                                @Override
-                                public List<ListenableFuture<Void>> call() throws Exception {
-                                    final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
-                                    ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMac(broker,
-                                            hwvtepNodeId, logicalSwitchName, macToBeRemoved.getMacEntryKey());
-
-                                    Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
-                                        @Override
-                                        public void onSuccess(Void noarg) {
-                                            if (LOG.isTraceEnabled()) {
-                                                LOG.trace("Successful in initiating ucast_remote_macs deletion " +
-                                                        "related to {} in {}", logicalSwitchName, hwvtepId);
-                                            }
-                                        }
-
-                                        @Override
-                                        public void onFailure(Throwable error) {
-                                            LOG.error(String.format("Failed removing ucast_remote_macs related " +
-                                                    "to %s in %s", logicalSwitchName, hwvtepId), error);
-                                        }
-                                    });
-
-                                    return Lists.newArrayList(uninstallFuture);
-                                }
-                            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("DMAC entry removal is not executed on the cluster node as this is not owner for " +
-                                    "the Hwvtep {}", hwvtepId);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to uninstall DMAC entry", error);
-                    }
-                });
-            }
-        }
+        return macs;
     }
 
     /**
@@ -574,7 +625,7 @@ public class ElanL2GatewayUtils {
         List<MacAddress> lstL2GatewayDeviceMacs = new ArrayList<>();
 
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
         if (elanL2GwDevicesFromCache != null) {
             for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
                 if (!otherDevice.getHwvtepNodeId().equals(l2GwDeviceToBeExcluded.getHwvtepNodeId())) {
@@ -611,9 +662,9 @@ public class ElanL2GatewayUtils {
         String logicalSwitchName = getLogicalSwitchFromElan(elanName);
         NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
 
-        List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(elanName,
+        List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName,
                 l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
-        List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesAsRemoteUcastMacs(elanName,
+        List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
                 l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
 
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
@@ -639,11 +690,12 @@ public class ElanL2GatewayUtils {
      *            the logical switch name
      * @return the l2 gateway devices macs as remote ucast macs
      */
-    public static List<RemoteUcastMacs> getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(String elanName,
-            L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+    public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
+                                                            L2GatewayDevice l2GatewayDeviceToBeConfigured,
+                                                            NodeId hwVtepNodeId, String logicalSwitchName) {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
 
         if (elanL2GwDevicesFromCache != null) {
             for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
@@ -699,8 +751,9 @@ public class ElanL2GatewayUtils {
      *            the logical switch name
      * @return the elan mac table entries as remote ucast macs
      */
-    public static List<RemoteUcastMacs> getElanMacTableEntriesAsRemoteUcastMacs(String elanName,
-            L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+    public static List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
+                                                                   L2GatewayDevice l2GatewayDeviceToBeConfigured,
+                                                                   NodeId hwVtepNodeId, String logicalSwitchName) {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
 
         MacTable macTable = ElanUtils.getElanMacTable(elanName);
@@ -744,11 +797,12 @@ public class ElanL2GatewayUtils {
      * @return the external tunnel interface name
      */
     public static String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         String tunnelInterfaceName = null;
         try {
             Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
                     .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
-                            .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+                            .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
 
             RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
             if (rpcResult.isSuccessful()) {
@@ -913,7 +967,7 @@ public class ElanL2GatewayUtils {
      * @return the l2 gateway connection job key
      */
     public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
-        return new StringBuilder(nodeId).append(logicalSwitchName).toString();
+        return logicalSwitchName;
     }
 
     public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
@@ -944,45 +998,19 @@ public class ElanL2GatewayUtils {
      *            the elan name
      * @return the listenable future
      */
-    public static List<ListenableFuture<Void>> deleteL2GatewayDeviceUcastLocalMacsFromElan(
-            L2GatewayDevice l2GatewayDevice, String elanName) {
-        List<ListenableFuture<Void>> futures = new ArrayList<>();
+    public static List<ListenableFuture<Void>> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
+            String elanName) {
+        LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(), elanName);
 
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
         ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
             return futures;
         }
 
-        List<LocalUcastMacs> lstLocalUcastMacs = l2GatewayDevice.getUcastLocalMacs();
-        if (lstLocalUcastMacs != null) {
-            for (LocalUcastMacs localUcastMac : lstLocalUcastMacs) {
-                List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
-                if (dpnInterfaces != null) {
-                    // TODO: Need to check if it can be optimized
-                    for (DpnInterfaces elanDpn : dpnInterfaces) {
-                        ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), elanDpn.getDpId(),
-                                l2GatewayDevice.getHwvtepNodeId(), localUcastMac.getMacEntryKey().getValue());
-                    }
-                }
-            }
-
-            List<MacAddress> lstMac = Lists.transform(lstLocalUcastMacs, new Function<LocalUcastMacs, MacAddress>() {
-                @Override
-                public MacAddress apply(LocalUcastMacs mac) {
-                    return (mac != null) ? mac.getMacEntryKey() : null;
-                }
-            });
-
-            ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
-                    .getAllElanL2GatewayDevicesFromCache(elanName);
-            for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
-                if (!otherDevice.getHwvtepNodeId().equals(l2GatewayDevice.getHwvtepNodeId())) {
-                    futures.add(HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(otherDevice.getHwvtepNodeId()),
-                            elanName, lstMac));
-                }
-            }
-        }
+        List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GatewayDevice);
+        unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs);
         return futures;
     }
 
@@ -1009,4 +1037,62 @@ public class ElanL2GatewayUtils {
         return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
     }
 
+    public static void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
+                                                     List<PhysAddress> staticMacAddresses) {
+        ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanName);
+        for (final L2GatewayDevice externalDevice : elanDevices.values()) {
+            scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
+        }
+    }
+
+    public static void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
+                                                     final List<PhysAddress> staticMacAddresses,
+                                                     final L2GatewayDevice externalDevice) {
+        NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
+        final IpAddress dpnTepIp = ElanL2GatewayUtils.getSourceDpnTepIp(dpId, nodeId);
+        LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
+        if (dpnTepIp == null) {
+            LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
+            return;
+        }
+        TerminationPointKey tpKey = HwvtepSouthboundUtils.getTerminationPointKey(
+                dpnTepIp.getIpv4Address().getValue());
+        InstanceIdentifier<TerminationPoint> tpPath = HwvtepSouthboundUtils.createTerminationPointId
+                (nodeId, tpKey);
+
+        HwvtepPhysicalLocatorListener.runJobAfterPhysicalLocatorIsAvialable(tpPath, new Runnable() {
+            @Override
+            public void run() {
+                HwvtepUtils.installUcastMacs(broker,
+                        externalDevice.getHwvtepNodeId(), staticMacAddresses,
+                        elanName, dpnTepIp);
+            }
+        });
+    }
+
+    public static void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+        TimerTask logicalSwitchDeleteTask = new TimerTask() {
+            @Override
+            public void run() {
+                LogicalSwitchDeletedJob logicalSwitchDeletedJob = new LogicalSwitchDeletedJob(broker, hwvtepNodeId,
+                        lsName);
+                ElanL2GatewayUtils.dataStoreJobCoordinator.enqueueJob(logicalSwitchDeletedJob.getJobKey(),
+                        logicalSwitchDeletedJob, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+            }
+        };
+        Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+        LogicalSwitchDeletedTasks.putIfAbsent(nodeIdLogicalSwitchNamePair, logicalSwitchDeleteTask);
+        LogicalSwitchDeleteJobTimer.schedule(logicalSwitchDeleteTask, LOGICAL_SWITCH_DELETE_DELAY);
+    }
+
+    public static void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+        Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+        TimerTask logicalSwitchDeleteTask = LogicalSwitchDeletedTasks.get(nodeIdLogicalSwitchNamePair);
+        if (logicalSwitchDeleteTask != null) {
+            LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
+            logicalSwitchDeleteTask.cancel();
+            LogicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
+        }
+    }
 }
index be0012f47b899f0f27d86dbae8550271d48095ad..688fd151d8ac5f5f0ff9930b457ad908269b57f1 100644 (file)
@@ -8,26 +8,20 @@
 
 package org.opendaylight.vpnservice.elan.l2gw.utils;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Callable;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.AssociateHwvtepToElanJob;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DisAssociateHwvtepFromElanJob;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
-import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
-import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
-import org.opendaylight.vpnservice.utils.SystemPropertyReader;
-import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
 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.l2gateways.rev150712.l2gateway.attributes.Devices;
@@ -37,24 +31,35 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev15071
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gateway;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gatewayKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 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.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 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.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 
 public class L2GatewayConnectionUtils {
     private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionUtils.class);
 
+    private static DataBroker broker;
+    private static ElanInstanceManager elanInstanceManager;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
+    public static void setBroker(DataBroker broker) {
+        L2GatewayConnectionUtils.broker = broker;
+    }
+
+    public static void setElanInstanceManager(ElanInstanceManager elanInstanceManager) {
+        L2GatewayConnectionUtils.elanInstanceManager = elanInstanceManager;
+    }
+
     public static boolean isGatewayAssociatedToL2Device(L2GatewayDevice l2GwDevice) {
         return (l2GwDevice.getL2GatewayIds().size() > 0);
     }
@@ -90,16 +95,13 @@ public class L2GatewayConnectionUtils {
         return null;
     }
 
-    public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
-            L2gatewayConnection input) {
-        addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstanceManager,
-                input, null);
+    public static void addL2GatewayConnection(L2gatewayConnection input) {
+        addL2GatewayConnection(input, null/*deviceName*/);
     }
 
-    public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
-            L2gatewayConnection input, String l2GwDeviceName) {
+    public static void addL2GatewayConnection(L2gatewayConnection input, String l2GwDeviceName) {
+        LOG.info("Adding L2gateway Connection with ID: {}", input.getKey().getUuid());
+
         Uuid networkUuid = input.getNetworkId();
         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
         if (elanInstance == null || elanInstance.getVni() == null) {
@@ -110,15 +112,14 @@ public class L2GatewayConnectionUtils {
             if (l2Gateway == null) {
                 LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
             } else {
-                associateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
-                        l2Gateway, input.getSegmentId(), l2GwDeviceName);
+                associateHwvtepsToElan(elanInstance, l2Gateway, input, l2GwDeviceName);
             }
         }
     }
 
-    public static void deleteL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
-            L2gatewayConnection input) {
+    public static void deleteL2GatewayConnection(L2gatewayConnection input) {
+        LOG.info("Deleting L2gateway Connection with ID: {}", input.getKey().getUuid());
+
         Uuid networkUuid = input.getNetworkId();
         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
         if (elanInstance == null) {
@@ -129,269 +130,130 @@ public class L2GatewayConnectionUtils {
             if (l2Gateway == null) {
                 LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
             } else {
-                disAssociateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
-                        l2Gateway, input.getSegmentId());
+                disAssociateHwvtepsFromElan(elanInstance, l2Gateway, input);
             }
         }
     }
 
-    private static void disAssociateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
-            L2gateway l2Gateway, final Integer defaultVlan) {
-        final String elanName = elanInstance.getElanInstanceName();
+    private static void disAssociateHwvtepsFromElan(ElanInstance elanInstance, L2gateway l2Gateway,
+            L2gatewayConnection input) {
+        String elanName = elanInstance.getElanInstanceName();
+        Integer defaultVlan = input.getSegmentId();
         List<Devices> l2Devices = l2Gateway.getDevices();
-        for (final Devices l2Device : l2Devices) {
-            final String l2DeviceName = l2Device.getDeviceName();
-            final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+        for (Devices l2Device : l2Devices) {
+            String l2DeviceName = l2Device.getDeviceName();
+            L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
             if (isL2GwDeviceConnected(l2GatewayDevice)) {//TODO handle delete while device is offline
                 // Delete L2 Gateway device from 'ElanL2GwDevice' cache
-                ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, l2GatewayDevice.getHwvtepNodeId());
-
-                final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                    @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("L2 Gateway device delete is triggered for {} connected to cluster owner node",
-                                    l2DeviceName);
-
-                            // Create DataStoreJobCoordinator jobs to create Logical
-                            // switches on all physical switches
-                            // which are part of L2 Gateway
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            DisAssociateHwvtepFromElan disAssociateHwvtepToElan = new DisAssociateHwvtepFromElan(broker,
-                                    l2GatewayDevice, elanInstance, l2Device, defaultVlan);
-                            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
-                            dataStoreCoordinator.enqueueJob(jobKey, disAssociateHwvtepToElan,
-                                    SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("L2 Gateway device delete is not triggered on the cluster node as this is not " +
-                                    "owner for {}", l2DeviceName);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to trigger L2 Gateway device delete action", error);
-                    }
-                });
+                String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+                boolean isLastL2GwConnDeleted = false;
+                L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+                if (isLastL2GwConnBeingDeleted(elanL2GwDevice)) {
+                    LOG.debug("Elan L2Gw Conn cache removed for id {}", hwvtepNodeId);
+                    ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+                    isLastL2GwConnDeleted = true;
+                } else {
+                    Uuid l2GwConnId = input.getKey().getUuid();
+                    LOG.debug("Elan L2Gw Conn cache with id {} is being referred by other L2Gw Conns; so only " +
+                            "L2 Gw Conn {} reference is removed", hwvtepNodeId, l2GwConnId);
+                    elanL2GwDevice.removeL2GatewayId(l2GwConnId);
+                }
+
+                DisAssociateHwvtepFromElanJob disAssociateHwvtepToElanJob = new DisAssociateHwvtepFromElanJob(broker,
+                        elanL2GwDevice, elanInstance, l2Device, defaultVlan, isLastL2GwConnDeleted);
+                ElanClusterUtils.runOnlyInLeaderNode(disAssociateHwvtepToElanJob.getJobKey(),
+                        "remove l2gw connection job ",
+                        disAssociateHwvtepToElanJob);
             } else {
-                LOG.error("could not handle connection delete L2 Gateway device with id {} is not present",
-                        l2DeviceName);
+                LOG.info("L2GwConn delete is not handled for device with id {} as it's not connected", l2DeviceName);
             }
         }
     }
 
-    private static void associateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
-            L2gateway l2Gateway, final Integer defaultVlan, String l2GwDeviceName) {
-        final String elanName = elanInstance.getElanInstanceName();
+    private static void associateHwvtepsToElan(ElanInstance elanInstance,
+            L2gateway l2Gateway, L2gatewayConnection input, String l2GwDeviceName) {
+        String elanName = elanInstance.getElanInstanceName();
+        Integer defaultVlan = input.getSegmentId();
+        Uuid l2GwConnId = input.getKey().getUuid();
         List<Devices> l2Devices = l2Gateway.getDevices();
-        for (final Devices l2Device : l2Devices) {
-            final String l2DeviceName = l2Device.getDeviceName();
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Associating ELAN {} with L2Gw Conn Id {} having below L2Gw devices {}", elanName, l2GwConnId,
+                    l2Devices);
+        }
+
+        for (Devices l2Device : l2Devices) {
+            String l2DeviceName = l2Device.getDeviceName();
             // L2gateway can have more than one L2 Gw devices. Configure Logical Switch, VLAN mappings,...
             // only on the switch which has come up just now and exclude all other devices from
             // preprovisioning/re-provisioning
             if (l2GwDeviceName != null && !l2GwDeviceName.equals(l2DeviceName)) {
+                LOG.debug("Associating Hwvtep to ELAN is not been processed for {}; as only {} got connected now!",
+                        l2DeviceName, l2GwDeviceName);
                 continue;
             }
-            final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+            L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
             if (isL2GwDeviceConnected(l2GatewayDevice)) {
+                NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+
+                // Delete pending delete logical switch task if scheduled
+                ElanL2GatewayUtils.cancelDeleteLogicalSwitch(hwvtepNodeId,
+                        ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+
                 // Add L2 Gateway device to 'ElanL2GwDevice' cache
-                final boolean createLogicalSwitch;
+                boolean createLogicalSwitch;
                 LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
-                        new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
+                        hwvtepNodeId, elanName);
                 if (logicalSwitch == null) {
-                    final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
-                            l2GatewayDevice, elanName, l2Device, defaultVlan);
+                    HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
+                            l2GatewayDevice, elanName, l2Device, defaultVlan, l2GwConnId);
                     hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
                     createLogicalSwitch = true;
                 } else {
-                    addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice);
+                    addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice, l2GwConnId);
                     createLogicalSwitch = false;
                 }
-                final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                    @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("Creating Logical switch on {} connected to cluster owner node", l2DeviceName);
-
-                            // Create DataStoreJobCoordinator jobs to create Logical
-                            // switches on all physical switches
-                            // which are part of L2 Gateway
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            AssociateHwvtepToElan associateHwvtepToElan = new AssociateHwvtepToElan(broker,
-                                    l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
-                            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
-                            dataStoreCoordinator.enqueueJob(jobKey, associateHwvtepToElan,
-                                    SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("Logical switch creation is not triggered on the cluster node as this is not " +
-                                    "owner for {}", l2DeviceName);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to trigger Logical switch creation action", error);
-                    }
-                });
-            } else {
-                LOG.error("L2 Gateway device with id {} is not present", l2DeviceName);
-            }
-        }
-    }
-
-    public static void addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice) {
-        L2GatewayDevice elanL2GwDevice = new L2GatewayDevice();
-        elanL2GwDevice.setHwvtepNodeId(l2GatewayDevice.getHwvtepNodeId());
-        elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
-        elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
-        ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
-    }
-
-    private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
-        return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
-    }
-
-    private static class AssociateHwvtepToElan implements Callable<List<ListenableFuture<Void>>> {
-        DataBroker broker;
-        L2GatewayDevice l2GatewayDevice;
-        ElanInstance elanInstance;
-        Devices l2Device;
-        Integer defaultVlan;
-        boolean createLogicalSwitch;
-
-        public AssociateHwvtepToElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
-                Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
-            this.broker = broker;
-            this.l2GatewayDevice = l2GatewayDevice;
-            this.elanInstance = elanInstance;
-            this.l2Device = l2Device;
-            this.defaultVlan = defaultVlan;
-            this.createLogicalSwitch = createLogicalSwitch;
-        }
-
-        @Override
-        public List<ListenableFuture<Void>> call() throws Exception {
-            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                AssociateHwvtepToElanJob associateHwvtepToElanJob = new AssociateHwvtepToElanJob(broker,
+                        l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
 
-            final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
+                ElanClusterUtils.runOnlyInLeaderNode( associateHwvtepToElanJob.getJobKey() ,
+                        "create logical switch in hwvtep topo",
+                        associateHwvtepToElanJob);
 
-            // Create Logical Switch if it's not created already in
-            // the device
-            if (createLogicalSwitch) {
-                ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance, l2Device);
-                futures.add(lsCreateFuture);
             } else {
-                // Logical switch is already created; do the rest of
-                // configuration
-                futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
-                        new NodeId(l2GatewayDevice.getHwvtepNodeId()), logicalSwitchName, l2Device, defaultVlan));
-                futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, l2GatewayDevice));
-                HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
-                        logicalSwitchName, l2GatewayDevice,
-                        new Callable<List<ListenableFuture<Void>>>() {
-
-                        @Override
-                        public List<ListenableFuture<Void>> call() {
-                            List<ListenableFuture<Void>> futures = new ArrayList<>();
-                            futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
-                                    logicalSwitchName, l2GatewayDevice));
-                            return futures;
-                        }}
-                    );
+                LOG.info("L2GwConn create is not handled for device with id {} as it's not connected", l2DeviceName);
             }
-
-            return futures;
         }
+    }
 
-        private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
-                Devices l2Device) {
-            final String logicalSwitchName = ElanL2GatewayUtils
-                    .getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
-            String segmentationId = elanInstance.getVni().toString();
-
-            // Register for Logical switch update in opearational DS
-            final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
-                    l2GatewayDevice, logicalSwitchName, l2Device, defaultVlan);
-            hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
-
-            NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
-            InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
-                    .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
-            LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
-                    elanInstance.getDescription(), segmentationId);
-
-            ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
-            Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
-                @Override
-                public void onSuccess(Void noarg) {
-                    // Listener will be closed after all configuration completed
-                    // on hwvtep by
-                    // listener itself
-                    if (LOG.isTraceEnabled()) {
-                        LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
-                    }
-                }
+    public static L2GatewayDevice addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice,
+            Uuid l2GwConnId) {
+        String l2gwDeviceNodeId = l2GatewayDevice.getHwvtepNodeId();
+        L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, l2gwDeviceNodeId);
+        if (elanL2GwDevice == null) {
+            elanL2GwDevice = new L2GatewayDevice();
+            elanL2GwDevice.setHwvtepNodeId(l2gwDeviceNodeId);
+            elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
+            elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
+            ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
+            LOG.debug("Elan L2GwConn cache created for hwvtep id {}", l2gwDeviceNodeId);
+        } else {
+            LOG.debug("Elan L2GwConn cache already exists for hwvtep id {}; updating L2GwConn id {} to it",
+                    l2gwDeviceNodeId, l2GwConnId);
+        }
+        elanL2GwDevice.addL2GatewayId(l2GwConnId);
 
-                @Override
-                public void onFailure(Throwable error) {
-                    LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
-                    try {
-                        hwVTEPLogicalSwitchListener.close();
-                    } catch (final Exception e) {
-                        LOG.error("Error when cleaning up DataChangeListener.", e);
-                    }
-                }
-            });
-            return lsCreateFuture;
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Elan L2GwConn cache updated with below details: {}", elanL2GwDevice);
         }
+        return elanL2GwDevice;
     }
 
-    private static class DisAssociateHwvtepFromElan implements Callable<List<ListenableFuture<Void>>> {
-        DataBroker broker;
-        L2GatewayDevice l2GatewayDevice;
-        ElanInstance elanInstance;
-        Devices l2Device;
-        Integer defaultVlan;
-
-        public DisAssociateHwvtepFromElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
-                Devices l2Device, Integer defaultVlan) {
-            this.broker = broker;
-            this.l2GatewayDevice = l2GatewayDevice;
-            this.elanInstance = elanInstance;
-            this.l2Device = l2Device;
-            this.defaultVlan = defaultVlan;
-        }
+    private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
+        return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
+    }
 
-        @Override
-        public List<ListenableFuture<Void>> call() throws Exception {
-            List<ListenableFuture<Void>> futures = new ArrayList<>();
-
-            // Remove remote MACs and vlan mappings from physical port
-            // Once all above configurations are deleted, delete logical
-            // switch
-            NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
-            String elanName = elanInstance.getElanInstanceName();
-            futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
-            futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
-                    l2GatewayDevice));
-            futures.addAll(ElanL2GatewayUtils.deleteL2GatewayDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
-            futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
-            Thread.sleep(30000);
-            futures.add(HwvtepUtils.deleteLogicalSwitch(this.broker, hwvtepNodeId, elanName));
-
-            return futures;
-        }
+    protected static boolean isLastL2GwConnBeingDeleted(L2GatewayDevice l2GwDevice) {
+        return (l2GwDevice.getL2GatewayIds().size() == 1);
     }
 }
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java
new file mode 100644 (file)
index 0000000..ee4f4d6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.elan.utils;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public class ElanClusterUtils {
+    private static final Logger logger = LoggerFactory.getLogger(ElanClusterUtils.class);
+
+    private static EntityOwnershipService eos;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
+    public static void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+        eos = entityOwnershipService;
+    }
+
+    public static void runOnlyInLeaderNode(Runnable job) {
+        runOnlyInLeaderNode(job, "");
+    }
+
+    public static void runOnlyInLeaderNode(final Runnable job, final String jobDescription) {
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    job.run();
+                } else {
+                    logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+                }
+            }
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Failed to identity cluster owner ", error);
+            }
+        });
+    }
+
+    public static void runOnlyInLeaderNode(String jobKey, Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+        runOnlyInLeaderNode(jobKey, "", dataStoreJob);
+    }
+
+    public static void runOnlyInLeaderNode(final String jobKey, final String jobDescription,
+                                           final Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    logger.trace("scheduling job {} ", jobDescription);
+                    dataStoreJobCoordinator.enqueueJob(jobKey, dataStoreJob,
+                            SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+                } else {
+                    logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+                }
+            }
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Failed to identity cluster owner for job "+jobDescription, error);
+            }
+        });
+    }
+}
index 51aff882abcfd5ced15831e57d04a9a506537239..e317d14526082eb2a09bafc64aee45cb5260965a 100755 (executable)
@@ -33,4 +33,5 @@ public class ElanConstants {
 
     public static final String L2GATEWAY_DS_JOB_NAME = "L2GW";
     public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+    public static final int JOB_MAX_RETRIES = 3;
 }
index e81a2759ee653435b2e881606772ff8d095ee3ac..c53bff81a3027ff1bb504eac54b88c98b68f5b6a 100644 (file)
@@ -9,10 +9,12 @@ package org.opendaylight.vpnservice.elan.utils;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
+import org.apache.commons.lang3.StringUtils;
 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;
@@ -33,6 +35,10 @@ import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -90,13 +96,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInput;
@@ -110,6 +122,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev1512
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.RemoveTerminatingServiceActionsInputBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -122,8 +135,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 
 public class ElanUtils {
 
-    private static final ArrayList EMPTY_LIST = new ArrayList();
-
     private static OdlInterfaceRpcService interfaceMgrRpcService;
 
     private static ItmRpcService itmRpcService;
@@ -571,7 +582,6 @@ public class ElanUtils {
         synchronized (macAddress) {
             logger.info("Acquired lock for mac : " + macAddress + ". Proceeding with install operation.");
             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalMgr);
-            setupTermDmacFlows(interfaceInfo, mdsalMgr);
             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, mdsalMgr, dataBroker);
         }
     }
@@ -633,7 +643,7 @@ public class ElanUtils {
      * @param interfaceInfo
      * @param mdsalApiManager
      */
-    private static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
+    public static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
         BigInteger dpId = interfaceInfo.getDpId();
         int lportTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
@@ -788,7 +798,7 @@ public class ElanUtils {
     public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
         List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName);
         if (dpns == null) {
-            return EMPTY_LIST;
+            return Collections.emptyList();
         }
         return dpns;
     }
@@ -932,8 +942,6 @@ public class ElanUtils {
                 }
                 mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
                         getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
-                RemoveTerminatingServiceActionsInput removeTerminatingServiceActionsInput = new RemoveTerminatingServiceActionsInputBuilder().setServiceId(interfaceInfo.getInterfaceTag()).setDpnId(srcdpId).build();
-                itmRpcService.removeTerminatingServiceActions(removeTerminatingServiceActionsInput);
                 if (logger.isDebugEnabled()) {
                     logger.debug("All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
                 }
@@ -1058,7 +1066,7 @@ public class ElanUtils {
      * @return the list
      */
     public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
-        List<Action> result = EMPTY_LIST;
+        List<Action> result = Collections.emptyList();
         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
             GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
                     .setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
@@ -1096,10 +1104,10 @@ public class ElanUtils {
      * @return the external itm egress action
      */
     public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
-        List<Action> result = EMPTY_LIST;
+        List<Action> result = Collections.emptyList();
 
         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
-                .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).build();
+                .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).setTunnelType(TunnelTypeVxlan.class).build();
         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output =
                 itmRpcService.getExternalTunnelInterfaceName(input);
         try {
@@ -1136,13 +1144,13 @@ public class ElanUtils {
      */
     public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
             long serviceTag) {
-        List<Action> result = EMPTY_LIST;
+        List<Action> result = Collections.emptyList();
 
         logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}",
                      sourceDpnId, destinationDpnId, serviceTag);
-
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
-                .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build();
+                .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
         Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
         try {
             if (output.get().isSuccessful()) {
@@ -1199,6 +1207,69 @@ public class ElanUtils {
         return null;
     }
 
+    /**
+     * Gets the external tunnel.
+     *
+     * @param sourceDevice
+     *            the source device
+     * @param destinationDevice
+     *            the destination device
+     * @param datastoreType
+     *            the datastore type
+     * @return the external tunnel
+     */
+    public static ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
+            LogicalDatastoreType datastoreType) {
+        ExternalTunnel externalTunnel = null;
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class ;
+        InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
+                .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
+        Optional<ExternalTunnel> tunnelList = read(dataBroker, datastoreType, iid);
+        if (tunnelList.isPresent()) {
+            externalTunnel = tunnelList.get();
+        }
+        return externalTunnel;
+    }
+
+    /**
+     * Gets the external tunnel.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param datastoreType
+     *            the datastore type
+     * @return the external tunnel
+     */
+    public static ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
+        ExternalTunnel externalTunnel = null;
+        List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
+        for (ExternalTunnel tunnel : externalTunnels) {
+            if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
+                externalTunnel = tunnel;
+                break;
+            }
+        }
+        return externalTunnel;
+    }
+
+    /**
+     * Gets the all external tunnels.
+     *
+     * @return the all external tunnels
+     */
+    public static List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
+        List<ExternalTunnel> result = null;
+        InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+        Optional<ExternalTunnelList> tunnelList = read(dataBroker, datastoreType, iid);
+        if (tunnelList.isPresent()) {
+            result = tunnelList.get().getExternalTunnel();
+        }
+        if (result == null) {
+            result = Collections.emptyList();
+        }
+        return result;
+    }
+
     /**
      * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is
      * connected remotely in another CSS and accessible through an internal
@@ -1464,5 +1535,63 @@ public class ElanUtils {
         return dpId;
     }
 
+    /**
+     * Checks if is interface operational.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param dataBroker
+     *            the data broker
+     * @return true, if is interface operational
+     */
+    public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
+        if (StringUtils.isBlank(interfaceName)) {
+            return false;
+        }
+        Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
+        if (ifState == null) {
+            return false;
+        }
+        return ((ifState.getOperStatus() == OperStatus.Up) && (ifState.getAdminStatus() == AdminStatus.Up));
+    }
+
+    /**
+     * Gets the interface state from operational ds.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param dataBroker
+     *            the data broker
+     * @return the interface state from oper ds
+     */
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
+            String interfaceName, DataBroker dataBroker) {
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
+                interfaceName);
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
+                .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
+        if (ifStateOptional.isPresent()) {
+            return ifStateOptional.get();
+        }
+        return null;
+    }
+
+    /**
+     * Creates the interface state instance identifier.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @return the instance identifier
+     */
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
+            String interfaceName) {
+        InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
+                .builder(InterfacesState.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+                        new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
+                                interfaceName));
+        return idBuilder.build();
+    }
+
 }
 
index 82b13ea413f4a65cb896e7a9393c4b35c0ed9f66..6017e2d21489b416ecfb4282266b17c765e0cc7f 100644 (file)
@@ -40,7 +40,6 @@ public class ElanServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open
         provider.setItmManager(getItmmanagerDependency());
         provider.setIdManager(idManager);
         provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
-        provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
         getBrokerDependency().registerProvider(provider);
         return provider;
     }
index 90ff11504c73f96f630272a00f185e5b4a4a1b51..15df3ee7088cefbb31ff446da4243b44279c2be7 100644 (file)
@@ -85,14 +85,6 @@ module elanservice-impl {
                     }
                 }
             }
-            container binding-normalized-node-serializer {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity md-sal-binding:binding-normalized-node-serializer;
-                    }
-                }
-            }
         }
     }
 }
\ No newline at end of file
diff --git a/fcapsmanager/alarmmanager/pom.xml b/fcapsmanager/alarmmanager/pom.xml
new file mode 100644 (file)
index 0000000..88db687
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+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
+-->
+<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.vpnservice</groupId>
+        <artifactId>config-parent</artifactId>
+        <version>0.3.0-SNAPSHOT</version>
+        <relativePath>../../commons/config-parent</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opendaylight.vpnservice</groupId>
+    <artifactId>alarmmanager</artifactId>
+    <version>${vpnservices.version}</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <maven-bundle-plugin.version>2.5.3</maven-bundle-plugin.version>
+        <osgi.version>5.0.0</osgi.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>${osgi.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.vpnservice</groupId>
+            <artifactId>fcaps-api</artifactId>
+            <version>${vpnservices.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven-bundle-plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                        <Bundle-Activator>org.opendaylight.vpnservice.fcapsmanager.alarmmanager.Activator</Bundle-Activator>
+                        <Export-Package>org.opendaylight.vpnservice.fcapsmanager.alarmmanager*;version=${project.version}</Export-Package>
+                        <Import-Package>*</Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/Activator.java b/fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/Activator.java
new file mode 100644 (file)
index 0000000..a133c8d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager.alarmmanager;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+    static Logger s_logger = LoggerFactory.getLogger(Activator.class);
+    private Runnable listener;
+    private Thread listenerThread;
+
+    public void start(BundleContext context) {
+        s_logger.info("Starting alarmmanager bundle");
+        AlarmNotificationListeners notificationListeners = new AlarmNotificationListeners(context);
+        try {
+            listener = notificationListeners;
+            listenerThread = new Thread(listener);
+            listenerThread.start();
+        } catch (Exception e) {
+            s_logger.error("Exception in alarm thread {}", e);
+        }
+    }
+
+    public void stop(BundleContext context) {
+        s_logger.info("Stopping alarmmanager bundle");
+    }
+}
\ No newline at end of file
diff --git a/fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/AlarmNotificationListeners.java b/fcapsmanager/alarmmanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/alarmmanager/AlarmNotificationListeners.java
new file mode 100644 (file)
index 0000000..7cb8785
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager.alarmmanager;
+
+import javax.management.*;
+import java.lang.management.ManagementFactory;
+import java.util.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.vpnservice.fcapsmanager.AlarmServiceFacade;
+
+public class AlarmNotificationListeners implements Runnable {
+    static Logger s_logger = LoggerFactory.getLogger(AlarmNotificationListeners.class);
+    private MBeanServer mbs = null;
+    private static String DOMAIN = "SDNC.FM";
+
+    private final DelegateListener delegateListener = new DelegateListener();
+    private BundleContext context = null;
+
+    public AlarmNotificationListeners(BundleContext context) {
+        this.context=context;
+    }
+
+    /**
+     * Platform dependent bundle injects its handle and it is retrieved in the method
+     */
+    private AlarmServiceFacade getAlarmServiceSPI (){
+        AlarmServiceFacade service =null;
+        if(context != null) {
+            try {
+                ServiceReference<?> serviceReference = context.
+                        getServiceReference(AlarmServiceFacade.class.getName());
+                service = (AlarmServiceFacade) context.
+                        getService(serviceReference);
+            }catch (NullPointerException ex){
+                service = null;
+            }catch (Exception e){
+                s_logger.error("Exception {} occurred in getting AlarmServiceSPI",e);
+            }
+        }
+        return service;
+    }
+
+    /**
+     * Gets register notification when a mbean is registered in platform Mbeanserver and checks if it is alarm mbean and add attribute notification listener to it.
+     * Gets attribute notification when alarm mbean is updated by the application.
+     */
+    public class DelegateListener implements NotificationListener {
+        public void handleNotification(Notification notification, Object obj) {
+            if (notification instanceof MBeanServerNotification) {
+                MBeanServerNotification msnotification =
+                        (MBeanServerNotification) notification;
+                String nType = msnotification.getType();
+                ObjectName mbn = msnotification.getMBeanName();
+
+                if (nType.equals("JMX.mbean.registered")) {
+                    if (mbn.toString().contains(DOMAIN)) {
+                        s_logger.debug("Received registeration of Mbean "+mbn);
+                        try {
+                            mbs.addNotificationListener(mbn,delegateListener, null, null);
+                            s_logger.debug("Added attribute notification listener for Mbean "+ mbn);
+                        } catch (InstanceNotFoundException e) {
+                            s_logger.error("Exception while adding attribute notification of mbean {}", e);
+                        }
+                    }
+                }
+
+                if (nType.equals("JMX.mbean.unregistered")) {
+                    if (mbn.toString().contains(DOMAIN)) {
+                        s_logger.debug("Time: " + msnotification.getTimeStamp() + "MBean " + msnotification.getMBeanName()+" unregistered successfully");
+                    }
+                }
+            }
+            else if (notification instanceof AttributeChangeNotification) {
+                AttributeChangeNotification acn =
+                        (AttributeChangeNotification) notification;
+
+                s_logger.debug("Received attribute notification of Mbean: "
+                        + notification.getSource()
+                        + " for attribute:" + acn.getAttributeName() );
+
+                if(acn.getAttributeName().toString().equals("raiseAlarmObject")){
+
+                    String value=acn.getNewValue().toString();
+                    value = value.replace(value.charAt(0), ' ');
+                    value = value.replace(value.charAt(value.lastIndexOf("]")), ' ');
+
+                    String[] args =value.split(",");
+                    s_logger.debug("Receive attribute value :"+args[0].trim()+args[1].trim()+args[2].trim());
+                    if(getAlarmServiceSPI() != null ) {
+                        getAlarmServiceSPI().raiseAlarm(args[0].trim(),args[1].trim(),args[2].trim());
+                    } else {
+                        s_logger.debug("Alarm service not available");
+                    }
+
+                } else if(acn.getAttributeName().toString().equals("clearAlarmObject")){
+
+                    String value=acn.getNewValue().toString();
+                    value = value.replace(value.charAt(0), ' ');
+                    value = value.replace(value.charAt(value.lastIndexOf("]")), ' ');
+
+                    String[] args =value.split(",");
+                    s_logger.debug("Receive attribute value :"+args[0].trim()+args[1].trim()+args[2].trim());
+                    if(getAlarmServiceSPI() != null )
+                        getAlarmServiceSPI().clearAlarm(args[0].trim(), args[1].trim(), args[2].trim());
+                    else
+                        s_logger.debug("Alarm service not available");
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the platform MBeanServer instance and registers to get notification whenever alarm mbean is registered in the mbeanserver
+     */
+    @Override
+    public void run() {
+        mbs = ManagementFactory.getPlatformMBeanServer();
+
+        queryMbeans();
+
+        ObjectName delegate = null;
+        try {
+            delegate = new ObjectName("JMImplementation:type=MBeanServerDelegate");
+        } catch (MalformedObjectNameException e) {
+            e.printStackTrace();
+        }
+        NotificationFilterSupport filter = new NotificationFilterSupport();
+        filter.enableType("JMX.mbean.registered");
+        filter.enableType("JMX.mbean.unregistered");
+
+        try {
+            mbs.addNotificationListener(delegate, delegateListener, filter, null);
+            s_logger.debug("Added registeration listener for Mbean {}",delegate);
+        } catch (InstanceNotFoundException e) {
+            s_logger.error("Failed to add registeration listener {}", e);
+        }
+
+        waitForNotification();
+    }
+
+    /**
+     *  Pre-provisioning case to handle all alarm mbeans which are registered before installation of framework bundle
+     *  Queries the platform Mbeanserver to retrieve registered alarm mbean and add attribute notification listener to it
+     */
+    public void queryMbeans() {
+
+        Set<ObjectName> names =
+                new TreeSet<ObjectName>(mbs.queryNames(null, null));
+        s_logger.debug("Queried MBeanServer for MBeans:");
+        for (ObjectName beanName : names) {
+            if(beanName.toString().contains(DOMAIN)){
+                try {
+                    mbs.addNotificationListener(beanName,delegateListener, null, null);
+                    s_logger.debug("Added attribute notification listener for Mbean "+ beanName);
+                } catch (InstanceNotFoundException e) {
+                    s_logger.error("Failed to add attribute notification for Mbean {}", e);
+                }
+            }
+        }
+    }
+    public void waitForNotification() {
+        while(true){
+            try {
+                Thread.sleep(50);
+            }
+            catch(Exception ex){
+                ex.printStackTrace();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/fcapsmanager/countermanager/pom.xml b/fcapsmanager/countermanager/pom.xml
new file mode 100644 (file)
index 0000000..63cb649
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+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
+-->
+<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.vpnservice</groupId>
+        <artifactId>config-parent</artifactId>
+        <version>0.3.0-SNAPSHOT</version>
+        <relativePath>../../commons/config-parent</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opendaylight.vpnservice</groupId>
+    <artifactId>countermanager</artifactId>
+    <version>${vpnservices.version}</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <maven-bundle-plugin.version>2.5.3</maven-bundle-plugin.version>
+        <osgi.version>5.0.0</osgi.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>${osgi.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.vpnservice</groupId>
+            <artifactId>fcaps-api</artifactId>
+            <version>${vpnservices.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven-bundle-plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                        <Bundle-Activator>org.opendaylight.vpnservice.fcapsmanager.countermanager.Activator</Bundle-Activator>
+                        <Export-Package>org.opendaylight.vpnservice.fcapsmanager.countermanager*;version=${project.version}</Export-Package>
+                        <Import-Package>*</Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Activator.java b/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Activator.java
new file mode 100644 (file)
index 0000000..6f6928c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager.countermanager;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MalformedObjectNameException;
+import javax.management.ReflectionException;
+import java.io.IOException;
+
+public class Activator implements BundleActivator {
+    private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(Activator.class);
+    private Runnable listener;
+    private Thread listenerThread;
+
+    public void start(BundleContext context) throws InstanceNotFoundException, MalformedObjectNameException, MBeanException, ReflectionException, IOException {
+        LOG.info("Starting countermanager bundle ");
+        PMRegistrationListener notificationListeners = new PMRegistrationListener(context);
+        try {
+            listener = notificationListeners;
+            listenerThread = new Thread(listener);
+            listenerThread.start();
+        } catch (Exception e) {
+            LOG.error("Exception in counter thread {}", e);
+        }
+    }
+
+    public void stop(BundleContext context) {
+        LOG.info("Stopping countermanager bundle ");
+    }
+}
\ No newline at end of file
diff --git a/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/PMRegistrationListener.java b/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/PMRegistrationListener.java
new file mode 100644 (file)
index 0000000..cfdbdb4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager.countermanager;
+
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationFilterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.osgi.framework.BundleContext;
+import org.slf4j.LoggerFactory;
+
+public class PMRegistrationListener implements Runnable {
+    private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(PMRegistrationListener.class);
+    static MBeanServer mbs = null;
+
+    private static String DOMAIN = "SDNC.PM";
+    public static HashSet<ObjectName> beanNames = new HashSet<ObjectName>();
+    private BundleContext context = null;
+
+    public PMRegistrationListener(BundleContext context){
+        this.context=context;
+    }
+
+    /**
+     * Gets register notification when a mbean is registered in platform Mbeanserver and checks if it is counter mbean and add it to the map.
+     */
+    public static class DelegateListener implements NotificationListener {
+        public void handleNotification(Notification notification, Object obj) {
+            if (notification instanceof MBeanServerNotification) {
+                MBeanServerNotification msnotification =
+                        (MBeanServerNotification) notification;
+                String nType = msnotification.getType();
+                ObjectName mbn = msnotification.getMBeanName();
+                if (nType.equals("JMX.mbean.registered")) {
+                    String mbean = mbn.toString();
+                    if(mbean.contains(DOMAIN)) {
+                        beanNames.add(mbn);
+                        LOG.debug("Beans are " +beanNames);
+                    }
+                }
+                if (nType.equals("JMX.mbean.unregistered")) {
+                    if(mbn.toString().contains(DOMAIN)) {
+                        beanNames.remove(mbn);
+                        LOG.debug(mbn +" MBean has been unregistered");
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void run(){
+        mbs = ManagementFactory.getPlatformMBeanServer();
+        queryMbeans();
+        DelegateListener delegateListener = new DelegateListener();
+        ObjectName delegate = null;
+        try {
+            delegate = new ObjectName("JMImplementation:type=MBeanServerDelegate");
+        } catch (MalformedObjectNameException e) {
+            e.printStackTrace();
+        }
+        NotificationFilterSupport filter = new NotificationFilterSupport();
+
+        filter.enableType("JMX.mbean.registered");
+        filter.enableType("JMX.mbean.unregistered");
+
+        LOG.debug("Add PM Registeration Notification Listener");
+        try {
+            mbs.addNotificationListener(delegate, delegateListener, filter,null);
+        }catch (InstanceNotFoundException e) {
+            e.printStackTrace();
+        }
+        Poller poller = new Poller(this.context);
+        poller.polling();
+        waitforNotification();
+    }
+
+    /**
+     * Prepovising case to handle all counter mbeans which are registered before the installation of framework bundle
+     * Queries the platform Mbeanserver to retrieve registered counter mbean and add it to the map
+     */
+    public void queryMbeans() {
+        Set<ObjectName> names =
+                new TreeSet<ObjectName>(mbs.queryNames(null, null));
+        LOG.debug("\nQueried MBeanServer for MBeans:");
+        for (ObjectName name : names) {
+            if(name.toString().contains(DOMAIN)){
+                beanNames.add(name);
+            }
+        }
+    }
+
+    private void waitforNotification() {
+        while(true){
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Poller.java b/fcapsmanager/countermanager/src/main/java/org/opendaylight/vpnservice/fcapsmanager/countermanager/Poller.java
new file mode 100644 (file)
index 0000000..ad6f850
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager.countermanager;
+
+import java.lang.management.ManagementFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import org.opendaylight.vpnservice.fcapsmanager.PMServiceFacade;
+
+public class Poller {
+    private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(Poller.class);
+    private static BundleContext context = null;
+    public Poller(){
+    }
+    public Poller(BundleContext bundleContext) {
+        context = bundleContext;
+    }
+    //This method do the Polling every 5 second and retrieves the the counter details
+    //@Override
+    public void polling() {
+        LOG.debug("Poller Polling Mbean List and the content is " + PMRegistrationListener.beanNames);
+        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
+        service.scheduleAtFixedRate(new Pollerthread(), 0, 5, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Platform dependent bundle injects its handle and it is retrieved in the method
+     */
+    protected PMServiceFacade getPMServiceSPI (){
+        PMServiceFacade service =null;
+        if(context != null) {
+            try {
+                ServiceReference<?> serviceReference = context.
+                        getServiceReference(PMServiceFacade.class.getName());
+                service = (PMServiceFacade) context.
+                        getService(serviceReference);
+            }catch(NullPointerException ex){
+                service = null;
+            }catch (Exception e){
+                LOG.error("Exception {} occurred in getting PMServiceSPI",e);
+            }
+        }
+        return service;
+    }
+}
+
+class Pollerthread implements Runnable {
+    private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(Pollerthread.class);
+    MBeanServer mbs = null;
+    Map<String,String> getCounter = new HashMap<String,String>();
+    Poller poller = new Poller();
+
+    /**
+     * Retrieve countermap from each counter mbean and send to platform
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public void run() {
+        try {
+            mbs = ManagementFactory.getPlatformMBeanServer();
+            for (ObjectName objectName : PMRegistrationListener.beanNames) {
+                getCounter=(Map<String, String>) mbs.invoke(objectName, "retrieveCounterMap",null,null);
+                if(poller.getPMServiceSPI() != null)
+                    poller.getPMServiceSPI().connectToPMFactory(getCounter);
+                else
+                    LOG.debug("PM service not available");
+            }
+        } catch (Exception e) {
+            LOG.error("Exception caught {} ", e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/fcapsmanager/fcaps-api/pom.xml b/fcapsmanager/fcaps-api/pom.xml
new file mode 100644 (file)
index 0000000..1277591
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+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
+-->
+<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.vpnservice</groupId>
+        <artifactId>config-parent</artifactId>
+        <version>0.3.0-SNAPSHOT</version>
+        <relativePath>../../commons/config-parent</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opendaylight.vpnservice</groupId>
+    <artifactId>fcaps-api</artifactId>
+    <version>${vpnservices.version}</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <maven-bundle-plugin.version>2.5.3</maven-bundle-plugin.version>
+        <osgi.version>5.0.0</osgi.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>${osgi.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven-bundle-plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                        <Bundle-Activator>org.opendaylight.vpnservice.fcapsmanager.Activator</Bundle-Activator>
+                        <Export-Package>org.opendaylight.vpnservice.fcapsmanager*;version=${project.version}</Export-Package>
+                        <Import-Package>*</Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/Activator.java b/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/Activator.java
new file mode 100644 (file)
index 0000000..2188390
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+    static Logger s_logger = LoggerFactory.getLogger(Activator.class);
+    public void start(BundleContext context) {
+        s_logger.info("Starting fcapsSPI bundle");
+    }
+
+    public void stop(BundleContext context) {
+        s_logger.info("Stopping fcapsSPI bundle");
+    }
+
+}
\ No newline at end of file
diff --git a/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/AlarmServiceFacade.java b/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/AlarmServiceFacade.java
new file mode 100644 (file)
index 0000000..85ec789
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager;
+
+public interface AlarmServiceFacade {
+    /**
+     * Raises the given alarm in platform environment
+     *
+     * @param alarmName
+     *            Alarm to be raised
+     * @param additionalText
+     *            Additional details describing about the alarm
+     * @param source
+     *            Source of the alarm ex: dpnId=openflow:1
+     *            the source node that caused this alarm
+     */
+    public void raiseAlarm(String alarmName, String additionalText, String source);
+
+    /**
+     * Clears the given alarm in platform environment
+     *
+     * @param alarmName
+     *            Alarm to be cleared
+     * @param additionalText
+     *            Additional details describing about the alarm
+     * @param source
+     *            Source of the alarm ex:  dpnId=openflow:1
+     *            the source node that caused this alarm
+     */
+    public void clearAlarm(String alarmName, String additionalText, String source);
+}
\ No newline at end of file
diff --git a/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/PMServiceFacade.java b/fcapsmanager/fcaps-api/src/main/java/org/opendaylight/vpnservice/fcapsmanager/PMServiceFacade.java
new file mode 100644 (file)
index 0000000..6bad020
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fcapsmanager;
+
+import java.util.Map;
+
+public interface PMServiceFacade {
+    public void connectToPMFactory(Map map);
+}
diff --git a/fcapsmanager/pom.xml b/fcapsmanager/pom.xml
new file mode 100644 (file)
index 0000000..6034382
--- /dev/null
@@ -0,0 +1,50 @@
+<?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>odlparent</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.vpnservice</groupId>
+    <artifactId>fcapsmanager</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <name>fcapsmanager</name>
+    <packaging>pom</packaging>
+    <modelVersion>4.0.0</modelVersion>
+    <prerequisites>
+        <maven>3.1.1</maven>
+    </prerequisites>
+    <modules>
+        <module>fcaps-api</module>
+        <module>alarmmanager</module>
+        <module>countermanager</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>
\ No newline at end of file
index c5ece44da22229bd78bdd54daef410f42734855f..e2e05a02a0e7141e210efd8228345dabce9bd3cd 100644 (file)
@@ -42,6 +42,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <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>
+
   </properties>
   <dependencyManagement>
     <dependencies>
@@ -364,6 +366,23 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <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>
@@ -420,5 +439,21 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <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>
   </dependencies>
 </project>
index f441332c1b60b35c1bbc2c18d0acab138290520e..1daa7ed362a96969e08b14f43738dac48db3681a 100644 (file)
@@ -41,6 +41,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <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>
@@ -70,6 +71,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <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>
@@ -88,6 +90,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <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 '>
@@ -116,4 +119,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <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>
-  </features>
+
+  <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>
+</features>
index d698dec9b79bdec28f71133aefede34be0be6f0f..4296f0055ad87a7a8a01b9bb1e8fb41fe082afaf 100644 (file)
@@ -54,5 +54,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>config-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-base</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang b/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang
new file mode 100644 (file)
index 0000000..9a76379
--- /dev/null
@@ -0,0 +1,57 @@
+module fib-rpc {\r
+    namespace "urn:opendaylight:vpnservice:fib:rpc";\r
+    prefix "fib-rpc";\r
+\r
+    import ietf-inet-types {\r
+        prefix inet;\r
+        revision-date "2010-09-24";\r
+    }\r
+\r
+    import opendaylight-flow-types {\r
+        prefix offlow;\r
+        revision-date "2013-10-26";\r
+    }\r
+\r
+    revision "2016-01-21" {\r
+        description "FIB Servicer RPC Module";\r
+    }\r
+\r
+    /* RPCs */\r
+\r
+    rpc create-fib-entry {\r
+        description "to install FIB/LFIB/TST routes on specified dpn with given instructions";\r
+        input {\r
+            leaf source-dpid {\r
+                type uint64;\r
+            }\r
+            leaf vpn-name {\r
+                type string;\r
+            }\r
+            leaf service-id {\r
+                type uint32;\r
+            }\r
+            leaf ip-address {\r
+                type string;\r
+            }\r
+            uses offlow:instruction-list;\r
+        }\r
+    }\r
+\r
+    rpc remove-fib-entry {\r
+        description "to remove FIB/LFIB/TST routes from specified dpn";\r
+        input {\r
+            leaf source-dpid {\r
+                type uint64;\r
+            }\r
+            leaf vpn-name {\r
+                type string;\r
+            }\r
+            leaf service-id {\r
+                type uint32;\r
+            }\r
+            leaf ip-address {\r
+                type string;\r
+            }\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibConstants.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibConstants.java
new file mode 100644 (file)
index 0000000..52dc950
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fibmanager;
+
+import java.math.BigInteger;
+
+public class FibConstants {
+    static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
+    static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
+    static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+    static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
+    static final String FLOWID_PREFIX = "L3.";
+    static final String VPN_IDPOOL_NAME = "vpnservices";
+    static final String SEPARATOR = ".";
+}
index b9906ada2455bb32e8062d80fd2088bb09802d9f..a01bae3ff4c47f07287172e7d3f04bd62ee95b6e 100644 (file)
@@ -56,6 +56,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instanc
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
@@ -93,6 +94,7 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
   private NexthopManager nextHopManager;
   private ItmRpcService itmManager;
   private OdlInterfaceRpcService interfaceManager;
+  private IdManagerService idManager;
   private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
   private static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
   private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
@@ -140,6 +142,10 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
       this.interfaceManager = ifManager;
   }
 
+  public void setIdManager(IdManagerService idManager) {
+      this.idManager = idManager;
+  }
+
   private void registerListener(final DataBroker db) {
     try {
       listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
@@ -159,19 +165,19 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
   @Override
   protected void add(final InstanceIdentifier<VrfEntry> identifier,
                      final VrfEntry vrfEntry) {
-    LOG.trace("key: " + identifier + ", value=" + vrfEntry );
+    LOG.trace("Add key: " + identifier + ", value=" + vrfEntry );
     createFibEntries(identifier, vrfEntry);
   }
 
   @Override
   protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
-    LOG.trace("key: " + identifier + ", value=" + vrfEntry);
+    LOG.trace("Remove key: " + identifier + ", value=" + vrfEntry);
     deleteFibEntries(identifier, vrfEntry);
   }
 
   @Override
   protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
-    LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
+    LOG.trace("Update key: " + identifier + ", original=" + original + ", update=" + update );
     createFibEntries(identifier, update);
   }
 
@@ -182,12 +188,13 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
 
     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
-    Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
-    Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
+    Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
+    Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
 
     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
     Long vpnId = vpnInstance.getVpnId();
-    RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, vrfTableKey.getRouteDistinguisher(),
+    String rd = vrfTableKey.getRouteDistinguisher();
+    RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
             vrfEntry.getDestPrefix());
     if (rdToElanOpEntry!=null) {
         if (vpnToDpnList!=null) {
@@ -198,27 +205,36 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
         return;
     }
     BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
-              vrfTableKey.getRouteDistinguisher(), vrfEntry);
+            rd, vrfEntry);
     if (vpnToDpnList != null) {
-      for (VpnToDpnList curDpn : vpnToDpnList) {
-        if (!curDpn.getDpnId().equals(localDpnId)) {
-          createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
-                               vrfTableKey, vrfEntry);
+        for (VpnToDpnList curDpn : vpnToDpnList) {
+            if (!curDpn.getDpnId().equals(localDpnId)) {
+                createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
+                        vrfTableKey, vrfEntry);
+            }
         }
-      }
     }
   }
 
   private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
                                        long vpnId, VrfEntry vrfEntry){
-      makeSubnetRouteFlow(dpnId);
       List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-      List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
       Long elanTag = rdToElanOpEntry.getElanTag();
+
       instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
       instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
       makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
               instructions,NwConstants.ADD_FLOW);
+
+      List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+      // reinitialize instructions list for LFIB Table
+      instructions = new ArrayList<InstructionInfo>();
+
+      actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+      instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+      instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
+      instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
+
       makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
               vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
       // TODO makeTunnelTableEntry();
@@ -252,20 +268,24 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
       return result;
   }
 
-  private void makeSubnetRouteFlow(BigInteger dpnId) {
-      //Ask Vivek cookie
+  private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
       final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
       List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
       List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
       actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
-      instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+      instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
       List<MatchInfo> matches = new ArrayList<MatchInfo>();
       String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
       FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
               NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
 
-      LOG.debug("Invoking MDSAL to install Table Miss Entries");
-      mdsalManager.syncInstallFlow(flowEntity,1);
+      if (addOrRemove == NwConstants.ADD_FLOW) {
+          LOG.debug("Invoking MDSAL to install SubnetRoute Table Miss Entries for DPN" + dpnId);
+          mdsalManager.installFlow(flowEntity);
+      } else {
+          LOG.debug("Invoking MDSAL to remove SubnetRoute Table Miss Entries for DPN " + dpnId);
+          mdsalManager.removeFlow(flowEntity);
+      }
   }
 
   private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
@@ -567,7 +587,11 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
           LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
           FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
                          FibUtil.getVpnInterfaceIdentifier(ifName));
-       }
+      }
+
+      FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
+         FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
+
   }
 
   private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
@@ -576,8 +600,12 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
 
+    String rd  = vrfTableKey.getRouteDistinguisher();
     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
-    Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
+    if (vpnInstance == null) {
+        LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
+        return;
+    }
     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
     RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
             vrfEntry.getDestPrefix());
@@ -595,16 +623,18 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
         InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
                 vrfEntry.getDestPrefix());
         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
+        FibUtil.releaseId(idManager,FibConstants.VPN_IDPOOL_NAME,
+                FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
         return;
     }
     BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
-              vrfTableKey.getRouteDistinguisher(), vrfEntry);
+            vrfTableKey.getRouteDistinguisher(), vrfEntry);
     if (vpnToDpnList != null) {
-      for (VpnToDpnList curDpn : vpnToDpnList) {
-        if (!curDpn.getDpnId().equals(localDpnId)) {
-          deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
+        for (VpnToDpnList curDpn : vpnToDpnList) {
+            if (!curDpn.getDpnId().equals(localDpnId)) {
+                deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
+            }
         }
-      }
     }
     //The flow/group entry has been deleted from config DS; need to clean up associated operational
     //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
@@ -778,6 +808,17 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
       Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
       if (vrfTable.isPresent()) {
         for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                        /* Handle subnet routes here */
+            RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
+                    vrfEntry.getDestPrefix());
+            if (rdToElanOpEntry != null) {
+                LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
+                        dpnId, rd);
+                makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
+                makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
+                        vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
+                continue;
+            }
           // Passing null as we don't know the dpn
           // to which prefix is attached at this point
           deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
@@ -860,6 +901,7 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
         LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
         makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
         makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
+        makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
     }
 
     private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
index 382e6172f32c3afef36cf422f626919a249cbdfc..62f9e7111c0f22bf2f57adbd64b2eb752366f731 100644 (file)
@@ -12,9 +12,12 @@ import java.util.List;
 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.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.fibmanager.api.IFibManager;
 import org.opendaylight.vpnmanager.api.IVpnManager;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
@@ -33,6 +36,8 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au
   private ItmRpcService itmManager;
   private OdlInterfaceRpcService interfaceManager;
   private FibNodeCapableListener fibNcListener;
+  private RpcProviderRegistry rpcProviderRegistry;
+  private RpcRegistration<FibRpcService> rpcRegistration;
 
   @Override
   public void onSessionInitiated(ProviderContext session) {
@@ -50,7 +55,10 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au
       fibManager.setNextHopManager(nexthopManager);
       fibManager.setITMRpcService(itmManager);
       fibManager.setInterfaceManager(interfaceManager);
+      fibManager.setIdManager(idManager);
       fibNcListener = new FibNodeCapableListener(dataBroker, fibManager);
+      FibRpcService fibRpcService = new FibRpcServiceImpl(dataBroker, mdsalManager, this);
+      rpcRegistration = getRpcProviderRegistry().addRpcImplementation(FibRpcService.class, fibRpcService);
     } catch (Exception e) {
       LOG.error("Error initializing services", e);
     }
@@ -109,4 +117,13 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au
   public void deleteStaticRoute(String prefix, String rd) {
     this.vpnmanager.delExtraRoute(prefix, rd, null);
   }
+
+  public void setRpcProviderRegistry(RpcProviderRegistry rpcProviderRegistry) {
+    this.rpcProviderRegistry = rpcProviderRegistry;
+  }
+
+  private RpcProviderRegistry getRpcProviderRegistry() {
+    return rpcProviderRegistry;
+  }
+
 }
diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibRpcServiceImpl.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibRpcServiceImpl.java
new file mode 100644 (file)
index 0000000..c8afe58
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.fibmanager;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+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.fibmanager.api.IFibManager;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
+import static org.opendaylight.vpnservice.fibmanager.FibConstants.*;
+
+public class FibRpcServiceImpl implements FibRpcService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FibRpcServiceImpl.class);
+    private IMdsalApiManager mdsalManager;
+    private DataBroker broker;
+    private IFibManager fibManager;
+
+    public FibRpcServiceImpl(DataBroker broker, IMdsalApiManager mdsalManager, IFibManager fibManager) {
+        this.broker = broker;
+        this.mdsalManager = mdsalManager;
+        this.fibManager = fibManager;
+    }
+
+
+    /**
+     * to install FIB routes on specified dpn with given instructions
+     *
+     */
+    public Future<RpcResult<Void>> createFibEntry(CreateFibEntryInput input) {
+
+        BigInteger dpnId = input.getSourceDpid();
+        String vpnName = input.getVpnName();
+        long vpnId = getVpnId(broker, vpnName);
+        String ipAddress = input.getIpAddress();
+        LOG.info("Create custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName);
+        List<Instruction> instructions = input.getInstruction();
+
+        makeLocalFibEntry(vpnId, dpnId, ipAddress, instructions);
+        updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+
+        return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
+    }
+
+    /**
+     * to remove FIB/LFIB/TST routes from specified dpn
+     *
+     */
+    public Future<RpcResult<Void>> removeFibEntry(RemoveFibEntryInput input) {
+
+        BigInteger dpnId = input.getSourceDpid();
+        String vpnName = input.getVpnName();
+        long vpnId = getVpnId(broker, vpnName);
+        long serviceId = input.getServiceId();
+        String ipAddress = input.getIpAddress();
+
+        LOG.info("Delete custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName);
+
+        removeLocalFibEntry(dpnId, vpnId, ipAddress);
+        //removeLFibTableEntry(dpnId, serviceId);
+        //removeTunnelTableEntry(dpnId, serviceId);
+        removeFromVpnDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+
+        return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
+    }
+
+    private void removeLocalFibEntry(BigInteger dpnId, long vpnId, String ipPrefix) {
+        String values[] = ipPrefix.split("/");
+        String ipAddress = values[0];
+        int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
+        LOG.debug("Removing route from DPN. ip {} masklen {}", ipAddress, prefixLength);
+        InetAddress destPrefix = null;
+        try {
+          destPrefix = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+          LOG.error("UnknowHostException in removeRoute. Failed  to remove Route for ipPrefix {}", ipAddress);
+          return;
+        }
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+            BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                                  new long[] { 0x0800L }));
+
+        if(prefixLength != 0) {
+            matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+                    destPrefix.getHostAddress(), Integer.toString(prefixLength) }));
+        }
+
+        String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vpnId, ipAddress);
+
+
+        int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef,
+                                               priority, flowRef, 0, 0,
+                                               COOKIE_VM_FIB_TABLE, matches, null);
+
+        mdsalManager.removeFlow(dpnId, flowEntity);
+
+        LOG.debug("FIB entry for route {} on dpn {} removed successfully", ipAddress, dpnId);
+    }
+
+    private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                                  new long[] { 0x8847L }));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+        String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+        LOG.debug("removing LFib entry with flow ref {}", flowRef);
+
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+                                               DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
+                                               COOKIE_VM_LFIB_TABLE, matches, null);
+
+        mdsalManager.removeFlow(dpnId, flowEntity);
+
+        LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+    }
+
+    private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
+        LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+        // Matching metadata
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                                               getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+                                               5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+                                               COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+        mdsalManager.removeFlow(dpnId, flowEntity);
+        LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+    }
+
+    private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+
+        LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
+
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+
+        Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                        getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
+                        0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
+
+        mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+    }
+
+    private long getIpAddress(byte[] rawIpAddress) {
+        return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
+                + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
+    }
+
+    private void makeLocalFibEntry(long vpnId, BigInteger dpnId, String ipPrefix, List<Instruction> customInstructions) {
+        String values[] = ipPrefix.split("/");
+        String ipAddress = values[0];
+        int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
+        LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
+        InetAddress destPrefix = null;
+        try {
+          destPrefix = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+          LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", ipAddress);
+          return;
+        }
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+            BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                                  new long[] { 0x0800L }));
+
+        if(prefixLength != 0) {
+          matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+             destPrefix.getHostAddress(), Integer.toString(prefixLength) }));
+        }
+
+        String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vpnId, ipAddress);
+
+
+        int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef,
+                                               priority, flowRef, 0, 0,
+                                               COOKIE_VM_FIB_TABLE, matches, customInstructions);
+
+        mdsalManager.installFlow(dpnId, flowEntity);
+
+        LOG.debug("FIB entry for route {} on dpn {} installed successfully", ipAddress, dpnId);
+    }
+
+    private void makeLFibTableEntry(BigInteger dpId, long serviceId, List<Instruction> customInstructions) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x8847L }));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+        Instruction writeInstruction = new InstructionInfo(InstructionType.write_actions, actionsInfos).buildInstruction(0);
+        instructions.add(writeInstruction);
+        instructions.addAll(customInstructions);
+
+        // Install the flow entry in L3_LFIB_TABLE
+        String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+                DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
+                COOKIE_VM_LFIB_TABLE, matches, instructions);
+
+        mdsalManager.installFlow(dpId, flowEntity);
+
+        LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+    }
+
+    private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
+        return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+            .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+            .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+    }
+
+    private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
+        LOG.debug("Updating VPN to DPN list for dpn : {} for VPN: {} with ip: {}",
+                dpnId, vpnName, ipAddr);
+        String routeDistinguisher = getVpnRd(broker, vpnName);
+        String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
+        InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
+        Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses
+            ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
+
+        if (dpnInVpn.isPresent()) {
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+                org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance
+                    .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+                    new IpAddressesKey(ipAddr)), ipAddress);
+        } else {
+            MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
+                                    getVpnInstanceOpDataIdentifier(rd),
+                                    getVpnInstanceOpData(rd, vpnId));
+            VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses =  new ArrayList<>();
+            ipAddresses.add(ipAddress);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
+                              vpnToDpnList.setIpAddresses(ipAddresses).build());
+            LOG.debug("populate FIB on new dpn {} for VPN {}", dpnId, vpnName);
+            fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
+        }
+    }
+
+    private synchronized void removeFromVpnDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
+        LOG.debug("Removing association of VPN to DPN list for dpn : {} for VPN: {} with ip: {}",
+                dpnId, vpnName, ipAddr);
+        String routeDistinguisher = getVpnRd(broker, vpnName);
+        String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
+        InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
+        Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (dpnInVpn.isPresent()) {
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
+            org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses
+                    ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
+
+            if (ipAddresses != null && ipAddresses.remove(ipAddress)) {
+                if (ipAddresses.isEmpty()) {
+                    List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
+                    if(vpnInterfaces ==null || vpnInterfaces.isEmpty()) {
+                        //Clean up the dpn
+                        LOG.debug("Cleaning up dpn {} from VPN {}", dpnId, vpnName);
+                        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+                        fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
+                    }
+                } else {
+                    delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                            .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+                            new IpAddressesKey(ipAddr)));
+                }
+            }
+        }
+    }
+
+    //TODO: Below Util methods to be removed once VpnUtil methods are exposed in api bundle
+    public static String getVpnRd(DataBroker broker, String vpnName) {
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+                = getVpnInstanceToVpnIdIdentifier(vpnName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+                = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+        String rd = null;
+        if(vpnInstance.isPresent()) {
+            rd = vpnInstance.get().getVrfId();
+        }
+        return rd;
+    }
+
+    static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
+                                                                                         getVpnInstanceToVpnIdIdentifier(String vpnName) {
+        return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
+    }
+
+
+    static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
+        return InstanceIdentifier.builder(VpnInstanceOpData.class)
+            .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
+            .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
+    }
+
+    static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
+        return InstanceIdentifier.builder(VpnInstanceOpData.class)
+            .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
+    }
+
+    static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId) {
+        return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).build();
+    }
+
+    static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.delete(datastoreType, path);
+        tx.submit();
+    }
+
+    static long getVpnId(DataBroker broker, String vpnName) {
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+            = getVpnInstanceToVpnIdIdentifier(vpnName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+            = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+        long vpnId = -1;
+        if(vpnInstance.isPresent()) {
+            vpnId = vpnInstance.get().getVpnId();
+        }
+        return vpnId;
+    }
+
+}
index 1c13444093e8cc3620308452511e3cfc7972f06e..0ba7296d38902663a2dac3505942b8eb5fd4cdcc 100644 (file)
@@ -21,12 +21,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.math.BigInteger;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 
 public class FibUtil {
     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
@@ -100,6 +107,24 @@ public class FibUtil {
                         new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey(ipPrefix)).build();
     }
 
+    static String getNextHopLabelKey(String rd, String prefix){
+        String key = rd + FibConstants.SEPARATOR + prefix;
+        return key;
+    }
+
+    static void releaseId(IdManagerService idManager, String poolName, String idKey) {
+        ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
+        try {
+            Future<RpcResult<Void>> result = idManager.releaseId(idInput);
+            RpcResult<Void> rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
+        }
+    }
+
     static final FutureCallback<Void> DEFAULT_CALLBACK =
             new FutureCallback<Void>() {
                 public void onSuccess(Void result) {
index 89841010dd808e0e5c56ed614e4257738f51a102..84487410c313e75acebbe682fd5d9e8f06a4668e 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instanc
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
@@ -133,6 +134,9 @@ public class FibManagerTest {
                 return null;
               }
 
+              @Override
+              public List<IpAddresses> getIpAddresses() { return null; }
+
               @Override
               public VpnToDpnListKey getKey() {
                 return new VpnToDpnListKey(Dpn);
index 4cc72503407d1635eea6debf9db5a611abd28c80..b34fe1baf9ea15c3853a30659418cfe62b42bb2a 100644 (file)
@@ -138,8 +138,8 @@ public class InterfacemgrProvider implements BindingAwareProvider, AutoCloseable
             hwVTEPTunnelsStateListener = new HwVTEPTunnelsStateListener(dataBroker);
             hwVTEPTunnelsStateListener.registerListener(LogicalDatastoreType.OPERATIONAL,dataBroker);
 
-            //terminationPointStateListener = new TerminationPointStateListener(dataBroker);
-            //terminationPointStateListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+            terminationPointStateListener = new TerminationPointStateListener(dataBroker);
+            terminationPointStateListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
 
             flowBasedServicesConfigListener = new FlowBasedServicesConfigListener(dataBroker);
             flowBasedServicesConfigListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
index 98c1a6ff61c05d6653d494c650aec1aa6b4f6e44..c0578da290b61455183294d0e4168f8566b9b86d 100644 (file)
@@ -81,6 +81,7 @@ public class AlivenessMonitorUtils {
         if(!(ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)&& ifTunnel.isInternal())){
             return;
         }
+        LOG.debug("stop LLDP monitoring for {}", trunkInterface.getName());
         List<Long> monitorIds = getMonitorIdForInterface(dataBroker, trunkInterface.getName());
         if (monitorIds == null) {
             LOG.error("Monitor Id doesn't exist for Interface {}", trunkInterface);
@@ -144,23 +145,20 @@ public class AlivenessMonitorUtils {
             return;
         }
         LOG.debug("handling tunnel monitoring updates for interface {}", interfaceName);
-        // Restart LLDP monitoring only if it's started already
-        List<Long> monitorIds = getMonitorIdForInterface(dataBroker, interfaceName);
-        if (monitorIds != null && monitorIds.size() > 1) {
-                stopLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceOld);
-                if(ifTunnelNew.isMonitorEnabled()) {
-                    startLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceNew);
 
-                    // Delete old profile from Aliveness Manager
-                    IfTunnel ifTunnelOld = interfaceOld.getAugmentation(IfTunnel.class);
-                    if(ifTunnelNew.getMonitorInterval() != ifTunnelOld.getMonitorInterval()) {
-                        LOG.debug("deleting older monitor profile for interface {}", interfaceName);
-                        long profileId = allocateProfile(alivenessMonitorService, FAILURE_THRESHOLD, ifTunnelOld.getMonitorInterval(), MONITORING_WINDOW, EtherTypes.Lldp);
-                        MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder().setProfileId(profileId).build();
-                        alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
-                    }
-                }
+        stopLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceOld);
+        if(ifTunnelNew.isMonitorEnabled()) {
+            startLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceNew);
+
+            // Delete old profile from Aliveness Manager
+            IfTunnel ifTunnelOld = interfaceOld.getAugmentation(IfTunnel.class);
+            if(ifTunnelNew.getMonitorInterval() != ifTunnelOld.getMonitorInterval()) {
+                LOG.debug("deleting older monitor profile for interface {}", interfaceName);
+                long profileId = allocateProfile(alivenessMonitorService, FAILURE_THRESHOLD, ifTunnelOld.getMonitorInterval(), MONITORING_WINDOW, EtherTypes.Lldp);
+                MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder().setProfileId(profileId).build();
+                alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
             }
+        }
     }
 
 
@@ -224,13 +222,37 @@ public class AlivenessMonitorUtils {
             if(rpcResult.isSuccessful()) {
                 return rpcResult.getResult().getProfileId();
             } else {
-                LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}", rpcResult.getErrors());
+                LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID", rpcResult.getErrors());
+                try{
+                    Profile createProfile = monitorProfileCreateInput.getProfile();
+                    Future<RpcResult<MonitorProfileGetOutput>> existingProfile = alivenessMonitor.monitorProfileGet(buildMonitorGetProfile(createProfile.getMonitorInterval(), createProfile.getMonitorWindow(), createProfile.getFailureThreshold(), createProfile.getProtocolType()));
+                    RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
+                    if(rpcGetResult.isSuccessful()){
+                        return rpcGetResult.getResult().getProfileId();
+                    }else{
+                        LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}", rpcGetResult.getErrors());
+                    }
+                }catch(Exception e){
+                    LOG.warn("Exception when getting existing profile",e);
+                }
             }
         } catch (InterruptedException | ExecutionException e) {
             LOG.warn("Exception when allocating profile Id",e);
         }
         return 0;
     }
+
+    private static MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval, long monitorWindow, long failureThreshold, EtherTypes protocolType){
+        MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.get.input.ProfileBuilder profileBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.get.input.ProfileBuilder();
+        profileBuilder.setFailureThreshold(failureThreshold);
+        profileBuilder.setMonitorInterval(monitorInterval);
+        profileBuilder.setMonitorWindow(monitorWindow);
+        profileBuilder.setProtocolType(protocolType);
+        buildGetProfile.setProfile(profileBuilder.build());
+        return (buildGetProfile.build());
+    };
+
     public static long allocateProfile(AlivenessMonitorService alivenessMonitor, long FAILURE_THRESHOLD, long MONITORING_INTERVAL,
                                               long MONITORING_WINDOW, EtherTypes etherTypes) {
         MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().
index bb9d5d14974bb50027405a5541d2e3a97de4b9bd..c1e389358bb4dfcdd27cc1f06af5bbb0a08dadfe 100644 (file)
@@ -99,6 +99,12 @@ public class InterfaceManagerCommonUtils {
         }
         return vxlanList;
     }
+
+    public static Interface getInterfaceFromConfigDS(String interfaceName, DataBroker dataBroker) {
+        InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
+        return getInterfaceFromConfigDS(interfaceKey, dataBroker);
+    }
+
     public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
         InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
         Optional<Interface> interfaceOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION, interfaceId, dataBroker);
@@ -112,6 +118,11 @@ public class InterfaceManagerCommonUtils {
     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(String interfaceName, DataBroker dataBroker) {
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
                 IfmUtil.buildStateInterfaceId(interfaceName);
+        return getInterfaceStateFromOperDS(ifStateId, dataBroker);
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS
+            (InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId, DataBroker dataBroker) {
         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional =
                 IfmUtil.read(LogicalDatastoreType.OPERATIONAL, ifStateId, dataBroker);
         if (!ifStateOptional.isPresent()) {
@@ -158,19 +169,6 @@ public class InterfaceManagerCommonUtils {
         MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, interfaceData);
     }
 
-    public static void updateTunnelMonitorDetailsInConfigDS(DataBroker broker, String interfaceName, boolean monitorEnabled, long monitorInterval) {
-        InstanceIdentifier<Interface> id = IfmUtil.buildId(interfaceName);
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder();
-        ifaceBuilder.setKey(new InterfaceKey(interfaceName));
-        IfTunnelBuilder ifTunnelBuilder = new IfTunnelBuilder();
-        ifTunnelBuilder.setMonitorEnabled(monitorEnabled);
-        ifTunnelBuilder.setMonitorInterval(monitorInterval);
-        ifaceBuilder.addAugmentation(IfTunnel.class, ifTunnelBuilder.build());
-
-        LOG.trace("Updating trunk interface {} in Config DS", interfaceName);
-        MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, id, ifaceBuilder.build());
-    }
-
     public static void createInterfaceChildEntry( WriteTransaction t,
                                                   String parentInterface, String childInterface){
         InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(parentInterface);
@@ -257,7 +255,7 @@ public class InterfaceManagerCommonUtils {
         // install ingress flow
         BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
         long portNo = Long.valueOf(IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId));
-        if(interfaceInfo.isEnabled() && ifState.getOperStatus() == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
+        if(interfaceInfo != null && interfaceInfo.isEnabled() && ifState.getOperStatus() == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
             List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForVlanPortAtIngressTable(dpId, portNo, interfaceInfo);
             FlowBasedServicesUtils.installVlanFlow(dpId, portNo, interfaceInfo, transaction, matches, ifIndex);
         }
@@ -360,9 +358,9 @@ public class InterfaceManagerCommonUtils {
      */
     public static void updateOpState(WriteTransaction transaction, String interfaceName,
                                      org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus operStatus){
-        LOG.debug("updating tep interface state for {}", interfaceName);
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
                 IfmUtil.buildStateInterfaceId(interfaceName);
+        LOG.debug("updating tep interface state as {} for {}", operStatus.name(), interfaceName);
         InterfaceBuilder ifaceBuilder = new InterfaceBuilder().setOperStatus(operStatus);
         ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(interfaceName));
         transaction.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
index b768b406eadfb2df1fc865400653221c5ca81850..82ff6cfbbae536604113d25236a25e921e0475e6 100644 (file)
@@ -99,6 +99,7 @@ public class InterfaceMetaUtils {
         BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
         InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier =
                 InterfaceMetaUtils.getBridgeEntryIdentifier(bridgeEntryKey);
+        LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
         return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier,
                         dataBroker);
     }
@@ -121,17 +122,6 @@ public class InterfaceMetaUtils {
 
     }
 
-    public static BridgeInterfaceEntry getBridgeInterfaceEntryFromConfigDS(
-            InstanceIdentifier<BridgeInterfaceEntry> bridgeInterfaceEntryInstanceIdentifier, DataBroker dataBroker) {
-        Optional<BridgeInterfaceEntry> bridgeInterfaceEntryOptional =
-                IfmUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeInterfaceEntryInstanceIdentifier, dataBroker);
-        if (!bridgeInterfaceEntryOptional.isPresent()) {
-            return null;
-        }
-        return bridgeInterfaceEntryOptional.get();
-    }
-
-
     public static void createBridgeInterfaceEntryInConfigDS(BridgeEntryKey bridgeEntryKey,
                                                              BridgeInterfaceEntryKey bridgeInterfaceEntryKey,
                                                              String childInterface,
@@ -160,6 +150,14 @@ public class InterfaceMetaUtils {
         return intfIdBuilder.build();
     }
 
+    public static InterfaceParentEntry getInterfaceParentEntryFromConfigDS(
+            String interfaceName, DataBroker dataBroker) {
+        InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(interfaceName);
+        InterfaceParentEntry interfaceParentEntry =
+                InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceParentEntryKey, dataBroker);
+        return interfaceParentEntry;
+    }
+
     public static InterfaceParentEntry getInterfaceParentEntryFromConfigDS(
             InterfaceParentEntryKey interfaceParentEntryKey, DataBroker dataBroker) {
         InstanceIdentifier<InterfaceParentEntry> intfParentIid =
@@ -204,16 +202,6 @@ public class InterfaceMetaUtils {
         t.put(LogicalDatastoreType.OPERATIONAL, id, ifIndexInterface, true);
     }
 
-    public static void removeLportTagInterfaceMap(WriteTransaction t, IdManagerService idManager, DataBroker broker, String infName, Integer ifIndex) {
-        InstanceIdentifier<IfIndexInterface> id = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(ifIndex)).build();
-        Optional<IfIndexInterface> ifIndexesInterface = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker);
-        if(ifIndexesInterface.isPresent()) {
-           LOG.debug("removing lport tag to interface map for {}",infName);
-           t.delete(LogicalDatastoreType.OPERATIONAL, id);
-        }
-        IfmUtil.releaseId(idManager, IfmConstants.IFM_IDPOOL_NAME, infName);
-    }
-
     public static void createBridgeRefEntry(BigInteger dpnId, InstanceIdentifier<?> bridgeIid,
                                             WriteTransaction tx){
         LOG.debug("Creating bridge ref entry for dpn: {} bridge: {}",
index 9f8b84ccbec423903a66eddd2c5f65da6ba3592f..e7ddbab96818417fa896196b0280669c21daaa92 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -52,23 +52,17 @@ public class AlivenessMonitorListener implements org.opendaylight.yang.gen.v1.ur
     @Override
     public void onMonitorEvent(MonitorEvent notification) {
         Long monitorId = notification.getEventData().getMonitorId();
-        String trunkInterfaceName = AlivenessMonitorUtils.getInterfaceFromMonitorId(dataBroker, monitorId);
-        if (trunkInterfaceName == null) {
-            LOG.debug("Either monitoring for interface - {} not started by Interfacemgr or it is not LLDP monitoring", trunkInterfaceName);
+        String tunnelInterface = AlivenessMonitorUtils.getInterfaceFromMonitorId(dataBroker, monitorId);
+        if (tunnelInterface == null) {
+            LOG.debug("Either monitoring for interface - {} not started by Interfacemgr or it is not LLDP monitoring", tunnelInterface);
             return;
         }
         LivenessState livenessState = notification.getEventData().getMonitorState();
-        Interface interfaceInfo = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(trunkInterfaceName),
-                dataBroker);
-        IfTunnel tunnelInfo = interfaceInfo.getAugmentation(IfTunnel.class);
-        // Not handling monitoring event if it is GRE Trunk Interface.
-        if (tunnelInfo.getTunnelInterfaceType().isAssignableFrom(TunnelTypeGre.class)) {
-            return;
-        }
+        LOG.debug("received monitor event for {} with livenessstate {}", tunnelInterface, livenessState);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState =
                 livenessState == LivenessState.Up ? org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up :
                         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Down;
-        InterfaceManagerCommonUtils.setOpStateForInterface(dataBroker, trunkInterfaceName, opState);
+        InterfaceManagerCommonUtils.setOpStateForInterface(dataBroker, tunnelInterface, opState);
     }
 
-}
\ No newline at end of file
+}
index 99f6a8026b03d7b6046426f553ee7e6fff8df40f..4bec4051957f6eea59bb4bfb024c9d8b075e5a1b 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
 import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateRemoveHelper;
 import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateUpdateHelper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
@@ -52,15 +53,18 @@ public class HwVTEPTunnelsStateListener extends AsyncDataChangeListenerBase<Tunn
     }
 
     @Override
-    protected void remove(InstanceIdentifier<Tunnels> identifier, Tunnels tunnelOld) {
-        LOG.info("Received Remove DataChange Notification for identifier: {}, physicalSwitchAugmentation: {}",
-                identifier, tunnelOld);
+    protected void remove(InstanceIdentifier<Tunnels> identifier, Tunnels tunnel) {
+        LOG.debug("Received Remove DataChange Notification for identifier: {}, physicalSwitchAugmentation: {}",
+                identifier, tunnel);
+        DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
+        RendererStateRemoveWorker rendererStateRemoveWorker = new RendererStateRemoveWorker(identifier, tunnel);
+        jobCoordinator.enqueueJob(tunnel.getTunnelUuid().getValue(), rendererStateRemoveWorker);
     }
 
     @Override
     protected void update(InstanceIdentifier<Tunnels> identifier, Tunnels tunnelOld,
                           Tunnels tunnelNew) {
-        LOG.info("Received Update Tunnel Update Notification for identifier: {}", identifier);
+        LOG.debug("Received Update Tunnel Update Notification for identifier: {}", identifier);
         DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
         RendererStateUpdateWorker rendererStateUpdateWorker = new RendererStateUpdateWorker(identifier, tunnelNew, tunnelOld);
         jobCoordinator.enqueueJob(tunnelNew.getTunnelUuid().getValue(), rendererStateUpdateWorker);
@@ -68,7 +72,7 @@ public class HwVTEPTunnelsStateListener extends AsyncDataChangeListenerBase<Tunn
 
     @Override
     protected void add(InstanceIdentifier<Tunnels> identifier, Tunnels tunnelNew) {
-        LOG.info("Received Add DataChange Notification for identifier: {}, tunnels: {}",
+        LOG.debug("Received Add DataChange Notification for identifier: {}, tunnels: {}",
                 identifier, tunnelNew);
         DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
         RendererStateAddWorker rendererStateAddWorker = new RendererStateAddWorker(identifier, tunnelNew);
@@ -113,4 +117,22 @@ public class HwVTEPTunnelsStateListener extends AsyncDataChangeListenerBase<Tunn
             return HwVTEPInterfaceStateUpdateHelper.startBfdMonitoring(dataBroker, instanceIdentifier, tunnelsNew);
         }
     }
-}
\ No newline at end of file
+
+    private class RendererStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+        InstanceIdentifier<Tunnels> instanceIdentifier;
+        Tunnels tunnel;
+
+        public RendererStateRemoveWorker(InstanceIdentifier<Tunnels> instanceIdentifier,
+                                      Tunnels tunnel) {
+            this.instanceIdentifier = instanceIdentifier;
+            this.tunnel = tunnel;
+        }
+
+        @Override
+        public List<ListenableFuture<Void>> call() throws Exception {
+            // If another renderer(for eg : CSS) needs to be supported, check can be performed here
+            // to call the respective helpers.
+            return HwVTEPInterfaceStateRemoveHelper.removeExternalTunnel(dataBroker, instanceIdentifier);
+        }
+    }
+}
index d2e56baf4480f2d9eba7487bff33448cc7f6f2de..cfafe2097465a84aad41088549c8755f9695ffd1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -69,7 +69,7 @@ public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase
 
     @Override
     protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
-        return AsyncDataBroker.DataChangeScope.BASE;
+        return AsyncDataBroker.DataChangeScope.ONE;
     }
 
     @Override
@@ -210,4 +210,4 @@ public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase
                     '}';
         }
     }
-}
\ No newline at end of file
+}
index 9d9debcd6e78b3feff75f08cca346c7146a07552..2b14757fbc956692eea5a9d5efff7d231d001f0d 100644 (file)
@@ -48,7 +48,7 @@ public class TerminationPointStateListener extends AsyncDataChangeListenerBase<O
 
     @Override
     protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
-        return AsyncDataBroker.DataChangeScope.ONE;
+        return AsyncDataBroker.DataChangeScope.SUBTREE;
     }
 
     @Override
@@ -60,10 +60,11 @@ public class TerminationPointStateListener extends AsyncDataChangeListenerBase<O
     protected void update(InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
                           OvsdbTerminationPointAugmentation tpOld,
                           OvsdbTerminationPointAugmentation tpNew) {
-        LOG.debug("Received Update DataChange Notification for ovsdb termination point identifier: {},  old: {}, new: {}.",
-                identifier, tpOld, tpNew);
+        LOG.debug("Received Update DataChange Notification for ovsdb termination point {}", tpNew.getName());
         if (tpNew.getInterfaceBfdStatus() != null &&
                 !tpNew.getInterfaceBfdStatus().equals(tpOld.getInterfaceBfdStatus())) {
+            LOG.trace("Bfd Status changed for ovsdb termination point identifier: {},  old: {}, new: {}.",
+                    identifier, tpOld, tpNew);
             DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
             RendererStateUpdateWorker rendererStateAddWorker = new RendererStateUpdateWorker(identifier, tpNew, tpOld);
             jobCoordinator.enqueueJob(tpNew.getName(), rendererStateAddWorker);
index a91fcce9a1dfad697ea5c287f6589730000c166a..0b63cb3d903beed70a3f2edfdf1dc3abfe9d01e8 100644 (file)
@@ -7,10 +7,13 @@
  */
 package org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.confighelpers;
 
+import com.google.common.base.Optional;
 import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
 import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.utilities.SouthboundUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
@@ -30,6 +33,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,7 +53,7 @@ public class HwVTEPInterfaceConfigUpdateHelper {
         // create hwvtep through ovsdb plugin
         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
         if(globalNodeId != null) {
-            updateBfdMonitoring(dataBroker, physicalSwitchNodeId, ifTunnel);
+            updateBfdMonitoring(dataBroker, globalNodeId, physicalSwitchNodeId, ifTunnel);
 
         }else{
             LOG.debug("specified physical switch is not connected {}", physicalSwitchNodeId);
@@ -61,23 +65,23 @@ public class HwVTEPInterfaceConfigUpdateHelper {
     /*
      * bfd monitoring interval and enable/disbale attributes can be modified
      */
-    public static List<ListenableFuture<Void>> updateBfdMonitoring(DataBroker dataBroker, InstanceIdentifier<Node> nodeId,
+    public static List<ListenableFuture<Void>> updateBfdMonitoring(DataBroker dataBroker, InstanceIdentifier<Node> globalNodeId, InstanceIdentifier<Node> physicalSwitchId,
                                                                    IfTunnel ifTunnel) {
         List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
         TunnelsBuilder tBuilder = new TunnelsBuilder();
         InstanceIdentifier<TerminationPoint> localTEPInstanceIdentifier =
-                SouthboundUtils.createTEPInstanceIdentifier(nodeId, ifTunnel.getTunnelSource());
+                SouthboundUtils.createTEPInstanceIdentifier(globalNodeId, ifTunnel.getTunnelSource());
         InstanceIdentifier<TerminationPoint> remoteTEPInstanceIdentifier =
-                SouthboundUtils.createTEPInstanceIdentifier(nodeId, ifTunnel.getTunnelDestination());
+                SouthboundUtils.createTEPInstanceIdentifier(globalNodeId, ifTunnel.getTunnelDestination());
         InstanceIdentifier<Tunnels> tunnelsInstanceIdentifier = SouthboundUtils.
-                createTunnelsInstanceIdentifier(nodeId, localTEPInstanceIdentifier, remoteTEPInstanceIdentifier);
+                createTunnelsInstanceIdentifier(physicalSwitchId, localTEPInstanceIdentifier, remoteTEPInstanceIdentifier);
 
         LOG.debug("updating bfd monitoring parameters for the hwvtep {}", tunnelsInstanceIdentifier);
         tBuilder.setKey(new TunnelsKey(new HwvtepPhysicalLocatorRef(localTEPInstanceIdentifier),
                 new HwvtepPhysicalLocatorRef(remoteTEPInstanceIdentifier)));
         List <BfdParams> bfdParams = new ArrayList<>();
-        SouthboundUtils.fillBfdParameters(bfdParams, null);
+        SouthboundUtils.fillBfdParameters(bfdParams, ifTunnel);
         tBuilder.setBfdParams(bfdParams);
         transaction.merge(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier,tBuilder.build(), true);
         futures.add(transaction.submit());
diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateRemoveHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/hwvtep/statehelpers/HwVTEPInterfaceStateRemoveHelper.java
new file mode 100644 (file)
index 0000000..54407d7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers;
+
+import com.google.common.util.concurrent.ListenableFuture;
+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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HwVTEPInterfaceStateRemoveHelper {
+    private static final Logger LOG = LoggerFactory.getLogger(HwVTEPInterfaceStateRemoveHelper.class);
+
+    public static List<ListenableFuture<Void>> removeExternalTunnel(DataBroker dataBroker,
+                                                                  InstanceIdentifier<Tunnels> tunnelsInstanceIdentifier) {
+        List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+        LOG.debug("Removing HwVTEP tunnel entries for tunnel: {}", tunnelsInstanceIdentifier);
+        WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+        transaction.delete(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier);
+        futures.add(transaction.submit());
+        return futures;
+    }
+}
index c3b4d3eb80d8c45495a7f01c8c0c9e8152e5e8d1..94d774ce6b569513393686782105fcdcf090b414 100644 (file)
@@ -102,18 +102,6 @@ public class SouthboundUtils {
         return (InstanceIdentifier<Node>) physicalSwitchAugmentation.getManagedBy().getValue();
     }
 
-    public static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(NodeKey nodekey,
-                                                                                                String portName){
-        InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
-                .create(NetworkTopology.class)
-                .child(Topology.class, new TopologyKey(HWVTEP_TOPOLOGY_ID))
-                .child(Node.class,nodekey)
-                .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
-
-        LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
-        return terminationPointPath;
-    }
-
     public static InstanceIdentifier<TerminationPoint> createTEPInstanceIdentifier
             (InstanceIdentifier<Node> nodeIid,  IpAddress ipAddress) {
         TerminationPointKey localTEP = SouthboundUtils.getTerminationPointKey(ipAddress.getIpv4Address().getValue());
@@ -143,9 +131,11 @@ public class SouthboundUtils {
                                                                               InstanceIdentifier<TerminationPoint> remoteTEPInstanceIdentifier) {
         TunnelsKey tunnelsKey = new TunnelsKey(new HwvtepPhysicalLocatorRef(localTEPInstanceIdentifier),
                 new HwvtepPhysicalLocatorRef(remoteTEPInstanceIdentifier));
-        return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(HWVTEP_TOPOLOGY_ID))
+
+        InstanceIdentifier<Tunnels> tunnelInstanceId = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(HWVTEP_TOPOLOGY_ID))
                 .child(Node.class, new NodeKey(nodeId.firstKeyOf(Node.class))).augmentation(PhysicalSwitchAugmentation.class)
                 .child(Tunnels.class, tunnelsKey).build();
+        return tunnelInstanceId;
     }
 
     public static String getTerminationPointKeyString(String ipAddress) {
@@ -166,16 +156,6 @@ public class SouthboundUtils {
         return tpKey;
     }
 
-    public static TerminationPoint getTEPFromConfigDS(InstanceIdentifier<TerminationPoint> tpPath,
-                                                      DataBroker dataBroker) {
-        Optional<TerminationPoint> terminationPointOptional =
-                IfmUtil.read(LogicalDatastoreType.CONFIGURATION, tpPath, dataBroker);
-        if (!terminationPointOptional.isPresent()) {
-            return null;
-        }
-        return terminationPointOptional.get();
-    }
-
     public static void setDstIp(HwvtepPhysicalLocatorAugmentationBuilder tpAugmentationBuilder, IpAddress ipAddress) {
         IpAddress ip = new IpAddress(ipAddress);
         tpAugmentationBuilder.setDstIp(ip);
index e0086804dd3d0c53aecef61361e849cf64cb4417..fde4bb0c4d7714ecda5eca654281de0f5447f7a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -55,35 +55,6 @@ public class OvsVlanMemberConfigAddHelper {
         if (ifState != null) {
             LOG.debug("add interface state info for vlan member {}",interfaceNew.getName());
             InterfaceManagerCommonUtils.addStateEntry(interfaceNew.getName(), t, dataBroker, idManager, ifState);
-
-
-            // FIXME: Maybe, add the new interface to the higher-layer if of the parent interface-state.
-            // That may not serve any purpose though for interface manager.... Unless some external parties are interested in it.
-
-            /* FIXME -- Below code is needed to add vlan-trunks to the of-port. Is this really needed.
-            String lowerLayerIf = ifState.getLowerLayerIf().get(0);
-
-            NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
-            BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
-
-            BridgeRefEntryKey BridgeRefEntryKey = new BridgeRefEntryKey(dpId);
-            InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid =
-                    InterfaceMetaUtils.getBridgeRefEntryIdentifier(BridgeRefEntryKey);
-            BridgeRefEntry bridgeRefEntry =
-                    InterfaceMetaUtils.getBridgeRefEntryFromOperDS(dpnBridgeEntryIid, dataBroker);
-            if (bridgeRefEntry != null) {
-                InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
-                        (InstanceIdentifier<OvsdbBridgeAugmentation>)bridgeRefEntry.getBridgeReference().getValue();
-                Optional<OvsdbBridgeAugmentation> bridgeNodeOptional =
-                        IfmUtil.read(LogicalDatastoreType.OPERATIONAL, bridgeIid, dataBroker);
-                if (bridgeNodeOptional.isPresent()) {
-                    OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNodeOptional.get();
-                    String bridgeName = ovsdbBridgeAugmentation.getBridgeName().getValue();
-                    VlanTrunkSouthboundUtils.addVlanPortToBridge(bridgeIid, ifL2vlan,
-                            ovsdbBridgeAugmentation, bridgeName, parentRefs.getParentInterface(), dataBroker, t);
-                }
-            } */
-            // FIXME: Need to add the Group here with actions: Push-Vlan, output_port. May not be needed here...
         }
 
         futures.add(t.submit());
index 9360c57059e16cc625c7cc5bf6d0b2c49ed312ad..b005d4051c8d1ea818221bb4b58865ef304a8528 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -94,7 +94,7 @@ public class OvsInterfaceStateRemoveHelper {
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface>
                 higerLayerChildIfStateId = IfmUtil.buildStateInterfaceId(higherlayerChild.getChildInterface());
         Interface higherLayerIfChildState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(higherlayerChild.getChildInterface(), dataBroker);
-        if (interfaceState != null) {
+        if (interfaceState != null && higherLayerIfChildState != null) {
             transaction.delete(LogicalDatastoreType.OPERATIONAL, higerLayerChildIfStateId);
             FlowBasedServicesUtils.removeIngressFlow(higherLayerIfChildState.getName(), dpId, transaction);
         }
@@ -139,4 +139,4 @@ public class OvsInterfaceStateRemoveHelper {
         futures.add(transaction.submit());
         return futures;
     }
-}
\ No newline at end of file
+}
index d3acbc741b08b14444f05a505ed5036f0fc55c17..eb63773b20ca131c31746c5cb32425e84fd40d0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -15,21 +15,25 @@ import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
 import org.opendaylight.vpnservice.interfacemgr.commons.AlivenessMonitorUtils;
 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
 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.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.AlivenessMonitorService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -43,112 +47,135 @@ public class OvsInterfaceStateUpdateHelper {
                                                            FlowCapableNodeConnector flowCapableNodeConnectorOld) {
         LOG.debug("Update of Interface State for port: {}", portName);
         List<ListenableFuture<Void>> futures = new ArrayList<>();
-        WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+        WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
 
-        Interface.OperStatus operStatusNew =
-                flowCapableNodeConnectorNew.getState().isLinkDown() ? Interface.OperStatus.Down : Interface.OperStatus.Up;
-        Interface.AdminStatus adminStatusNew =
-                flowCapableNodeConnectorNew.getState().isBlocked() ? Interface.AdminStatus.Down : Interface.AdminStatus.Up;
+        Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
         MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
 
-        Interface.OperStatus operStatusOld =
-                flowCapableNodeConnectorOld.getState().isLinkDown() ? Interface.OperStatus.Down : Interface.OperStatus.Up;
-        Interface.AdminStatus adminStatusOld =
-                flowCapableNodeConnectorOld.getState().isBlocked() ? Interface.AdminStatus.Down : Interface.AdminStatus.Up;
+        Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
         MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
 
         boolean opstateModified = false;
-        boolean adminStateModified = false;
         boolean hardwareAddressModified = false;
         if (!operStatusNew.equals(operStatusOld)) {
             opstateModified = true;
         }
-        if (!adminStatusNew.equals(adminStatusOld)) {
-            adminStateModified = true;
-        }
         if (!macAddressNew.equals(macAddressOld)) {
             hardwareAddressModified = true;
         }
 
-        if (!opstateModified && !adminStateModified && !hardwareAddressModified) {
+        if (!opstateModified && !hardwareAddressModified) {
             LOG.debug("If State entry for port: {} Not Modified.", portName);
             return futures;
         }
 
-        InstanceIdentifier<Interface> ifStateId = IfmUtil.buildStateInterfaceId(portName);
         InterfaceBuilder ifaceBuilder = new InterfaceBuilder();
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = null;
-        boolean modified = false;
-        if (opstateModified) {
-            LOG.debug("Opstate Modified for Port: {}", portName);
-            InterfaceKey interfaceKey = new InterfaceKey(portName);
-             iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceKey, dataBroker);
-
-            // If interface config admin state is disabled, set operstate of the Interface State entity to Down.
-            if (iface != null && !iface.isEnabled()) {
-                operStatusNew = Interface.OperStatus.Down;
-            }
-
-            ifaceBuilder.setOperStatus(operStatusNew);
-            modified = true;
-        }
-
-        if (adminStateModified) {
-            LOG.debug("Admin state Modified for Port: {}", portName);
-            ifaceBuilder.setAdminStatus(adminStatusNew);
-            modified = true;
-        }
-
         if (hardwareAddressModified) {
             LOG.debug("Hw-Address Modified for Port: {}", portName);
             PhysAddress physAddress = new PhysAddress(macAddressNew.getValue());
             ifaceBuilder.setPhysAddress(physAddress);
-            modified = true;
         }
 
-        /* FIXME: Is there chance that lower layer node-connector info is updated.
-                  Not Considering for now.
-         */
-
-        if (modified) {
-            ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(portName));
-            t.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
-
-            InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(portName);
-            InterfaceParentEntry interfaceParentEntry =
-                    InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceParentEntryKey, dataBroker);
-            if (interfaceParentEntry == null || interfaceParentEntry.getInterfaceChildEntry() == null) {
-                futures.add(t.submit());
-                // start/stop monitoring based on opState
-                IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
-                if(ifTunnel != null) {
-                    if (operStatusNew == Interface.OperStatus.Down)
-                        AlivenessMonitorUtils.stopLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
-                    else
-                        AlivenessMonitorUtils.startLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
-                }
-                return futures;
-            }
-            for(InterfaceChildEntry higherlayerChild : interfaceParentEntry.getInterfaceChildEntry()) {
-                InstanceIdentifier<Interface> higherLayerIfChildStateId =
-                        IfmUtil.buildStateInterfaceId(higherlayerChild.getChildInterface());
-                t.merge(LogicalDatastoreType.OPERATIONAL, higherLayerIfChildStateId, ifaceBuilder.build());
-                InterfaceParentEntryKey higherLayerParentEntryKey = new InterfaceParentEntryKey(higherlayerChild.getChildInterface());
+        NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                handleInterfaceStateUpdates(portName, nodeConnectorId,
+                transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
+
+        InterfaceParentEntry interfaceParentEntry =
+                InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(portName, dataBroker);
+        if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
+            for (InterfaceChildEntry higherlayerChild : interfaceParentEntry.getInterfaceChildEntry()) {
+                handleInterfaceStateUpdates(higherlayerChild.getChildInterface(),
+                        nodeConnectorId, transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
                 InterfaceParentEntry higherLayerParent =
-                        InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(higherLayerParentEntryKey, dataBroker);
-                if(higherLayerParent != null && higherLayerParent.getInterfaceChildEntry() != null) {
+                        InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(higherlayerChild.getChildInterface(), dataBroker);
+                if (higherLayerParent != null && higherLayerParent.getInterfaceChildEntry() != null) {
                     for (InterfaceChildEntry interfaceChildEntry : higherLayerParent.getInterfaceChildEntry()) {
-                        LOG.debug("Updating if-state entries for Vlan-Trunk Members for port: {}", portName);
                         //FIXME: If the no. of child entries exceeds 100, perform txn updates in batches of 100.
-                        InstanceIdentifier<Interface> ifChildStateId =
-                                IfmUtil.buildStateInterfaceId(interfaceChildEntry.getChildInterface());
-                        t.merge(LogicalDatastoreType.OPERATIONAL, ifChildStateId, ifaceBuilder.build());
+                        handleInterfaceStateUpdates(interfaceChildEntry.getChildInterface(), nodeConnectorId,
+                                transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
                     }
                 }
             }
+        }else {
+            handleTunnelMonitoringUpdates(alivenessMonitorService, dataBroker, iface, operStatusNew, opstateModified);
         }
-
-        futures.add(t.submit());
+        futures.add(transaction.submit());
         return futures;
     }
-}
\ No newline at end of file
+
+    public static Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector){
+        Interface.OperStatus operStatus =
+                (flowCapableNodeConnector.getState().isLive() &&
+                        !flowCapableNodeConnector.getConfiguration().isPORTDOWN())
+                        ? Interface.OperStatus.Up: Interface.OperStatus.Down;
+        return operStatus;
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
+    handleInterfaceStateUpdates(String interfaceName, NodeConnectorId nodeConnectorId,WriteTransaction transaction,
+                                DataBroker dataBroker, InterfaceBuilder ifaceBuilder, boolean opStateModified,
+                                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState){
+        LOG.debug("updating interface state entry for {}", interfaceName);
+        InstanceIdentifier<Interface> ifStateId = IfmUtil.buildStateInterfaceId(interfaceName);
+        ifaceBuilder.setKey(new InterfaceKey(interfaceName));
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
+        if (modifyOpState(iface, opStateModified)) {
+            LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
+            ifaceBuilder.setOperStatus(opState);
+        }
+        transaction.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
+
+        // if opstate has changed, add or remove ingress flow for l2vlan interfaces accordingly
+        if(modifyIngressFlow(iface, opStateModified)) {
+            handleVlanIngressFlowUpdates(dataBroker, opState, transaction, iface, nodeConnectorId, ifStateId);
+        }
+        return iface;
+    }
+
+    public static void handleTunnelMonitoringUpdates(AlivenessMonitorService alivenessMonitorService, DataBroker dataBroker,
+                                                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+                                                     Interface.OperStatus operStatus, boolean opStateModified){
+        // start/stop monitoring based on opState
+        if(!modifyTunnel(iface, opStateModified)){
+            return;
+        }
+
+        LOG.debug("handling tunnel monitoring updates for {} due to opstate modification", iface.getName());
+        if (operStatus == Interface.OperStatus.Down)
+            AlivenessMonitorUtils.stopLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
+        else
+            AlivenessMonitorUtils.startLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
+    }
+
+    public static boolean modifyOpState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+                                        boolean opStateModified){
+        return (opStateModified && (iface == null || iface != null && iface.isEnabled()));
+    }
+
+    public static boolean modifyIngressFlow(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+                                        boolean opStateModified){
+        return modifyOpState(iface, opStateModified) && iface != null && iface.getAugmentation(IfTunnel.class) == null;
+    }
+
+    public static boolean modifyTunnel(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+                                            boolean opStateModified){
+        return modifyOpState(iface, opStateModified) && iface != null && iface.getAugmentation(IfTunnel.class) != null;
+    }
+
+    public static void handleVlanIngressFlowUpdates(DataBroker dataBroker, Interface.OperStatus opState, WriteTransaction transaction,
+                                                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+                                                    NodeConnectorId nodeConnectorId, InstanceIdentifier<Interface> ifStateId){
+        LOG.debug("handling vlan ingress flow updates for {}", iface.getName());
+        Interface ifState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(ifStateId, dataBroker);
+        BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
+        if (opState == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
+            long portNo = Long.valueOf(IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId));
+            List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
+            FlowBasedServicesUtils.installVlanFlow(dpId, portNo, iface, transaction, matches, ifState.getIfIndex());
+        } else {
+            FlowBasedServicesUtils.removeIngressFlow(iface.getName(), dpId, transaction);
+        }
+    }
+}
index 95f9e91ff3deb42d1479da2c05038d4a02eaab89..6bfb64d0442456b8ad4c6fd35c2b05d939764947 100644 (file)
@@ -52,12 +52,10 @@ public class OvsInterfaceTopologyStateAddHelper {
         // create bridge reference entry in interface meta operational DS
         InterfaceMetaUtils.createBridgeRefEntry(dpnId, bridgeIid, writeTransaction);
 
-        // FIX for OVSDB Bug - manually copying the bridge info from topology operational DS to config DS
-        SouthboundUtils.addBridge(bridgeIid, bridgeNew, dataBroker, futures);
-
         // handle pre-provisioning of tunnels for the newly connected dpn
         BridgeEntry bridgeEntry = InterfaceMetaUtils.getBridgeEntryFromConfigDS(dpnId, dataBroker);
         if (bridgeEntry == null) {
+            LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
             futures.add(writeTransaction.submit());
             return futures;
         }
index c607bff946801c333599c84ffd6571a53421e7a2..e64833f208a03372d3b5f3ca562d9838464f8a09 100644 (file)
@@ -43,13 +43,6 @@ public class OvsInterfaceTopologyStateRemoveHelper {
         //delete bridge reference entry in interface meta operational DS
         InterfaceMetaUtils.deleteBridgeRefEntry(dpnId, transaction);
 
-        // Workaround for ovsdb bug for delete TEP..
-        Optional<OvsdbBridgeAugmentation> bridgeNodeOptional =
-                IfmUtil.read(LogicalDatastoreType.OPERATIONAL, bridgeIid, dataBroker);
-        if (!bridgeNodeOptional.isPresent()) {
-            SouthboundUtils.deleteBridge(bridgeIid, dataBroker, futures);
-        }
-
         futures.add(transaction.submit());
         return futures;
     }
index 3ce9aecef9d5e8ad70734e4b6ad54f2971445a00..ae2b02b7e37df1cba0168be53e5772010872a3f8 100644 (file)
@@ -14,15 +14,10 @@ import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils;
 import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.utilities.SouthboundUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.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.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.bridge._interface.info.BridgeEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.bridge._interface.info.BridgeEntryKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.bridge._interface.info.bridge.entry.BridgeInterfaceEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,6 +65,9 @@ public class OvsInterfaceTopologyStateUpdateHelper {
                                                                  OvsdbTerminationPointAugmentation terminationPointOld) {
         List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
 
+        if (InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(terminationPointNew.getName(), dataBroker) == null) {
+            return futures;
+        }
         // update opstate of interface if TEP has gone down/up as a result of BFD monitoring
         LOG.debug("updating tunnel state for interface {}", terminationPointNew.getName());
         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
index 9fbd1b7dc063ab68e8ea57cc5269d67f50211a40..c10cc2e0789fff717b2acf1e26aa75bc872c99ad 100644 (file)
@@ -88,26 +88,6 @@ public class SouthboundUtils {
         }
     }
 
-    public static void addBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
-                                 OvsdbBridgeAugmentation bridgeAugmentation,
-                                 DataBroker dataBroker, List<ListenableFuture<Void>> futures){
-        WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-        NodeId nodeId = InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)).getNodeId();
-        NodeBuilder bridgeNodeBuilder = new NodeBuilder();
-        bridgeNodeBuilder.setNodeId(nodeId);
-        bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, bridgeAugmentation);
-        tx.put(LogicalDatastoreType.CONFIGURATION, createNodeInstanceIdentifier(nodeId), bridgeNodeBuilder.build(), true);
-        futures.add(tx.submit());
-    }
-
-    public static void deleteBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
-                                 DataBroker dataBroker, List<ListenableFuture<Void>> futures){
-        WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-        NodeId nodeId = InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)).getNodeId();
-        tx.delete(LogicalDatastoreType.CONFIGURATION, createNodeInstanceIdentifier(nodeId));
-        futures.add(tx.submit());
-    }
-
     private static void addVlanPortToBridge(InstanceIdentifier<?> bridgeIid, IfL2vlan ifL2vlan, IfTunnel ifTunnel,
                                               OvsdbBridgeAugmentation bridgeAugmentation, String bridgeName,
                                               String portName, DataBroker dataBroker, WriteTransaction t) {
@@ -142,7 +122,9 @@ public class SouthboundUtils {
         }
 
         Map<String, String> options = Maps.newHashMap();
-        options.put("key", "flow");
+        if(!ifTunnel.getTunnelInterfaceType().equals(TunnelTypeMplsOverGre.class) ) {
+            options.put("key", "flow");
+        }
 
         IpAddress localIp = ifTunnel.getTunnelSource();
         options.put("local_ip", localIp.getIpv4Address().getValue());
@@ -231,18 +213,6 @@ public class SouthboundUtils {
         return bfdBuilder.build();
     }
 
-    private 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 InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(NodeKey nodekey,
                                                                                                 String portName){
         InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
@@ -254,11 +224,4 @@ public class SouthboundUtils {
         LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
         return terminationPointPath;
     }
-
-    public static InstanceIdentifier<Node> createNodeInstanceIdentifier(NodeId nodeId) {
-        return InstanceIdentifier
-                .create(NetworkTopology.class)
-                .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
-                .child(Node.class,new NodeKey(nodeId));
-    }
 }
index 048f63867fd0f6ef16558497f232cc4960afc40c..86848182ffee5edce73891a544a7101425e44872 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
 import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.confighelpers.HwVTEPConfigRemoveHelper;
 import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.confighelpers.HwVTEPInterfaceConfigAddHelper;
+import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateRemoveHelper;
 import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateUpdateHelper;
 import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.utilities.SouthboundUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
@@ -73,6 +74,7 @@ public class HwVTEPConfigurationTest {
     HwVTEPInterfaceConfigAddHelper addHelper;
     HwVTEPConfigRemoveHelper removeHelper;
     HwVTEPInterfaceStateUpdateHelper updateHelper;
+    HwVTEPInterfaceStateRemoveHelper stateRemoveHelper;
 
     BigInteger dpId = BigInteger.valueOf(1);
     Interface hwVTEPInterfaceEnabled;
@@ -206,4 +208,13 @@ public class HwVTEPConfigurationTest {
         //Verify
         verify(mockWriteTx).put(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier, tBuilder.build(), true);
     }
+
+    @Test
+    public void testRemoveExternalTunnels(){
+
+        stateRemoveHelper.removeExternalTunnel(dataBroker, tunnelsInstanceIdentifier);
+
+        //Verify
+        verify(mockWriteTx).delete(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier);
+    }
 }
index 28bb764393cf92e733afc7e81017934671575988..61713ed483bd57e64b235eaf5be6fc80ab202bd1 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
@@ -40,6 +41,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 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.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
 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;
@@ -105,10 +109,21 @@ import java.util.*;
 
 public class InterfaceManagerTestUtil {
     public static final String interfaceName = "s1-eth1";
-    public static final String interfaceName2 = "s1-eth2";
+    public static final String childInterface = "s1-eth1-trunk";
     public static final String tunnelInterfaceName = "s2-gre1";
     public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
 
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface buildStateInterface(String ifaceName, String physAddress,
+                                                                                                                                                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState){
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
+        if(physAddress != null) {
+            ifaceBuilder.setPhysAddress(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress.getDefaultInstance(physAddress));
+        }
+        ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(ifaceName));
+        ifaceBuilder.setOperStatus(opState);
+        return ifaceBuilder.build();
+    }
+
     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface buildStateInterface(
             String ifName, NodeConnectorId ncId) {
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder =
@@ -170,7 +185,7 @@ public class InterfaceManagerTestUtil {
         IpAddress remoteIp = new IpAddress(Ipv4Address.getDefaultInstance(remoteIpStr));
         IpAddress localIp =  new IpAddress(Ipv4Address.getDefaultInstance(localIpStr));
         IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(remoteIp).setTunnelGateway(localIp).setTunnelSource(localIp)
-                    .setTunnelInterfaceType( tunType).setInternal(true).build();
+                    .setTunnelInterfaceType( tunType).setInternal(true).setMonitorEnabled(false).build();
         builder.addAugmentation(IfTunnel.class, tunnel);
         return builder.build();
     }
@@ -239,6 +254,14 @@ public class InterfaceManagerTestUtil {
         return ncBuilder.build();
     }
 
+    public static FlowCapableNodeConnector buildFlowCapableNodeConnector(boolean isPortDown, boolean isLive, String macAddress) {
+        PortConfig portConfig = new PortConfig(false, false, false, isPortDown);
+        State state = new StateBuilder().setBlocked(true).setLinkDown(false).setLive(isLive).build();
+        FlowCapableNodeConnectorBuilder fcNodeConnector = new FlowCapableNodeConnectorBuilder().
+                setHardwareAddress(MacAddress.getDefaultInstance(macAddress)).setConfiguration(portConfig).setState(state);
+        return fcNodeConnector.build();
+    }
+
     public static NodeConnectorId buildNodeConnectorId(BigInteger dpn, long portNo) {
         return new NodeConnectorId(buildNodeConnectorString(dpn, portNo));
     }
index 1092f7edf72d821e971fb10fdd3ab59db5596b74..1a64b41432350e5e0f68fb1d0cf7055d9ef7b0f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * 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,
@@ -36,6 +36,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 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.FlowCapableNodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
@@ -49,9 +51,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.met
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -123,16 +123,16 @@ public class StateInterfaceTest {
         IfindexInterface = InterfaceManagerTestUtil.buildIfIndexInterface(100, InterfaceManagerTestUtil.interfaceName);
         ifIndexId = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(100)).build();
         interfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(InterfaceManagerTestUtil.interfaceName));
-        childInterfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(InterfaceManagerTestUtil.interfaceName2));
+        childInterfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(InterfaceManagerTestUtil.childInterface));
         interfaceStateIdentifier = IfmUtil.buildStateInterfaceId(InterfaceManagerTestUtil.interfaceName);
-        childInterfaceStateIdentifier = IfmUtil.buildStateInterfaceId(InterfaceManagerTestUtil.interfaceName2);
+        childInterfaceStateIdentifier = IfmUtil.buildStateInterfaceId(InterfaceManagerTestUtil.childInterface);
         vlanInterfaceEnabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.interfaceName, "Test Vlan Interface1", true, L2vlan.class, BigInteger.valueOf(1));
         vlanInterfaceDisabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.interfaceName, "Test Vlan Interface1", false, L2vlan.class, BigInteger.valueOf(1));
         tunnelInterfaceEnabled = InterfaceManagerTestUtil.buildTunnelInterface(dpId, InterfaceManagerTestUtil.tunnelInterfaceName ,"Test Tunnel Interface", true, TunnelTypeGre.class, "192.168.56.101", "192.168.56.102");
-        childVlanInterfaceEnabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.interfaceName2, "Test Vlan Interface2", true, L2vlan.class, BigInteger.valueOf(1));
+        childVlanInterfaceEnabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.childInterface, "Test Vlan Interface2", true, L2vlan.class, BigInteger.valueOf(1));
         interfaceParentEntryKey = new InterfaceParentEntryKey(InterfaceManagerTestUtil.interfaceName);
         interfaceParentEntryIdentifier = InterfaceMetaUtils.getInterfaceParentEntryIdentifier(interfaceParentEntryKey);
-        higherLayerInterfaceParentEntryKey = new InterfaceParentEntryKey(InterfaceManagerTestUtil.interfaceName2);
+        higherLayerInterfaceParentEntryKey = new InterfaceParentEntryKey(InterfaceManagerTestUtil.childInterface);
         higherLevelInterfaceParentEntryIdentifier= InterfaceMetaUtils.getInterfaceParentEntryIdentifier(higherLayerInterfaceParentEntryKey);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
         List<String> lowerLayerIfList = new ArrayList<>();
@@ -147,7 +147,7 @@ public class StateInterfaceTest {
 
         InterfaceParentEntryBuilder ifaceParentEntryBuilder = new InterfaceParentEntryBuilder();
         List<InterfaceChildEntry> ifaceChildEntryList= new ArrayList<>();
-        ifaceChildEntryList.add(new InterfaceChildEntryBuilder().setChildInterface(InterfaceManagerTestUtil.interfaceName2).build());
+        ifaceChildEntryList.add(new InterfaceChildEntryBuilder().setChildInterface(InterfaceManagerTestUtil.childInterface).build());
         interfaceParentEntry = ifaceParentEntryBuilder.setInterfaceChildEntry(ifaceChildEntryList).build();
 
         InterfaceParentEntryBuilder higherLayerIfParentEntryBuilder = new InterfaceParentEntryBuilder();
@@ -185,7 +185,7 @@ public class StateInterfaceTest {
         doReturn(idOutputOptional).when(idManager).allocateId(getIdInput);
         AllocateIdInput getIdInput2 = new AllocateIdInputBuilder()
                 .setPoolName(IfmConstants.IFM_IDPOOL_NAME)
-                .setIdKey(InterfaceManagerTestUtil.interfaceName2).build();
+                .setIdKey(InterfaceManagerTestUtil.childInterface).build();
         doReturn(idOutputOptional2).when(idManager).allocateId(getIdInput2);
 
         addHelper.addState(dataBroker, idManager, mdsalManager, alivenessMonitorService,
@@ -277,6 +277,8 @@ public class StateInterfaceTest {
 
         doReturn(Futures.immediateCheckedFuture(expectedStateInterface)).when(mockReadTx).read(
                 LogicalDatastoreType.OPERATIONAL, interfaceStateIdentifier);
+        doReturn(Futures.immediateCheckedFuture(expectedStateInterface)).when(mockReadTx).read(
+                LogicalDatastoreType.OPERATIONAL, childInterfaceStateIdentifier);
         doReturn(Futures.immediateCheckedFuture(expectedParentEntry)).when(mockReadTx).read(
                 LogicalDatastoreType.CONFIGURATION, interfaceParentEntryIdentifier);
         doReturn(Futures.immediateCheckedFuture(higherLayerParentOptional)).when(mockReadTx).read(
@@ -286,26 +288,15 @@ public class StateInterfaceTest {
         doReturn(Futures.immediateCheckedFuture(expectedChildInterface)).when(mockReadTx).read(
                 LogicalDatastoreType.CONFIGURATION, childInterfaceInstanceIdentifier);
 
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
-        ifaceBuilder.setAdminStatus(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up)
-                .setPhysAddress(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress.getDefaultInstance("AA:AA:AA:AA:AA:AA"));
-        ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(InterfaceManagerTestUtil.interfaceName));
-        ifaceBuilder.setOperStatus(OperStatus.Down);
-
-        stateInterface = ifaceBuilder.build();
-
-        FlowCapableNodeConnectorBuilder fcNodeConnectorOldupdate = new FlowCapableNodeConnectorBuilder().setHardwareAddress(MacAddress.getDefaultInstance("AA:AA:AA:AA:AA:AB"));
-        FlowCapableNodeConnectorBuilder fcNodeConnectorNewupdate = new FlowCapableNodeConnectorBuilder().setHardwareAddress(MacAddress.getDefaultInstance("AA:AA:AA:AA:AA:AA"));
-
-        StateBuilder b2 = new StateBuilder().setBlocked(true).setLinkDown(false);
-        StateBuilder b3 = new StateBuilder().setBlocked(false).setLinkDown(true);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface parentInterface = InterfaceManagerTestUtil.buildStateInterface(InterfaceManagerTestUtil.interfaceName, null, OperStatus.Down);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface childInterface = InterfaceManagerTestUtil.buildStateInterface(InterfaceManagerTestUtil.childInterface, null, OperStatus.Down);
 
-        fcNodeConnectorOldupdate.setState(b2.build());
-        fcNodeConnectorNewupdate.setState(b3.build());
+        FlowCapableNodeConnector fcNodeConnectorOld = InterfaceManagerTestUtil.buildFlowCapableNodeConnector(false, true, "AA:AA:AA:AA:AA:AA");
+        FlowCapableNodeConnector fcNodeConnectorNew = InterfaceManagerTestUtil.buildFlowCapableNodeConnector(true, false, "AA:AA:AA:AA:AA:AA");
 
-        updateHelper.updateState(fcNodeConnectorId, alivenessMonitorService, dataBroker, InterfaceManagerTestUtil.interfaceName, fcNodeConnectorNewupdate.build(), fcNodeConnectorOldupdate.build());
+        updateHelper.updateState(fcNodeConnectorId, alivenessMonitorService, dataBroker, InterfaceManagerTestUtil.interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
 
-        verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,interfaceStateIdentifier,stateInterface);
-        verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,childInterfaceStateIdentifier,stateInterface);
+        verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,interfaceStateIdentifier,parentInterface);
+        verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,childInterfaceStateIdentifier,childInterface);
     }
-}
\ No newline at end of file
+}
index 6938837b246beb99e51a4fab5884ae53aadf8f12..a2b6a9ec35f1bea0ee87b73a1788472323395cfc 100644 (file)
@@ -24,6 +24,7 @@ import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInt
 import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInterfaceTopologyStateUpdateHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
 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.port._interface.attributes.InterfaceBfdStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatusBuilder;
@@ -60,6 +61,7 @@ public class TopologyStateInterfaceTest {
     BridgeEntry bridgeEntry = null;
     ParentRefs parentRefs = null;
     InstanceIdentifier<Interface> interfaceInstanceIdentifier = null;
+    InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceStateIdentifier = null;
     Interface tunnelInterfaceEnabled = null;
     BridgeInterfaceEntry bridgeInterfaceEntry;
     BridgeInterfaceEntryKey bridgeInterfaceEntryKey;
@@ -95,6 +97,7 @@ public class TopologyStateInterfaceTest {
         bridgeOld = InterfaceManagerTestUtil.getOvsdbBridgeRef("s1");
         bridgeEntryIid = InterfaceMetaUtils.getBridgeEntryIdentifier(new BridgeEntryKey(dpId));
         interfaceInstanceIdentifier = IfmUtil.buildId(InterfaceManagerTestUtil.tunnelInterfaceName);
+        interfaceStateIdentifier = IfmUtil.buildStateInterfaceId(newTerminationPoint.getName());
         bridgeInterfaceEntryKey = new BridgeInterfaceEntryKey(InterfaceManagerTestUtil.tunnelInterfaceName);
         bridgeInterfaceEntry =
                 new BridgeInterfaceEntryBuilder().setKey(bridgeInterfaceEntryKey)
@@ -184,8 +187,14 @@ public class TopologyStateInterfaceTest {
         interfaceBfdStatus.add(new InterfaceBfdStatusBuilder().setBfdStatusKey(SouthboundUtils.BFD_OP_STATE).setBfdStatusValue(SouthboundUtils.BFD_STATE_UP).build());
         List bfdStatusSpy = spy(interfaceBfdStatus);
         when(newTerminationPoint.getInterfaceBfdStatus()).thenReturn(bfdStatusSpy);
-        updateHelper.updateTunnelState(dataBroker, newTerminationPoint, null);
 
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState = new InterfaceBuilder().setKey(new InterfaceKey(InterfaceManagerTestUtil.interfaceName)).build();
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> expectedInterface = Optional.of(ifState);
+
+        doReturn(Futures.immediateCheckedFuture(expectedInterface)).when(mockReadTx).read(
+                LogicalDatastoreType.OPERATIONAL, interfaceStateIdentifier);
+        updateHelper.updateTunnelState(dataBroker, newTerminationPoint, null);
+        
         //verify
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
                 IfmUtil.buildStateInterfaceId(null);
index f2662e4e62b601ea3a2a61af4bd19d6e008cb7a2..38d9b09ad69dfa8f7a126909ac4c381ebb6f5867 100644 (file)
@@ -100,7 +100,7 @@ public class IfmCLIUtil {
         System.out.println(fmt.format(VXLAN_OUTPUT_FORMAT + "\n",
                 (interfaceInfo == null) ? InterfaceOpState.DOWN : interfaceInfo.getOpState(),
                 String.format("%s/%s", parentRefs.getDatapathNodeIdentifier(),
-                parentRefs.getParentInterface()),
+                        iface.getName()),
                 (interfaceInfo == null) ? UNSET : interfaceInfo.getInterfaceTag(), ""));
         fmt.close();
     }
index c45b982d920eb76ef8df39e9358f606ae7996edd..3ec1311315949fef359266b16c048ed6f554c276 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 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.params.xml.ns.yang.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema; 
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.op.rev150701.TunnelsState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
 
 public interface IITMProvider {
        // APIs used by i
@@ -27,6 +27,7 @@ public interface IITMProvider {
     public DataBroker getDataBroker();
 
     public void showTeps();
+    public void showState(TunnelList tunnels);
 
     public void deleteVtep(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
                     String gatewayIp, String transportZone);
index b6f6673b838978042183dd57617e9f781354bced..eaba9f3120669d8f46099f70da90f94dadadfe33 100644 (file)
@@ -20,8 +20,11 @@ public class ITMConstants{
   //Tunnel Monitoring
   public static final boolean DEFAULT_MONITOR_ENABLED = true;
   public static final int DEFAULT_MONITOR_INTERVAL = 10;
+  public static final int BFD_DEFAULT_MONITOR_INTERVAL = 100;
   public static final String DUMMY_IP_ADDRESS = "0.0.0.0";
   public static final String TUNNEL_TYPE_VXLAN = "VXLAN";
   public static final String TUNNEL_TYPE_GRE = "GRE";
+  public static final String TUNNEL_TYPE_MPLS_OVER_GRE = "MPLS_OVER_GRE";
+  public static final String TUNNEL_TYPE_INVALID = "Invalid";
 }
 
index 866c6e635b413a04c207d54332c337c50c9c6eca..0ca995bf45b33e4a0c0448de55781a7342cadd30 100644 (file)
@@ -39,6 +39,11 @@ module itm-rpc {
             leaf destination-dpid {
                  type uint64;
             }
+            leaf tunnel-type {
+                type identityref {
+                    base odlif:tunnel-type-base;
+                }
+            }
         }
         output {
             leaf interface-name {
@@ -56,6 +61,11 @@ module itm-rpc {
                 leaf destination-ip {
                 type inet:ip-address;
                 }
+                leaf tunnel-type {
+                    type identityref {
+                        base odlif:tunnel-type-base;
+                    }
+                }
             }
             output {
                 leaf interface-name {
@@ -73,6 +83,11 @@ module itm-rpc {
             leaf destination-node {
             type string;
             }
+            leaf tunnel-type {
+                type identityref {
+                    base odlif:tunnel-type-base;
+                }
+            }
         }
         output {
             leaf interface-name {
@@ -182,6 +197,20 @@ module itm-rpc {
         }
     }
 
+    rpc add-l2-gw-mlag-device {
+            description "used for building tunnels between teps on all Dpns and hwVtep";
+            input {
+                leaf topology-id {
+                    type string;
+                }
+                leaf-list node-id {
+                    type string;
+                }
+                leaf ip-address {
+                    type inet:ip-address;
+                }
+            }
+        }
     rpc delete-l2-gw-device {
         description "used for deleting tunnels between teps on all Dpns and hwVtep";
         input {
@@ -197,4 +226,18 @@ module itm-rpc {
         }
     }
 
+      rpc delete-l2-gw-mlag-device {
+            description "used for deleting tunnels between teps on all Dpns and hwVtep";
+            input {
+                leaf topology-id {
+                    type string;
+                }
+                leaf-list node-id {
+                    type string;
+                }
+                leaf ip-address {
+                    type inet:ip-address;
+                }
+            }
+        }
 }
\ No newline at end of file
index aa30269193a46690f4bb224ba8df161544c9a6f5..c76ce52e3a3629f5e062d8960c276064b2cd8a20 100644 (file)
@@ -27,6 +27,27 @@ module itm-state {
 
         /* Operational state */
 
+    identity tep-type-base {
+        description "Base TEP device type";
+    }
+    identity tep-type-internal {
+        base tep-type-base;
+        description "TEP type internal e.g. Compute OVS";
+    }
+    identity tep-type-external {
+        base tep-type-base;
+        description "TEP type external e.g. DC Gateway";
+    }
+    identity tep-type-hwvtep {
+        base tep-type-base;
+        description "TEP type Hwvtep e.g. TOR devices";
+    }
+    typedef tep-type {
+        type identityref {
+            base tep-type-base;
+        }
+        description "This type is used to refer to an TEP Device Type.";
+    }
       container dpn-endpoints {
 
         list DPN-TEPs-info {
@@ -43,8 +64,8 @@ module itm-state {
 
           /* Minimum 1 port. We may for now support only two ports */
           list tunnel-end-points {
-
-               key "portname VLAN-ID ip-address"; /* Multiple tunnels on the same physical port but on different VLAN can be supported */
+                ordered-by user;
+               key "portname VLAN-ID ip-address tunnel-type"; /* Multiple tunnels on the same physical port but on different VLAN can be supported */
 
                  leaf portname {
                      type string;
@@ -81,7 +102,7 @@ module itm-state {
       container tunnel-list {
              list internal-tunnel {
 
-               key  "source-DPN destination-DPN";
+               key  "source-DPN destination-DPN transport-type";
 
                leaf source-DPN {
                    type uint64;
@@ -90,6 +111,11 @@ module itm-state {
                leaf destination-DPN {
                    type uint64;
                }
+               leaf transport-type {
+                    type identityref {
+                        base odlif:tunnel-type-base;
+                    }
+               }
 
                /* logical-group interface id */
 
@@ -102,7 +128,7 @@ module itm-state {
       container external-tunnel-list {
              list external-tunnel {
 
-               key  "source-device destination-device";
+               key  "source-device destination-device transport-type";
 
                leaf source-device {
                    type string; //dpnid or node-id
@@ -112,6 +138,11 @@ module itm-state {
                    type string; //dpn-id or node-id or ip
                }
 
+               leaf transport-type {
+                    type identityref {
+                        base odlif:tunnel-type-base;
+                    }
+               }
                /* logical-group interface id */
 
                leaf tunnel-interface-name {
@@ -121,7 +152,43 @@ module itm-state {
              }
           }
 
-
+        grouping tep-info-attributes {
+            leaf tep-device-type {
+                type identityref {
+                    base tep-type-base;
+                }
+            }
+            leaf tep-device-id {
+                type string; //dpnid or node-id
+            }
+            leaf tep-ip {
+                type inet:ip-address; //dpnid or node-id
+            }
+        }
+
+      container tunnels_state {
+        list state-tunnel-list {
+            key  "tunnel-interface-name";
+            leaf tunnel-interface-name {
+                type string;
+            }
+            leaf tunnel-state {
+                type boolean;
+                config false;
+            }
+            container src-info {
+                uses tep-info-attributes;
+            }
+            container dst-info {
+                uses tep-info-attributes;
+            }
+            leaf transport-type {
+                type identityref {
+                    base odlif:tunnel-type-base;
+                }
+            }
+        }
+      }
           notification itm-tunnel-build-complete{
           }
 
index 3d3ccbe533c62a2915a48484a787cbd036601c7d..ddef8f071067c3be53c5fa46b9cdc64032ca8a5b 100644 (file)
@@ -29,6 +29,7 @@ module itm {
 
     container transport-zones {
       list transport-zone {
+      ordered-by user;
         key zone-name;
         leaf zone-name {
             type string;
index 7f417d3b4230a0466bcf11a2c23a68be88c779e7..f7741591e394297e9079a6efb3898da8f2895df4 100644 (file)
@@ -22,16 +22,24 @@ import org.opendaylight.vpnservice.interfacemgr.exceptions.InterfaceNotFoundExce
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 //import org.opendaylight.vpnservice.interfacemgr.util.OperationalIfmUtil;
 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan;
 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
 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.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabled;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabledBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorInterval;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorIntervalBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZonesBuilder;
@@ -44,6 +52,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.tr
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.Vteps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.VtepsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.VtepsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -436,9 +445,9 @@ public class TepCommandHelper {
             result.add(String.format("Tunnel Monitoring (for VXLAN tunnels): %s", (monitorEnabled ? "On" : "Off")));
             result.add(String.format("Tunnel Monitoring Interval (for VXLAN tunnels): %d", monitorInterval));
             result.add(System.lineSeparator());
-            result.add(String.format("%-16s  %-16s  %-16s  %-12s  %-12s %-12s %-12s %-12s", "TransportZone", "TunnelType", "SubnetMask",
+            result.add(String.format("%-16s  %-16s  %-16s  %-12s  %-12s %-12s %-16s %-12s", "TransportZone", "TunnelType", "SubnetMask",
                             "GatewayIP", "VlanID", "DpnID", "IPAddress", "PortName"));
-            result.add("--------------------------------------------------------------------------------------------------------------");
+            result.add("------------------------------------------------------------------------------------------------------------------------------");
             for (TransportZone tZ : tZones.getTransportZone()) {
                 if (tZ.getSubnets() == null || tZ.getSubnets().isEmpty()) {
                     LOG.error("Transport Zone " + tZ.getZoneName() + "has no subnets");
@@ -456,7 +465,7 @@ public class TepCommandHelper {
                           strTunnelType = ITMConstants.TUNNEL_TYPE_GRE ;
                         else
                           strTunnelType = ITMConstants.TUNNEL_TYPE_VXLAN ;
-                        result.add(String.format("%-16s  %-16s  %-16s  %-12s  %-12s %-12s %-12s %-12s", tZ.getZoneName(), strTunnelType, sub
+                        result.add(String.format("%-16s  %-16s  %-16s  %-12s  %-12s %-12s %-16s %-12s", tZ.getZoneName(), strTunnelType, sub
                                         .getPrefix().getIpv4Prefix().getValue(), sub.getGatewayIp().getIpv4Address()
                                         .getValue(), sub.getVlanId().toString(), vtep.getDpnId().toString(), vtep
                                         .getIpAddress().getIpv4Address().getValue(), vtep.getPortname().toString()));
@@ -628,46 +637,60 @@ public class TepCommandHelper {
             e.printStackTrace();
         }
     }
-/*
-    public void showState(TunnelsState tunnelsState, boolean tunnelMonitorEnabled) {
-        List<StateTunnelList> tunnelLists = tunnelsState.getStateTunnelList();
+
+    public void showState(TunnelList tunnels, boolean tunnelMonitorEnabled) {
+        IfTunnel tunnelInterface = null;
+        IfL2vlan l2Vlan = null;
+        List<InternalTunnel> tunnelLists = tunnels.getInternalTunnel();
         if (tunnelLists == null || tunnelLists.isEmpty()) {
-            System.out.println("No Logical Tunnels Exist");
+            System.out.println("No Internal Tunnels Exist");
             return;
         }
         if (!tunnelMonitorEnabled) {
             System.out.println("Tunnel Monitoring is Off");
         }
-        System.out.println(String.format("%-16s  %-16s  %-16s  %-10s  %-16s %-8s  %-10s  %-10s", "Source-DPN",
-                        "Destination-DPN", "SourcePortName", "Source-IP", "Destination-IP", "VLan-ID", "Trunk-State",
-                        "Logical-Tunnel-State"));
-        System.out.println("----------------------------------------------------------------------------------------------------------------------");
-
-        for (StateTunnelList tunnel : tunnelLists) {
-            String logicaltunnelState = (tunnel.isLogicalTunnelState()) ? "UP" : "DOWN";
-            try {
-                List<String> trunks =
-                                interfaceManager.getTunnelInterfacesOfLogicalGroup(tunnel.getLogicalTunnelGroupName());
-                if (trunks != null && !trunks.isEmpty()) {
-                    for (String trunk : trunks) {
-                        List<String> params = Arrays.asList(trunk.split(":"));
-                        LOG.trace("trunk {} for LogicalIf {} ", trunk, tunnel.getLogicalTunnelGroupName());
-                        String trunkState = (OperationalIfmUtil.isInterfaceUp(dataBroker, trunk)) ? "UP" : "DOWN";
-                        System.out.println(String.format("%-16s  %-16s  %-16s  %-10s  %-16s %-8s  %-10s  %-10s", tunnel
-                                        .getSourceDPN().toString(), tunnel.getDestinationDPN().toString(), params
-                                        .get(1), params.get(3), params.get(4), params.get(2), trunkState,
-                                        logicaltunnelState));
-                    }
-                } else {
-                    LOG.error("No trunks for " + tunnel.getLogicalTunnelGroupName());
+        String displayFormat = "%-16s  %-16s  %-16s  %-16s  %-16s  %-8s  %-10s  %-10s";
+        System.out.println(String.format(displayFormat, "Tunnel Name", "Source-DPN",
+                        "Destination-DPN", "Source-IP", "Destination-IP", "Vlan Id", "Trunk-State", "Transport Type"));
+        System.out.println("-------------------------------------------------------------------------------------------------------------------------------------");
+
+        for (InternalTunnel tunnel : tunnelLists) {
+            String tunnelInterfaceName = tunnel.getTunnelInterfaceName();
+            LOG.trace("tunnelInterfaceName::: {}", tunnelInterfaceName);
+            
+            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
+                    ItmUtils.buildStateInterfaceId(tunnelInterfaceName);
+            Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional =
+                  ItmUtils.read(LogicalDatastoreType.OPERATIONAL, ifStateId, dataBroker);
+            String tunnelState = "DOWN" ;
+            if (ifStateOptional.isPresent()) {
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface iface = ifStateOptional.get() ;
+                if(iface.getAdminStatus() == AdminStatus.Up && iface.getOperStatus() == OperStatus.Up)
+                tunnelState = "UP" ;
+            }
+                InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(tunnelInterfaceName);
+                Optional<Interface> ifaceObj = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, dataBroker) ;
+                if (ifaceObj.isPresent()) {
+                    l2Vlan = (IfL2vlan) ifaceObj.get().getAugmentation(IfL2vlan.class);
+                    tunnelInterface = (IfTunnel) ifaceObj.get().getAugmentation(IfTunnel.class);
                 }
 
-            } catch (InterfaceNotFoundException e) {
-                LOG.error("if not found " + tunnel.getLogicalTunnelGroupName());
-            }
-        }
+                Class<? extends TunnelTypeBase> tunType = tunnelInterface.getTunnelInterfaceType();
+                String tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN;
+                if( tunType.equals(TunnelTypeVxlan.class))
+                    tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN ;
+                else if( tunType.equals(TunnelTypeGre.class) )
+                    tunnelType = ITMConstants.TUNNEL_TYPE_GRE ;
+                int vlanId = 0;
+                if( l2Vlan != null ) {
+                   vlanId = l2Vlan.getVlanId().getValue() ;
+                }
+                System.out.println(String.format(displayFormat, tunnel.getTunnelInterfaceName(), tunnel
+                                .getSourceDPN().toString(), tunnel.getDestinationDPN().toString(), tunnelInterface.getTunnelSource().getIpv4Address().getValue(), tunnelInterface.getTunnelDestination().getIpv4Address().getValue(),vlanId, tunnelState ,
+                                tunnelType));
+         }
     }
-*/
+
     // deletes from ADD-cache if it exists.
     public boolean isInCache(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
                     String gatewayIp, String transportZone) {
index a2a254debd99e58810f2ff80628e52450ed4a648..7e64282f9499ae9ee3d0f2a17ac779fe7eba2096 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.itm.api.IITMProvider;
 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.op.rev150701.TunnelsState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import java.util.ArrayList;
@@ -33,18 +33,16 @@ import java.util.List;
 
     @Override
     protected Object doExecute() throws Exception {
-        /*
+        
         DataBroker broker = itmProvider.getDataBroker();
         List<String> result = new ArrayList<String>();
-        InstanceIdentifier<TunnelsState> path = InstanceIdentifier.builder(TunnelsState.class).build();
-        Optional<TunnelsState> tunnels = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, path, broker);
+        InstanceIdentifier<TunnelList> path = InstanceIdentifier.builder(TunnelList.class).build();
+        Optional<TunnelList> tunnels = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
         if (tunnels.isPresent()) {
             itmProvider.showState(tunnels.get());
         }
         else
-            System.out.println("No Logical Tunnels Exist");
-            */
-        System.out.println( "Logical Tunnels state is not currently supported");
+            System.out.println("No Internal Tunnels Exist");
         return null;
     }
 }
index 6a0ed5be2bd9c4a032c3a2ceef8ea17a0cc8a75e..caae0cbb7e1ddafaed35ea232aa6ecb637e7c620 100644 (file)
@@ -15,6 +15,7 @@ import com.google.common.base.Optional;
 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.vpnservice.itm.globals.ITMConstants;
 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
 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.IpPrefix;
@@ -75,15 +76,16 @@ public class ItmExternalTunnelAddWorker {
                 // CHECK -- Assumption -- Only one End Point / Dpn for GRE/Vxlan Tunnels
                 TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0);
                 String interfaceName = firstEndPt.getInterfaceName();
-                String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName, firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue());
+                String tunTypeStr = tunType.getName();
+                String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName, firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue(), tunTypeStr);
                 char[] subnetMaskArray = firstEndPt.getSubnetMask().getValue();
                 String subnetMaskStr = String.valueOf(subnetMaskArray);
                 SubnetUtils utils = new SubnetUtils(subnetMaskStr);
                 String dcGwyIpStr = String.valueOf(extIp.getValue());
-                IpAddress gwyIpAddress = (utils.getInfo().isInRange(dcGwyIpStr)) ? null : firstEndPt.getGwIpAddress();
-                String ifDescription = tunType.getName();
+                IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+                IpAddress gwyIpAddress = (utils.getInfo().isInRange(dcGwyIpStr)) ? gatewayIpObj : firstEndPt.getGwIpAddress();
                 logger.debug(" Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, source IP - {}, DC Gateway IP - {} gateway IP - {}", trunkInterfaceName, interfaceName, firstEndPt.getIpAddress(), extIp, gwyIpAddress);
-                Interface iface = ItmUtils.buildTunnelInterface(teps.getDPNID(), trunkInterfaceName, String.format("%s %s", ifDescription, "Trunk Interface"), true, tunType, firstEndPt.getIpAddress(), extIp, gwyIpAddress, firstEndPt.getVLANID(), false,false,null);
+                Interface iface = ItmUtils.buildTunnelInterface(teps.getDPNID(), trunkInterfaceName, String.format("%s %s", ItmUtils.convertTunnelTypetoString(tunType), "Trunk Interface"), true, tunType, firstEndPt.getIpAddress(), extIp, gwyIpAddress, firstEndPt.getVLANID(), false,false,null);
                 logger.debug(" Trunk Interface builder - {} ", iface);
                 InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
                 logger.debug(" Trunk Interface Identifier - {} ", trunkIdentifier);
@@ -92,8 +94,9 @@ public class ItmExternalTunnelAddWorker {
                 // update external_tunnel_list ds
                 InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                         ExternalTunnelList.class)
-                        .child(ExternalTunnel.class, new ExternalTunnelKey(extIp.toString(), teps.getDPNID().toString()));
-                ExternalTunnel tnl = ItmUtils.buildExternalTunnel(teps.getDPNID().toString(), extIp.toString(), trunkInterfaceName);
+                        .child(ExternalTunnel.class, new ExternalTunnelKey(extIp.toString(), teps.getDPNID().toString(), tunType));
+                ExternalTunnel tnl = ItmUtils.buildExternalTunnel(  teps.getDPNID().toString(), extIp.toString(),
+                                                                    tunType, trunkInterfaceName);
                 t.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
             }
             futures.add(t.submit());
@@ -144,14 +147,16 @@ public class ItmExternalTunnelAddWorker {
                                         String cssID = dpn.getDPNID().toString();
                                         String nodeId = hwVtepDS.getNodeId();
                                         //CSS-TOR
+                                        Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+                                        Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
                                         logger.trace("wire up {} and {}",tep, hwVtepDS);
                                         if (!wireUp(dpn.getDPNID(), tep.getPortname(), sub.getVlanId(), tep.getIpAddress(), nodeId, hwVtepDS.getIpAddress(), tep.getSubnetMask(),
-                                                sub.getGatewayIp(), sub.getPrefix(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+                                                sub.getGatewayIp(), sub.getPrefix(), tZone.getTunnelType(),monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
                                             logger.error("Unable to build tunnel {} -- {}", tep.getIpAddress(), hwVtepDS.getIpAddress());
                                         //TOR-CSS
                                         logger.trace("wire up {} and {}", hwVtepDS,tep);
                                         if (!wireUp(hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), cssID, tep.getIpAddress(), sub.getPrefix(),
-                                                sub.getGatewayIp(), tep.getSubnetMask(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+                                                sub.getGatewayIp(), tep.getSubnetMask(), tZone.getTunnelType(), monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
                                             logger.error("Unable to build tunnel {} -- {}", hwVtepDS.getIpAddress(), tep.getIpAddress());
 
                                     }
@@ -167,6 +172,7 @@ public class ItmExternalTunnelAddWorker {
         for (HwVtep hwTep : cfgdHwVteps) {
             InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class).child(TransportZone.class, new TransportZoneKey((hwTep.getTransportZone()))).build();
             Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
+            Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
             if (tZoneOptional.isPresent()) {
                 TransportZone tZone = tZoneOptional.get();
                 //do we need to check tunnel type?
@@ -177,14 +183,17 @@ public class ItmExternalTunnelAddWorker {
                                 if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp()))
                                     continue;//dont mesh with self
                                 //TOR1-TOR2
+                                Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+                                Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
                                 logger.trace("wire up {} and {}",hwTep, hwVtepDS);
                                 if (!wireUp(hwTep.getTopo_id(), hwTep.getNode_id(), hwTep.getHwIp(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(),
-                                        hwTep.getIpPrefix(), hwTep.getGatewayIP(), sub.getPrefix(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+                                        hwTep.getIpPrefix(), hwTep.getGatewayIP(), sub.getPrefix(), tunType,monitorEnabled,
+                                                ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
                                     logger.error("Unable to build tunnel {} -- {}", hwTep.getHwIp(), hwVtepDS.getIpAddress());
                                 //TOR2-TOR1
                                 logger.trace("wire up {} and {}", hwVtepDS,hwTep);
                                 if (!wireUp(hwTep.getTopo_id(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), hwTep.getNode_id(), hwTep.getHwIp(),
-                                        sub.getPrefix(), sub.getGatewayIp(), hwTep.getIpPrefix(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+                                        sub.getPrefix(), sub.getGatewayIp(), hwTep.getIpPrefix(), tunType, monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
                                     logger.error("Unable to build tunnel {} -- {}", hwVtepDS.getIpAddress(), hwTep.getHwIp());
                             }
                         }
@@ -192,14 +201,17 @@ public class ItmExternalTunnelAddWorker {
                             for (Vteps vtep : sub.getVteps()) {
                                 //TOR-CSS
                                 String cssID = vtep.getDpnId().toString();
+                                Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+                                Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
                                 logger.trace("wire up {} and {}",hwTep, vtep);
                                 if(!wireUp(hwTep.getTopo_id(), hwTep.getNode_id(), hwTep.getHwIp(), cssID, vtep.getIpAddress(), hwTep.getIpPrefix(),
-                                        hwTep.getGatewayIP(), sub.getPrefix(), tZone.getTunnelType(),idManagerService, dataBroker, futures, t ))
+                                        hwTep.getGatewayIP(), sub.getPrefix(), tunType,monitorEnabled, ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t ))
                                     logger.error("Unable to build tunnel {} -- {}", hwTep.getHwIp(), vtep.getIpAddress());
                                     //CSS-TOR
                                 logger.trace("wire up {} and {}", vtep,hwTep);
                                 if(!wireUp(vtep.getDpnId(), vtep.getPortname(), sub.getVlanId(), vtep.getIpAddress(),
-                                                hwTep.getNode_id(),hwTep.getHwIp(),sub.getPrefix(), sub.getGatewayIp(),hwTep.getIpPrefix(),tZone.getTunnelType(),idManagerService, dataBroker, futures, t ));
+                                                hwTep.getNode_id(),hwTep.getHwIp(),sub.getPrefix(), sub.getGatewayIp(),hwTep.getIpPrefix(),
+                                                tunType,monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL,idManagerService, dataBroker, futures, t ));
 
                             }
 
@@ -212,41 +224,57 @@ public class ItmExternalTunnelAddWorker {
 
     //for tunnels from TOR device
     private static boolean wireUp(String topo_id, String srcNodeid, IpAddress srcIp, String dstNodeId, IpAddress dstIp, IpPrefix srcSubnet,
-                                  IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType, IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
-        IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? null : gWIp;
+                                  IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType,Boolean monitorEnabled,
+                    Integer monitorInterval,IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
+        IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+        IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? gatewayIpObj : gWIp;
         String parentIf =  ItmUtils.getHwParentIf(topo_id, srcNodeid);
-        String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf, srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue());
+        String tunTypeStr = tunType.getName();
+        String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf,
+                        srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue(), tunTypeStr);
         logger.debug(" Creating ExternalTrunk Interface with parameters Name - {}, parent I/f name - {}, source IP - {}, destination IP - {} gateway IP - {}", tunnelIfName, parentIf, srcIp, dstIp, gwyIpAddress);
         Interface hwTunnelIf = ItmUtils.buildHwTunnelInterface(tunnelIfName, String.format("%s %s", tunType.getName(), "Trunk Interface"),
-                true, topo_id, srcNodeid, tunType, srcIp, dstIp, gwyIpAddress, true);
+                        true, topo_id, srcNodeid, tunType, srcIp, dstIp, gwyIpAddress, monitorEnabled, monitorInterval);
         InstanceIdentifier<Interface> ifIID = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(tunnelIfName)).build();
         logger.trace(" Writing Trunk Interface to Config DS {}, {} ", ifIID, hwTunnelIf);
+        ItmUtils.itmCache.addInterface(hwTunnelIf);
         t.merge(LogicalDatastoreType.CONFIGURATION, ifIID, hwTunnelIf, true);
         // also update itm-state ds?
         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                 ExternalTunnelList.class)
-                .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId), getExternalTunnelKey(srcNodeid)));
-        ExternalTunnel tnl = ItmUtils.buildExternalTunnel(getExternalTunnelKey(srcNodeid), getExternalTunnelKey(dstNodeId), tunnelIfName);
+                .child(ExternalTunnel.class, new ExternalTunnelKey( getExternalTunnelKey(dstNodeId), getExternalTunnelKey(srcNodeid), tunType));
+        ExternalTunnel tnl = ItmUtils.buildExternalTunnel(  getExternalTunnelKey(srcNodeid),
+                                                            getExternalTunnelKey(dstNodeId),
+                                                            tunType, tunnelIfName);
         t.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
+        ItmUtils.itmCache.addExternalTunnel(tnl);
         return true;
     }
 
     //for tunnels from CSS
     private static boolean wireUp(BigInteger dpnId,String portname, Integer vlanId, IpAddress srcIp, String dstNodeId, IpAddress dstIp, IpPrefix srcSubnet,
-                                  IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType, IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
-        IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? null : gWIp;
+                                  IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType,Boolean monitorEnabled, Integer monitorInterval,
+                    IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
+        IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+        IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? gatewayIpObj : gWIp;
         String parentIf = ItmUtils.getInterfaceName(dpnId, portname, vlanId);
-        String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf, srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue());
+        String tunTypeStr = tunType.getName();
+        String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf,
+                        srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue(), tunTypeStr);
         logger.debug(" Creating ExternalTrunk Interface with parameters Name - {}, parent I/f name - {}, source IP - {}, destination IP - {} gateway IP - {}", tunnelIfName, parentIf, srcIp, dstIp, gwyIpAddress);
-        Interface extTunnelIf = ItmUtils.buildTunnelInterface(dpnId, tunnelIfName, String.format("%s %s", tunType.getName(), "Trunk Interface"), true, tunType, srcIp, dstIp, gwyIpAddress, vlanId, false, true, 5L);
+        Interface extTunnelIf = ItmUtils.buildTunnelInterface(dpnId, tunnelIfName, String.format("%s %s", tunType.getName(), "Trunk Interface"), true, tunType, srcIp, dstIp, gwyIpAddress, vlanId, false,monitorEnabled, monitorInterval);
         InstanceIdentifier<Interface> ifIID = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(tunnelIfName)).build();
         logger.trace(" Writing Trunk Interface to Config DS {}, {} ", ifIID, extTunnelIf);
         t.merge(LogicalDatastoreType.CONFIGURATION, ifIID, extTunnelIf, true);
+        ItmUtils.itmCache.addInterface(extTunnelIf);
         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                 ExternalTunnelList.class)
-                .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId), dpnId.toString()));
-        ExternalTunnel tnl = ItmUtils.buildExternalTunnel(dpnId.toString(), getExternalTunnelKey(dstNodeId), tunnelIfName);
+                .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId), dpnId.toString(), tunType));
+        ExternalTunnel tnl = ItmUtils.buildExternalTunnel(  dpnId.toString(),
+                                                            getExternalTunnelKey(dstNodeId),
+                                                            tunType, tunnelIfName);
         t.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
+        ItmUtils.itmCache.addExternalTunnel(tnl);
         return true;
     }
     
index c1d8f863e52ea89d9861f7d5696f486fa30d59f9..16e629a1e1e4f752bc4019be2702ce4dbb9a8522 100644 (file)
@@ -16,10 +16,13 @@ import com.google.common.base.Optional;
 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.vpnservice.itm.globals.ITMConstants;
 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
 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.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
@@ -52,20 +55,26 @@ public class ItmExternalTunnelDeleteWorker {
             }
             for( DPNTEPsInfo teps : dpnTepsList) {
                 TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0) ;
-                if( firstEndPt.getTunnelType().equals(tunType)) {
                     String interfaceName = firstEndPt.getInterfaceName() ;
-                    String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName,firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue()) ;
+                    String trunkInterfaceName = ItmUtils.getTrunkInterfaceName( idManagerService, interfaceName,
+                                                                                firstEndPt.getIpAddress().getIpv4Address().getValue(),
+                                                                                extIp.getIpv4Address().getValue(),
+                                                                                tunType.getName());
                     InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
                     t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
+                    ItmUtils.itmCache.removeInterface(trunkInterfaceName);
 
                     InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                             ExternalTunnelList.class)
-                                .child(ExternalTunnel.class, getExternalTunnelKey(extIp.toString(), teps.getDPNID().toString()));
+                                .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(extIp.toString(),
+                                                                                    teps.getDPNID().toString(),
+                                                                                    tunType));
                     t.delete(LogicalDatastoreType.CONFIGURATION, path);
+                    logger.debug( "Deleting tunnel towards DC gateway, Tunnel interface name {} ",trunkInterfaceName );
+                    ItmUtils.itmCache.removeExternalTunnel(trunkInterfaceName);
                     // Release the Ids for the trunk interface Name
-                    ItmUtils.releaseIdForTrunkInterfaceName(idManagerService,interfaceName,firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue() );
+                    ItmUtils.releaseIdForTrunkInterfaceName(idManagerService,interfaceName,firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue(),tunType.getName());
                 }
-            }
             futures.add(t.submit()) ;
         return futures ;
     }
@@ -73,23 +82,21 @@ public class ItmExternalTunnelDeleteWorker {
     public static List<ListenableFuture<Void>> deleteHwVtepsTunnels(DataBroker dataBroker, IdManagerService idManagerService, List<DPNTEPsInfo> delDpnList ,List<HwVtep> cfgdHwVteps) {
         List<ListenableFuture<Void>> futures = new ArrayList<>();
         WriteTransaction t = dataBroker.newWriteOnlyTransaction();
-        if (null != delDpnList) {
-            tunnelsFromCSS(delDpnList, idManagerService , futures, t , dataBroker);
-        }
-        if (null != cfgdHwVteps) {
-            tunnelsFromhWVtep(cfgdHwVteps, idManagerService, futures, t, dataBroker);
-        }
 
         if (delDpnList != null || cfgdHwVteps != null)
+            tunnelsDeletion(delDpnList, cfgdHwVteps, idManagerService, futures, t, dataBroker);
             futures.add(t.submit());
         return futures;
     }
 
-    private static void tunnelsFromCSS(List<DPNTEPsInfo> cfgdDpnList, IdManagerService idManagerService, List<ListenableFuture<Void>> futures, WriteTransaction t, DataBroker dataBroker) {
+    private static void tunnelsDeletion(List<DPNTEPsInfo> cfgdDpnList, List<HwVtep> cfgdhwVteps, IdManagerService idManagerService, List<ListenableFuture<Void>> futures, WriteTransaction t, DataBroker dataBroker) {
+        if (cfgdDpnList != null && !cfgdDpnList.isEmpty()) {
         for (DPNTEPsInfo dpn : cfgdDpnList) {
             if (dpn.getTunnelEndPoints() != null && !dpn.getTunnelEndPoints().isEmpty())
                 for (TunnelEndPoints srcTep : dpn.getTunnelEndPoints()) {
-                    InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class).child(TransportZone.class, new TransportZoneKey((srcTep.getTransportZone()))).build();
+                        InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
+                                        .child(TransportZone.class, new TransportZoneKey((srcTep.getTransportZone())))
+                                        .build();
                     Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
                     if (tZoneOptional.isPresent()) {
                         TransportZone tZone = tZoneOptional.get();
@@ -100,13 +107,64 @@ public class ItmExternalTunnelDeleteWorker {
                                     for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
                                         String cssID = dpn.getDPNID().toString();
                                         //CSS-TOR-CSS
-                                        deleteTrunksCSSTOR(dataBroker, idManagerService, dpn.getDPNID(),
-                                                        srcTep.getInterfaceName(), srcTep.getIpAddress(),
-                                                        hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(),
-                                                        hwVtepDS.getIpAddress(), t, futures);
+                                            deleteTrunksCSSTOR(dataBroker, idManagerService, dpn.getDPNID(), srcTep.getInterfaceName(), srcTep.getIpAddress(),
+                                                            hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), tZone.getTunnelType(),
+                                                            t, futures);
+                                        }
+                                    }
+                                }
+                            }
+                            if (cfgdhwVteps != null && !cfgdhwVteps.isEmpty()) {
+                                for (HwVtep hwVtep : cfgdhwVteps) {
+                                    deleteTrunksCSSTOR(dataBroker, idManagerService, dpn.getDPNID(), srcTep.getInterfaceName(), srcTep.getIpAddress(),
+                                                    hwVtep.getTopo_id(), hwVtep.getNode_id(), hwVtep.getHwIp(),
+                                                    TunnelTypeVxlan.class, t, futures);
+                                }
+                            }
+                        }
+                    }
+            }
+        }
+            if (cfgdhwVteps != null && !cfgdhwVteps.isEmpty()) {
+                for (HwVtep hwTep : cfgdhwVteps) {
+                    logger.trace("processing hwTep from list {}", hwTep);
+                    for (HwVtep hwTepRemote : cfgdhwVteps) {
+                        if (!hwTep.getHwIp().equals(hwTepRemote.getHwIp())) {
+                            deleteTrunksTORTOR(dataBroker, idManagerService, hwTep.getTopo_id(), hwTep.getNode_id(),
+                                    hwTep.getHwIp(), hwTepRemote.getTopo_id(), hwTepRemote.getNode_id(),
+                                    hwTepRemote.getHwIp(), TunnelTypeVxlan.class, t, futures);
+                        }
+                    }
+                    InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
+                            .child(TransportZone.class, new TransportZoneKey((hwTep.getTransportZone()))).build();
+                    Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
+                    if (tZoneOptional.isPresent()) {
+                        TransportZone tZone = tZoneOptional.get();
+                        logger.trace("subnets under tz {} are {}", tZone.getZoneName(), tZone.getSubnets());
+                        if (tZone.getSubnets() != null && !tZone.getSubnets().isEmpty()) {
+                            for (Subnets sub : tZone.getSubnets()) {
+                                if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                                    for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
+                                        logger.trace("hwtepDS exists {}", hwVtepDS);
+                                        if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp()))
+                                            continue;//dont delete tunnels with self
+                                        logger.trace("deleting tor-tor {} and {}", hwTep, hwVtepDS);
+                                        deleteTrunksTORTOR(dataBroker, idManagerService, hwTep.getTopo_id(), hwTep.getNode_id(),
+                                                hwTep.getHwIp(), hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(),
+                                                hwVtepDS.getIpAddress(), tZone.getTunnelType(),
+                                                t, futures);
 
                                     }
                                 }
+                                if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
+                                    for (Vteps vtep : sub.getVteps()) {
+                                        logger.trace("deleting tor-css-tor {} and {}", hwTep, vtep);
+                                        String parentIf = ItmUtils.getInterfaceName(vtep.getDpnId(), vtep.getPortname(), sub.getVlanId());
+                                        deleteTrunksCSSTOR(dataBroker, idManagerService, vtep.getDpnId(), parentIf, vtep.getIpAddress(),
+                                                hwTep.getTopo_id(), hwTep.getNode_id(), hwTep.getHwIp(),
+                                                tZone.getTunnelType(), t, futures);
+                                    }
+                                }
                             }
                         }
                     }
@@ -118,83 +176,50 @@ public class ItmExternalTunnelDeleteWorker {
 
 
 
-    private static void tunnelsFromhWVtep(List<HwVtep> cfgdHwVteps, IdManagerService idManagerService, List<ListenableFuture<Void>> futures, WriteTransaction t, DataBroker dataBroker) {
-        for (HwVtep hwTep : cfgdHwVteps) {
-            logger.trace("processing hwTep from list {}",hwTep);
-            InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class).child(TransportZone.class, new TransportZoneKey((hwTep.getTransportZone()))).build();
-            Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
-            if (tZoneOptional.isPresent()) {
-                TransportZone tZone = tZoneOptional.get();
                 //do we need to check tunnel type?
-                logger.trace("subnets under tz {} are {}",tZone.getZoneName(),tZone.getSubnets());
-                if (tZone.getSubnets() != null && !tZone.getSubnets().isEmpty()) {
 
-                    for (Subnets sub : tZone.getSubnets()) {
-                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
-                            for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
-                                logger.trace("hwtepDS exists {}",hwVtepDS);
                                 //do i need to check node-id?
                                 //for mlag case and non-m-lag case, isnt it enough to just check ipaddress?
-                                if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp()))
-                                    continue;//dont delete tunnels with self
                                 //TOR-TOR
-                                logger.trace("deleting tor-tor {} and {}",hwTep,hwVtepDS);
-                                deleteTrunksTORTOR(dataBroker, idManagerService, hwTep.getTopo_id(), hwTep.getNode_id(),
-                                                hwTep.getHwIp(), hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(),
-                                                hwVtepDS.getIpAddress(), t, futures);
 
-                            }
-                        }
-                        if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
-                            for (Vteps vtep : sub.getVteps()) {
                                 //TOR-CSS
-                                logger.trace("deleting tor-css-tor {} and {}",hwTep,vtep);
-                                String parentIf = ItmUtils.getInterfaceName(vtep.getDpnId(),vtep.getPortname(),sub.getVlanId());
-                                deleteTrunksCSSTOR(dataBroker,idManagerService,vtep.getDpnId(),parentIf,vtep.getIpAddress(),
-                                                hwTep.getTopo_id(),hwTep.getNode_id(),hwTep.getHwIp(),t,futures );
-                            }
 
-                        }
-                    }
-                }
-            }
-        }
-    }
 
 
     private static void deleteTrunksCSSTOR(DataBroker dataBroker, IdManagerService idManagerService, BigInteger dpnid,
                     String interfaceName, IpAddress cssIpAddress, String topologyId, String nodeId, IpAddress hWIpAddress,
-                    WriteTransaction t, List<ListenableFuture<Void>> futures) {
+                                           Class<? extends TunnelTypeBase> tunType, WriteTransaction t,
+                                           List<ListenableFuture<Void>> futures) {
         //CSS-TOR
-        if (trunkExists(dpnid.toString(), nodeId,dataBroker)) {
+        if (trunkExists(dpnid.toString(), nodeId, tunType, dataBroker)) {
             logger.trace("deleting tunnel from {} to {} ", dpnid.toString(), nodeId);
             String parentIf = interfaceName;
             String fwdTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService,parentIf,cssIpAddress.getIpv4Address().getValue(),
-                            hWIpAddress.getIpv4Address().getValue());
+                            hWIpAddress.getIpv4Address().getValue(), tunType.getName());
             InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(fwdTrunkIf);
             t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
 
             InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                             ExternalTunnelList.class)
-                            .child(ExternalTunnel.class, getExternalTunnelKey(nodeId, dpnid.toString()));
+                            .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(nodeId, dpnid.toString(), tunType));
             t.delete(LogicalDatastoreType.CONFIGURATION, path);
         }
         else {
             logger.trace(" trunk from {} to {} already deleted",dpnid.toString(), nodeId);
         }
         //TOR-CSS
-        if (trunkExists( nodeId, dpnid.toString(),dataBroker)) {
+        if (trunkExists( nodeId, dpnid.toString(), tunType, dataBroker)) {
             logger.trace("deleting tunnel from {} to {} ",nodeId, dpnid.toString());
 
             String parentIf = ItmUtils.getHwParentIf(topologyId,nodeId);
             String revTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService,parentIf, hWIpAddress.getIpv4Address().getValue(),
-                            cssIpAddress.getIpv4Address().getValue());
+                            cssIpAddress.getIpv4Address().getValue(), tunType.getName());
             InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(revTrunkIf);
             t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
 
             InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                             ExternalTunnelList.class)
-                            .child(ExternalTunnel.class, getExternalTunnelKey( dpnid.toString(),nodeId));
+                            .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(dpnid.toString(),nodeId, tunType));
             t.delete(LogicalDatastoreType.CONFIGURATION, path);
         }
         else {
@@ -204,37 +229,39 @@ public class ItmExternalTunnelDeleteWorker {
 
     private static void deleteTrunksTORTOR(DataBroker dataBroker, IdManagerService idManagerService,
                     String topologyId1, String nodeId1, IpAddress hWIpAddress1, String topologyId2, String nodeId2, IpAddress hWIpAddress2,
-                    WriteTransaction t, List<ListenableFuture<Void>> futures) {
+                                           Class<? extends TunnelTypeBase> tunType, WriteTransaction t, List<ListenableFuture<Void>> futures) {
         //TOR1-TOR2
-        if (trunkExists(nodeId1, nodeId2,dataBroker)) {
+        if (trunkExists(nodeId1, nodeId2, tunType, dataBroker)) {
             logger.trace("deleting tunnel from {} to {} ", nodeId1, nodeId2);
             String parentIf = ItmUtils.getHwParentIf(topologyId1,nodeId1);
             String fwdTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf,
-                            hWIpAddress1.getIpv4Address().getValue(), hWIpAddress2.getIpv4Address().getValue());
+                                                                hWIpAddress1.getIpv4Address().getValue(),
+                                                                hWIpAddress2.getIpv4Address().getValue(),
+                                                                tunType.getName());
             InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(fwdTrunkIf);
             t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
 
             InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                             ExternalTunnelList.class)
-                            .child(ExternalTunnel.class, getExternalTunnelKey(nodeId2, nodeId1));
+                            .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(nodeId2, nodeId1, tunType));
             t.delete(LogicalDatastoreType.CONFIGURATION, path);
         }
         else {
             logger.trace(" trunk from {} to {} already deleted",nodeId1, nodeId2);
         }
         //TOR2-TOR1
-        if (trunkExists( nodeId2, nodeId1,dataBroker)) {
+        if (trunkExists( nodeId2, nodeId1, tunType, dataBroker)) {
             logger.trace("deleting tunnel from {} to {} ",nodeId2, nodeId1);
 
             String parentIf = ItmUtils.getHwParentIf(topologyId2,nodeId2);
             String revTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService,parentIf, hWIpAddress2.getIpv4Address().getValue(),
-                            hWIpAddress1.getIpv4Address().getValue());
+                                                                hWIpAddress1.getIpv4Address().getValue(), tunType.getName());
             InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(revTrunkIf);
             t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
 
             InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                             ExternalTunnelList.class)
-                            .child(ExternalTunnel.class, getExternalTunnelKey( nodeId1,nodeId2));
+                            .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(nodeId1,nodeId2, tunType));
             t.delete(LogicalDatastoreType.CONFIGURATION, path);
         }
         else {
@@ -242,25 +269,17 @@ public class ItmExternalTunnelDeleteWorker {
         }
     }
 
-    private static boolean trunkExists( String srcDpnOrNode,  String dstDpnOrNode, DataBroker dataBroker) {
+    private static boolean trunkExists( String srcDpnOrNode,  String dstDpnOrNode,
+                                        Class<? extends TunnelTypeBase> tunType,DataBroker dataBroker) {
         boolean existsFlag = false ;
         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                         ExternalTunnelList.class)
-                        .child(ExternalTunnel.class, getExternalTunnelKey(dstDpnOrNode, srcDpnOrNode));
+                        .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(dstDpnOrNode, srcDpnOrNode, tunType));
         Optional<ExternalTunnel> exTunnels = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,path, dataBroker) ;
-        if( exTunnels.isPresent())
+        if( exTunnels.isPresent()) {
             existsFlag = true ;
-        return existsFlag ;
     }
-
-    static ExternalTunnelKey getExternalTunnelKey(String dst , String src) {
-        if (src.indexOf("physicalswitch") > 0) {
-            src = src.substring(0, src.indexOf("physicalswitch") - 1);
-        }
-        if (dst.indexOf("physicalswitch") > 0) {
-            dst = dst.substring(0, dst.indexOf("physicalswitch") - 1);
-        }
-        return new ExternalTunnelKey(dst, src);
+        return existsFlag ;
     }
 
 
index c1850200f8c5e9bd5a5463fbc8ad0911d450ad92..9f2196434d279b5a08c28aeb9bc94c8ec5f081b1 100644 (file)
@@ -147,26 +147,34 @@ public class ItmInternalTunnelAddWorker {
         logger.trace( "Wiring between source tunnel end points {}, destination tunnel end points {} " , srcte, dstte );
         String interfaceName = srcte.getInterfaceName() ;
         Class<? extends TunnelTypeBase> tunType = srcte.getTunnelType();
-        String ifDescription = srcte.getTunnelType().getName();
+        String tunTypeStr = srcte.getTunnelType().getName();
         // Form the trunk Interface Name
-        String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName,srcte.getIpAddress().getIpv4Address().getValue(), dstte.getIpAddress().getIpv4Address().getValue()) ;
-        IpAddress gwyIpAddress = ( srcte.getSubnetMask().equals(dstte.getSubnetMask()) ) ? null : srcte.getGwIpAddress() ;
+        String trunkInterfaceName = ItmUtils.getTrunkInterfaceName( idManagerService, interfaceName,
+                                                                    srcte.getIpAddress().getIpv4Address().getValue(),
+                                                                    dstte.getIpAddress().getIpv4Address().getValue(),
+                                                                    tunTypeStr) ;
+        IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+        IpAddress gwyIpAddress = ( srcte.getSubnetMask().equals(dstte.getSubnetMask()) ) ? gatewayIpObj : srcte.getGwIpAddress() ;
         logger.debug(  " Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, source IP - {}, destination IP - {} gateway IP - {}",trunkInterfaceName, interfaceName, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress ) ;
-        Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName,
-                        String.format("%s %s", ifDescription, "Trunk Interface"), true, tunType, srcte.getIpAddress(),
-                        dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(), true, false, null);
+        Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+        Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
+        if(monitorInterval == null)
+            monitorInterval = ITMConstants.DEFAULT_MONITOR_INTERVAL;
+        Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName, String.format( "%s %s",ItmUtils.convertTunnelTypetoString(srcte.getTunnelType()), "Trunk Interface"), true, tunType, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(), true, monitorEnabled, monitorInterval*1000);
         logger.debug(  " Trunk Interface builder - {} ", iface ) ;
         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
         logger.debug(  " Trunk Interface Identifier - {} ", trunkIdentifier ) ;
         logger.trace(  " Writing Trunk Interface to Config DS {}, {} ", trunkIdentifier, iface ) ;
         t.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, iface, true);
+        ItmUtils.itmCache.addInterface(iface);
         // also update itm-state ds?
         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
                 TunnelList.class)
-                    .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId,srcDpnId ));
-        InternalTunnel tnl = ItmUtils.buildInternalTunnel(srcDpnId, dstDpnId, trunkInterfaceName);
+                    .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId, srcDpnId, tunType)); 
+        InternalTunnel tnl = ItmUtils.buildInternalTunnel(srcDpnId, dstDpnId, tunType, trunkInterfaceName);
         //ItmUtils.asyncUpdate(LogicalDatastoreType.CONFIGURATION, path, tnl, dataBroker, DEFAULT_CALLBACK);
         t.merge(LogicalDatastoreType.CONFIGURATION,path, tnl, true) ;
+        ItmUtils.itmCache.addInternalTunnel(tnl);
         return true;
     }
 }
index ed065b6eaa40fab4701461ba087b36d7970cd720..210622f79d190539e3028ff218b7cc3b657459b2 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.vpnservice.itm.impl.ItmUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpoints;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
@@ -53,7 +54,12 @@ public class ItmInternalTunnelDeleteWorker {
             }
             for (DPNTEPsInfo srcDpn : dpnTepsList) {
                 logger.trace("Processing srcDpn " + srcDpn);
-                List<TunnelEndPoints> meshedEndPtCache = new ArrayList<TunnelEndPoints>(srcDpn.getTunnelEndPoints()) ;
+                List<TunnelEndPoints> meshedEndPtCache = new ArrayList<TunnelEndPoints>(ItmUtils.getTEPsForDpn(srcDpn.getDPNID(), meshedDpnList)) ;
+                if(meshedEndPtCache == null ) {
+                    logger.debug("No Tunnel End Point configured for this DPN {}", srcDpn.getDPNID());
+                    continue ;
+                }
+                logger.debug( "Entries in meshEndPointCache {} ", meshedEndPtCache.size() );
                 for (TunnelEndPoints srcTep : srcDpn.getTunnelEndPoints()) {
                     logger.trace("Processing srcTep " + srcTep);
                     String srcTZone = srcTep.getTransportZone();
@@ -64,7 +70,7 @@ public class ItmInternalTunnelDeleteWorker {
                             for (TunnelEndPoints dstTep : dstDpn.getTunnelEndPoints()) {
                                 logger.trace("Processing dstTep " + dstTep);
                                 if (dstTep.getTransportZone().equals(srcTZone)) {
-                                    if( checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(), dataBroker)) {
+                                    if( checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(), srcTep.getTunnelType(),dataBroker)) {
                                     // remove all trunk interfaces
                                     logger.trace("Invoking removeTrunkInterface between source TEP {} , Destination TEP {} " ,srcTep , dstTep);
                                     removeTrunkInterface(dataBroker, idManagerService, srcTep, dstTep, srcDpn.getDPNID(), dstDpn.getDPNID(), t, futures);
@@ -79,7 +85,7 @@ public class ItmInternalTunnelDeleteWorker {
                                     InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.getKey())
                                                     .child(TunnelEndPoints.class, srcTep.getKey()).build();
 
-                    logger.trace("Tep Removal from DPNTEPSINFO CONFIG DS " + srcTep);
+                    logger.trace("Tep Removal of TEP {} from DPNTEPSINFO CONFIG DS with Key {} " + srcTep, srcTep.getKey());
                     t.delete(LogicalDatastoreType.CONFIGURATION, tepPath);
                     // remove the tep from the cache
                     meshedEndPtCache.remove(srcTep) ;
@@ -128,28 +134,31 @@ public class ItmInternalTunnelDeleteWorker {
                                              TunnelEndPoints srcTep, TunnelEndPoints dstTep, BigInteger srcDpnId, BigInteger dstDpnId,
                                              WriteTransaction t, List<ListenableFuture<Void>> futures) {
         String trunkfwdIfName =
-                        ItmUtils.getTrunkInterfaceName(idManagerService, srcTep.getInterfaceName(), srcTep.getIpAddress()
-                                        .getIpv4Address().getValue(), dstTep.getIpAddress().getIpv4Address()
-                                        .getValue());
+                        ItmUtils.getTrunkInterfaceName( idManagerService, srcTep.getInterfaceName(),
+                                                        srcTep.getIpAddress().getIpv4Address().getValue(),
+                                                        dstTep.getIpAddress().getIpv4Address().getValue(),
+                                                        srcTep.getTunnelType().getName());
         logger.trace("Removing forward Trunk Interface " + trunkfwdIfName);
         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkfwdIfName);
         logger.debug(  " Removing Trunk Interface Name - {} , Id - {} from Config DS ", trunkfwdIfName, trunkIdentifier ) ;
         t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
-
+        ItmUtils.itmCache.removeInterface(trunkfwdIfName);
         // also update itm-state ds -- Delete the forward tunnel-interface from the tunnel list
         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
                 TunnelList.class)
-                    .child(InternalTunnel.class, new InternalTunnelKey( srcDpnId, dstDpnId));   
+                    .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId, srcDpnId, srcTep.getTunnelType()));
         t.delete(LogicalDatastoreType.CONFIGURATION,path) ;
+        ItmUtils.itmCache.removeInternalTunnel(trunkfwdIfName);
         // Release the Ids for the forward trunk interface Name
         ItmUtils.releaseIdForTrunkInterfaceName(idManagerService,srcTep.getInterfaceName(), srcTep.getIpAddress()
                 .getIpv4Address().getValue(), dstTep.getIpAddress().getIpv4Address()
-                .getValue() );
+                .getValue(), srcTep.getTunnelType().getName() );
 
         String trunkRevIfName =
-                        ItmUtils.getTrunkInterfaceName(idManagerService, dstTep.getInterfaceName(), dstTep.getIpAddress()
-                                        .getIpv4Address().getValue(), srcTep.getIpAddress().getIpv4Address()
-                                        .getValue());
+                        ItmUtils.getTrunkInterfaceName( idManagerService, dstTep.getInterfaceName(),
+                                                        dstTep.getIpAddress().getIpv4Address().getValue(),
+                                                        srcTep.getIpAddress().getIpv4Address().getValue(),
+                                                        srcTep.getTunnelType().getName());
         logger.trace("Removing Reverse Trunk Interface " + trunkRevIfName);
         trunkIdentifier = ItmUtils.buildId(trunkRevIfName);
         logger.debug(  " Removing Trunk Interface Name - {} , Id - {} from Config DS ", trunkRevIfName, trunkIdentifier ) ;
@@ -158,19 +167,19 @@ public class ItmInternalTunnelDeleteWorker {
      // also update itm-state ds -- Delete the reverse tunnel-interface from the tunnel list
         path = InstanceIdentifier.create(
                 TunnelList.class)
-                    .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId));   
+                    .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, srcTep.getTunnelType()));
         t.delete(LogicalDatastoreType.CONFIGURATION,path) ;
         
      // Release the Ids for the reverse trunk interface Name
         ItmUtils.releaseIdForTrunkInterfaceName(idManagerService, dstTep.getInterfaceName(), dstTep.getIpAddress()
                 .getIpv4Address().getValue(), srcTep.getIpAddress().getIpv4Address()
-                .getValue());
+                .getValue(),dstTep.getTunnelType().getName());
     }
-    private static boolean checkIfTrunkExists( BigInteger srcDpnId, BigInteger dstDpnId, DataBroker dataBroker) {
+    private static boolean checkIfTrunkExists(BigInteger srcDpnId, BigInteger dstDpnId, Class<? extends TunnelTypeBase> tunType, DataBroker dataBroker) {
         boolean existsFlag = false ;
         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
                 TunnelList.class)
-                    .child(InternalTunnel.class, new InternalTunnelKey( srcDpnId, dstDpnId));   
+                    .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId, srcDpnId, tunType));
         Optional<InternalTunnel> internalTunnels = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,path, dataBroker) ;
         if( internalTunnels.isPresent())
             existsFlag = true ;
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorIntervalWorker.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorIntervalWorker.java
new file mode 100644 (file)
index 0000000..f2b64e6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.confighelpers;
+
+import com.google.common.util.concurrent.ListenableFuture;
+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.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Created by eanraju on 23-Mar-16.
+ */
+public class ItmMonitorIntervalWorker implements Callable<List<ListenableFuture<Void>>> {
+    private static final Logger logger = LoggerFactory.getLogger(ItmMonitorIntervalWorker.class) ;
+    private DataBroker dataBroker;
+    private String tzone;
+    private Integer interval;
+    private List<HwVtep> hwVteps;
+    private  Boolean exists;
+
+    public ItmMonitorIntervalWorker(List<HwVtep> hwVteps,String tzone,Integer interval, DataBroker dataBroker, Boolean exists){
+        this.dataBroker = dataBroker;
+        this.tzone = tzone;
+        this.interval = interval;
+        this.hwVteps = hwVteps;
+        this.exists = exists;
+        logger.trace("ItmMonitorToggleWorker initialized with  tzone {} and Interval {}",tzone,interval );
+    }
+
+    @Override public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>() ;
+        logger.debug("Invoking Tunnel Monitor Worker tzone = {} Interval= {}",tzone,interval );
+        WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+        toggleTunnelMonitoring(hwVteps,interval,tzone,t,exists);
+        futures.add(t.submit());
+        return futures;
+    }
+
+    private void toggleTunnelMonitoring(List<HwVtep> hwVteps,Integer interval, String tzone, WriteTransaction t,Boolean exists) {
+        //exists means hwVteps exist for this tzone
+
+        //List<String> TunnelList = ItmUtils.getTunnelsofTzone(hwVteps, tzone, dataBroker, exists);
+        List<String> TunnelList = ItmUtils.getInternalTunnelsofTzone(tzone,dataBroker);
+        if(TunnelList !=null &&!TunnelList.isEmpty()) {
+            for (String tunnel : TunnelList)
+                toggle(tunnel, interval,t);
+        }
+    }
+
+    private void toggle(String tunnelInterfaceName, Integer interval, WriteTransaction t) {
+        if (tunnelInterfaceName != null) {
+            logger.debug("tunnel {} will have monitor interval {}", tunnelInterfaceName, interval);
+            InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(tunnelInterfaceName);
+            IfTunnel tunnel = new IfTunnelBuilder().setMonitorInterval(interval.longValue() * 1000).build();
+            InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelInterfaceName))
+                            .addAugmentation(IfTunnel.class, tunnel);
+            t.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, builder.build());
+        }
+    }
+}
+
+
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorToggleWorker.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/confighelpers/ItmMonitorToggleWorker.java
new file mode 100644 (file)
index 0000000..de363d8
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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
+ */
+package org.opendaylight.vpnservice.itm.confighelpers;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+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.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Created by eanraju on 23-Mar-16.
+ */
+public class ItmMonitorToggleWorker implements Callable<List<ListenableFuture<Void>>> {
+    private static final Logger logger = LoggerFactory.getLogger(ItmMonitorToggleWorker.class) ;
+    private DataBroker dataBroker;
+    private String tzone;
+    private boolean enabled;
+    private List<HwVtep> hwVteps;
+    private  Boolean exists;
+
+  public  ItmMonitorToggleWorker(List<HwVtep> hwVteps,String tzone,boolean enabled, DataBroker dataBroker, Boolean exists){
+        this.dataBroker = dataBroker;
+        this.tzone = tzone;
+        this.enabled = enabled;
+        this.hwVteps = hwVteps;
+        this.exists = exists;
+        logger.trace("ItmMonitorToggleWorker initialized with  tzone {} and toggleBoolean {}",tzone,enabled );
+    }
+
+    @Override public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>() ;
+        logger.debug("Invoking Tunnel Monitor Worker tzone = {} enabled {}",tzone,enabled );
+        WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+        toggleTunnelMonitoring(hwVteps,enabled,tzone,t,exists);
+        futures.add(t.submit());
+        return futures;
+    }
+
+    private void toggleTunnelMonitoring(List<HwVtep> hwVteps,Boolean enabled, String tzone, WriteTransaction t,Boolean exists) {
+        //exists means hwVteps exist for this tzone
+
+        List<String> TunnelList = ItmUtils.getTunnelsofTzone(hwVteps,tzone,dataBroker,exists);
+        if(TunnelList !=null &&!TunnelList.isEmpty()) {
+            for (String tunnel : TunnelList)
+                toggle(tunnel, enabled,t);
+        }
+    }
+
+    private void toggle(String tunnelInterfaceName, boolean enabled, WriteTransaction t) {
+        if(tunnelInterfaceName!=null) {
+            InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(tunnelInterfaceName);
+            IfTunnel tunnel = new IfTunnelBuilder().setMonitorEnabled(enabled).build();
+            InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelInterfaceName))
+                            .addAugmentation(IfTunnel.class, tunnel);
+            t.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, builder.build());
+        }
+    }
+}
+
+
+
+
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmCache.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/impl/ItmCache.java
new file mode 100644 (file)
index 0000000..8366e2e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.itm.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+
+public class ItmCache {
+    private ConcurrentHashMap<String, Interface> interfaces = null;
+    private ConcurrentHashMap<String, ExternalTunnel> externalTunnels = null;
+    private ConcurrentHashMap<String, InternalTunnel> internalTunnels = null;
+
+    public ItmCache() {
+        this.interfaces = new ConcurrentHashMap<>();
+        this.internalTunnels = new ConcurrentHashMap<>();
+        this.externalTunnels = new ConcurrentHashMap<>();
+    }
+
+    public void addInterface(Interface iface) {
+        this.interfaces.put(iface.getName(), iface);
+    }
+
+    public Interface getInterface(String name) {
+        return this.interfaces.get(name);
+    }
+
+    public Interface removeInterface(String name) {
+        return this.interfaces.remove(name);
+    }
+
+    public Collection<Interface> getAllInterfaces() {
+        return this.interfaces.values();
+    }
+
+    public void addExternalTunnel(ExternalTunnel tunnel) {
+        this.externalTunnels.put(tunnel.getTunnelInterfaceName(), tunnel);
+    }
+
+    public ExternalTunnel getExternalTunnel(String name) {
+        return this.externalTunnels.get(name);
+    }
+
+    public ExternalTunnel removeExternalTunnel(String name) {
+        return this.externalTunnels.remove(name);
+    }
+
+    public void addInternalTunnel(InternalTunnel tunnel) {
+        this.internalTunnels.put(tunnel.getTunnelInterfaceName(), tunnel);
+    }
+
+    public InternalTunnel getInternalTunnel(String name) {
+        return this.internalTunnels.get(name);
+    }
+
+    public InternalTunnel removeInternalTunnel(String name) {
+        return this.internalTunnels.remove(name);
+    }
+
+}
index 57ed05ae157e49b0227347410e8bf0acb466cca7..413cf3f85ee7fb24e7e4697d9a0479f0d9b42e88 100644 (file)
@@ -24,9 +24,12 @@ import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 import org.opendaylight.vpnservice.itm.api.IITMProvider;
 import org.opendaylight.vpnservice.itm.cli.TepCommandHelper;
 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
-import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.itm.listeners.InterfaceStateListener;
 import org.opendaylight.vpnservice.itm.listeners.TransportZoneListener;
+import org.opendaylight.vpnservice.itm.listeners.TunnelMonitorChangeListener;
+import org.opendaylight.vpnservice.itm.listeners.TunnelMonitorIntervalListener;
 import org.opendaylight.vpnservice.itm.listeners.VtepConfigSchemaListener;
+import org.opendaylight.vpnservice.itm.monitoring.ItmTunnelEventListener;
 import org.opendaylight.vpnservice.itm.rpc.ItmManagerRpcService;
 import org.opendaylight.vpnservice.itm.snd.ITMStatusMonitor;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
@@ -40,8 +43,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev15
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -62,9 +65,13 @@ public class ItmProvider implements BindingAwareProvider, AutoCloseable, IITMPro
     private NotificationService notificationService;
     private TepCommandHelper tepCommandHelper;
     private TransportZoneListener tzChangeListener;
+    private TunnelMonitorChangeListener tnlToggleListener;
+    private TunnelMonitorIntervalListener tnlIntervalListener;
     private VtepConfigSchemaListener vtepConfigSchemaListener;
+    private InterfaceStateListener ifStateListener;
     private RpcProviderRegistry rpcProviderRegistry;
     private static final ITMStatusMonitor itmStatusMonitor = ITMStatusMonitor.getInstance();
+    private ItmTunnelEventListener itmStateListener;
     static short flag = 0;
 
     public ItmProvider() {
@@ -92,6 +99,9 @@ public class ItmProvider implements BindingAwareProvider, AutoCloseable, IITMPro
             tzChangeListener = new TransportZoneListener(dataBroker, idManager) ;
             itmRpcService = new ItmManagerRpcService(dataBroker, idManager);
             vtepConfigSchemaListener = new VtepConfigSchemaListener(dataBroker);
+            this.ifStateListener = new InterfaceStateListener(dataBroker);
+            tnlToggleListener = new TunnelMonitorChangeListener(dataBroker);
+            tnlIntervalListener = new TunnelMonitorIntervalListener(dataBroker);
             tepCommandHelper = new TepCommandHelper(dataBroker);
             final BindingAwareBroker.RpcRegistration<ItmRpcService> rpcRegistration = getRpcProviderRegistry().addRpcImplementation(ItmRpcService.class, itmRpcService);
             itmRpcService.setMdsalManager(mdsalManager);
@@ -101,8 +111,11 @@ public class ItmProvider implements BindingAwareProvider, AutoCloseable, IITMPro
             tzChangeListener.setMdsalManager(mdsalManager);
             tzChangeListener.setItmManager(itmManager);
             tzChangeListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            tnlIntervalListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            tnlToggleListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
             tepCommandHelper = new TepCommandHelper(dataBroker);
             tepCommandHelper.setInterfaceManager(interfaceManager);
+            itmStateListener =new ItmTunnelEventListener(dataBroker);
             createIdPool();
             itmStatusMonitor.reportStatus("OPERATIONAL");
         } catch (Exception e) {
@@ -134,7 +147,12 @@ public class ItmProvider implements BindingAwareProvider, AutoCloseable, IITMPro
         if (tzChangeListener != null) {
             tzChangeListener.close();
         }
-
+        if (tnlIntervalListener != null) {
+            tnlIntervalListener.close();
+        }
+        if(tnlToggleListener!= null){
+            tnlToggleListener.close();
+        }
         LOG.info("ItmProvider Closed");
     }
 
@@ -183,6 +201,12 @@ public class ItmProvider implements BindingAwareProvider, AutoCloseable, IITMPro
         tepCommandHelper.showTeps(itmManager.getTunnelMonitorEnabledFromConfigDS(),
                 itmManager.getTunnelMonitorIntervalFromConfigDS());
     }
+    public void showState(TunnelList tunnels) {
+        if (tunnels != null)
+           tepCommandHelper.showState(tunnels, itmManager.getTunnelMonitorEnabledFromConfigDS());
+        else
+            LOG.debug("No tunnels available");
+    }
 
     public void deleteVtep(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
             String gatewayIp, String transportZone) {
@@ -272,21 +296,27 @@ public class ItmProvider implements BindingAwareProvider, AutoCloseable, IITMPro
                 this);
         if (ItmUtils.getDpnIdList(schema.getDpnIds()) == null) {
             VtepConfigSchemaBuilder builder = new VtepConfigSchemaBuilder(schema);
+        if (ItmUtils.getDpnIdList(schema.getDpnIds()).isEmpty()) {
             builder.setDpnIds(schema.getDpnIds());
             schema = builder.build();
         } else {
             if (lstDpnsForAdd != null && !lstDpnsForAdd.isEmpty()) {
-                ItmUtils.getDpnIdList(schema.getDpnIds()).addAll(lstDpnsForAdd);
+                List<BigInteger> originalDpnList = ItmUtils.getDpnIdList(schema.getDpnIds()) ;
+                originalDpnList.addAll(lstDpnsForAdd) ;
+                builder.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(originalDpnList));
             }
             if (lstDpnsForDelete != null && !lstDpnsForDelete.isEmpty()) {
-                 ItmUtils.getDpnIdList(schema.getDpnIds()).removeAll(lstDpnsForDelete);
+                List<BigInteger> originalDpnList = ItmUtils.getDpnIdList(schema.getDpnIds()) ;
+                originalDpnList.removeAll(lstDpnsForAdd) ;
+                builder.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(originalDpnList)) ;
             }
         }
+        schema = builder.build();
         MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
                 ItmUtils.getVtepConfigSchemaIdentifier(schemaName), schema);
         LOG.debug("Vtep config schema {} updated to config DS with DPN's {}", schemaName, ItmUtils.getDpnIdList(schema.getDpnIds()));
     }
-
+    }
     /*
      * (non-Javadoc)
      * 
index 7aa7fa99649c04880bbfe13a1c0b250cd2deed00..c86cbe0c1257e0ab1a5f18e4cf25ce42eb8e9ef3 100644 (file)
@@ -31,6 +31,8 @@ import org.opendaylight.vpnservice.itm.confighelpers.HwVtep;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabled;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorInterval;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.VtepConfigSchemas;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.VtepIpPools;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
@@ -50,6 +52,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.interfaces._interface.NodeIdentifierKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpoints;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpointsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfoKey;
@@ -62,6 +66,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
@@ -69,15 +74,19 @@ import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 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.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIds ;
 //import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice._interface.service.rev150602._interface.service.info.ServiceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIdsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIdsKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZoneKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.Vteps;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
@@ -107,6 +116,7 @@ public class ItmUtils {
     public static final String TUNNEL_TYPE_VXLAN = "VXLAN";
     public static final String TUNNEL_TYPE_GRE = "GRE";
     public static final String TUNNEL = "TUNNEL";
+    public static ItmCache itmCache = new ItmCache();
 
     private static final Logger LOG = LoggerFactory.getLogger(ItmUtils.class);
 
@@ -176,14 +186,29 @@ public class ItmUtils {
         return dpnId;
     }
 
-    public static String getTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName, String localHostName, String remoteHostName) {
-        String trunkInterfaceName = String.format("%s:%s:%s", parentInterfaceName, localHostName, remoteHostName);
+    public static String getTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName,
+                                               String localHostName, String remoteHostName, String tunnelType) {
+        String tunnelTypeStr;
+        if(tunnelType.contains("TunnelTypeGre")) {
+            tunnelTypeStr = ITMConstants.TUNNEL_TYPE_GRE;
+        } else {
+            tunnelTypeStr = ITMConstants.TUNNEL_TYPE_VXLAN;
+        }
+        String trunkInterfaceName = String.format(  "%s:%s:%s:%s", parentInterfaceName, localHostName,
+                                                    remoteHostName, tunnelTypeStr);
+        LOG.trace("trunk interface name is {}", trunkInterfaceName);
         trunkInterfaceName = String.format("%s:%s", TUNNEL, getUniqueId(idManager, trunkInterfaceName));
         return trunkInterfaceName;
     }
 
-    public static void releaseIdForTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName, String localHostName, String remoteHostName) {
-        String trunkInterfaceName = String.format("%s:%s:%s", parentInterfaceName, localHostName, remoteHostName);
+    public static void releaseIdForTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName, String localHostName, String remoteHostName, String tunnelType) {
+        String tunnelTypeStr;
+        if(tunnelType.contains("TunnelTypeGre")) {
+            tunnelTypeStr = ITMConstants.TUNNEL_TYPE_GRE;
+        } else {
+            tunnelTypeStr = ITMConstants.TUNNEL_TYPE_VXLAN;
+        }
+        String trunkInterfaceName = String.format("%s:%s:%s:%s", parentInterfaceName, localHostName, remoteHostName, tunnelTypeStr);
         LOG.trace("Releasing Id for trunkInterface - {}", trunkInterfaceName );
         releaseId(idManager, trunkInterfaceName) ;
     }
@@ -194,7 +219,8 @@ public class ItmUtils {
 
     public static InstanceIdentifier<DPNTEPsInfo> getDPNTEPInstance(BigInteger dpIdKey) {
         InstanceIdentifier.InstanceIdentifierBuilder<DPNTEPsInfo> dpnTepInfoBuilder =
-                        InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpIdKey));
+                        InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class,
+                                        new DPNTEPsInfoKey(dpIdKey));
         InstanceIdentifier<DPNTEPsInfo> dpnInfo = dpnTepInfoBuilder.build();
         return dpnInfo;
     }
@@ -207,7 +233,7 @@ public class ItmUtils {
     public static TunnelEndPoints createTunnelEndPoints(BigInteger dpnId, IpAddress ipAddress, String portName, int vlanId,
                     IpPrefix prefix, IpAddress gwAddress, String zoneName, Class<? extends TunnelTypeBase>  tunnel_type) {
         // when Interface Mgr provides support to take in Dpn Id
-        return new TunnelEndPointsBuilder().setKey(new TunnelEndPointsKey(ipAddress, portName, vlanId))
+        return new TunnelEndPointsBuilder().setKey(new TunnelEndPointsKey(ipAddress, portName,tunnel_type, vlanId))
                         .setSubnetMask(prefix).setGwIpAddress(gwAddress).setTransportZone(zoneName)
                         .setInterfaceName(ItmUtils.getInterfaceName(dpnId, portName, vlanId)).setTunnelType(tunnel_type).build();
     }
@@ -224,7 +250,7 @@ public class ItmUtils {
     }
 
     public static Interface buildTunnelInterface(BigInteger dpn, String ifName, String desc, boolean enabled, Class<? extends TunnelTypeBase> tunType,
-       IpAddress localIp, IpAddress remoteIp, IpAddress gatewayIp,Integer vlanId, boolean internal, boolean monitorEnabled, Long monitorInterval) {
+                    IpAddress localIp, IpAddress remoteIp, IpAddress gatewayIp,Integer vlanId, boolean internal, Boolean monitorEnabled, Integer monitorInterval) {
        InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(ifName)).setName(ifName)
        .setDescription(desc).setEnabled(enabled).setType(Tunnel.class);
        ParentRefs parentRefs = new ParentRefsBuilder().setDatapathNodeIdentifier(dpn).build();
@@ -233,21 +259,25 @@ public class ItmUtils {
            IfL2vlan l2vlan = new IfL2vlanBuilder().setVlanId(new VlanId(vlanId)).build();
            builder.addAugmentation(IfL2vlan.class, l2vlan);
         }
-               //use default monitoring value from Global Constants
-        Long monitoringInterval = 10000L;
+        Long monitoringInterval = (long) ITMConstants.DEFAULT_MONITOR_INTERVAL;
+        Boolean monitoringEnabled = true;
         if(monitorInterval!= null)
-            monitoringInterval = monitorInterval;
-       IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(remoteIp).setTunnelGateway(gatewayIp).setTunnelSource(localIp)
-       .setTunnelInterfaceType(tunType).setInternal(internal).setMonitorEnabled(monitorEnabled).setMonitorInterval(monitoringInterval).build();
+            monitoringInterval = monitorInterval.longValue();
+        if(monitorEnabled!=null  )
+            monitoringEnabled = monitorEnabled;
+        IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(remoteIp).setTunnelGateway(
+                        gatewayIp).setTunnelSource(localIp)
+                        .setTunnelInterfaceType(tunType).setInternal(internal).setMonitorEnabled(
+                                        monitoringEnabled).setMonitorInterval(monitoringInterval).build();
        builder.addAugmentation(IfTunnel.class, tunnel);
        return builder.build();
     }
 
-    public static Interface buildHwTunnelInterface(String tunnelIfName, String desc , boolean enabled, String topo_id, String node_id,
-                                                   Class<? extends TunnelTypeBase> tunType, IpAddress srcIp , IpAddress destIp, IpAddress gWIp,
-                                                   boolean monitor_enabled
-    ){
-        InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelIfName)).setName(tunnelIfName).setDescription(desc).
+    public static Interface buildHwTunnelInterface(String tunnelIfName, String desc, boolean enabled, String topo_id,
+                    String node_id, Class<? extends TunnelTypeBase> tunType, IpAddress srcIp, IpAddress destIp,
+                    IpAddress gWIp, Boolean monitor_enabled, Integer monitor_interval){
+        InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelIfName)).setName(
+                        tunnelIfName).setDescription(desc).
                 setEnabled(enabled).setType(Tunnel.class);
         List<NodeIdentifier> nodeIds = new ArrayList<NodeIdentifier>();
         NodeIdentifier hWnode = new NodeIdentifierBuilder().setKey(new NodeIdentifierKey(topo_id)).setTopologyId(
@@ -256,24 +286,38 @@ public class ItmUtils {
         nodeIds.add(hWnode);
         ParentRefs parent = new ParentRefsBuilder().setNodeIdentifier(nodeIds).build();
         builder.addAugmentation(ParentRefs.class , parent);
+        Long monitoringInterval = (long) ITMConstants.DEFAULT_MONITOR_INTERVAL;
+        Boolean monitoringEnabled = true;
+        if(monitor_interval!= null)
+            monitoringInterval = monitor_interval.longValue();
+        if(monitor_enabled!=null  )
+            monitoringEnabled = monitor_enabled;
         IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(destIp).setTunnelGateway(gWIp).setTunnelSource(
-                        srcIp).setMonitorEnabled(monitor_enabled).setTunnelInterfaceType(tunType).setInternal(false).build();
+                        srcIp).setMonitorEnabled(monitoringEnabled).setMonitorInterval(100L).
+                        setTunnelInterfaceType(tunType).setInternal(false).build();
         builder.addAugmentation(IfTunnel.class, tunnel);
         LOG.trace("iftunnel {} built from hwvtep {} ",tunnel,node_id);
         return builder.build();
     }
 
 
-    public static InternalTunnel buildInternalTunnel( BigInteger srcDpnId, BigInteger dstDpnId, String trunkInterfaceName) {
-        InternalTunnel tnl = new InternalTunnelBuilder().setKey(new InternalTunnelKey(dstDpnId,srcDpnId)).setDestinationDPN(dstDpnId)
-                        .setSourceDPN(srcDpnId)
+    public static InternalTunnel buildInternalTunnel( BigInteger srcDpnId, BigInteger dstDpnId,
+                                                      Class<? extends TunnelTypeBase> tunType,
+                                                      String trunkInterfaceName) {
+        InternalTunnel tnl = new InternalTunnelBuilder().setKey(new InternalTunnelKey(dstDpnId, srcDpnId, tunType)).setDestinationDPN(dstDpnId)
+                        .setSourceDPN(srcDpnId).setTransportType(tunType)
             .setTunnelInterfaceName(trunkInterfaceName).build();
         return tnl ;
     }
 
-    public static ExternalTunnel buildExternalTunnel(String srcNode, String dstNode, String trunkInterfaceName) {
+    public static ExternalTunnel buildExternalTunnel(String srcNode, String dstNode,
+                                                     Class<? extends TunnelTypeBase> tunType,
+                                                     String trunkInterfaceName) {
         ExternalTunnel extTnl = new ExternalTunnelBuilder().setKey(
-                        new ExternalTunnelKey(dstNode, srcNode)).setSourceDevice(srcNode).setDestinationDevice(dstNode).setTunnelInterfaceName(trunkInterfaceName).build();
+                        new ExternalTunnelKey(dstNode, srcNode, tunType))
+                                .setSourceDevice(srcNode).setDestinationDevice(dstNode)
+                                .setTunnelInterfaceName(trunkInterfaceName)
+                                .setTransportType(tunType).build();
         return extTnl ;
     }
 
@@ -671,5 +715,259 @@ public class ItmUtils {
         return dpnIdList;
     }
 
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
+        InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
+                InstanceIdentifier.builder(InterfacesState.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+                                new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
+                                                interfaceName));
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
+        return id;
+}
+    public static Boolean readMonitoringStateFromDS(DataBroker dataBroker) {
+        InstanceIdentifier<TunnelMonitorEnabled> iid = InstanceIdentifier.create(TunnelMonitorEnabled.class);
+        Optional<TunnelMonitorEnabled> tunnelMonitorEnabledOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
+                        iid, dataBroker);
+        if(tunnelMonitorEnabledOptional.isPresent())
+            return tunnelMonitorEnabledOptional.get().isEnabled();
+        return null;
+    }
+
+    public static Integer readMonitorIntervalfromDS(DataBroker dataBroker) {
+        InstanceIdentifier<TunnelMonitorInterval> iid = InstanceIdentifier.create(TunnelMonitorInterval.class);
+        Optional<TunnelMonitorInterval> tunnelMonitorIOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
+        if(tunnelMonitorIOptional.isPresent())
+            return tunnelMonitorIOptional.get().getInterval();
+        return null;
+    }
+    public static List<String> getTunnelsofTzone(List<HwVtep> hwVteps, String tzone, DataBroker dataBroker, Boolean hwVtepsExist) {
+        List<String> tunnels = new ArrayList<String>();
+        InstanceIdentifier<TransportZone> path = InstanceIdentifier.builder(TransportZones.class).
+                        child(TransportZone.class, new TransportZoneKey(tzone)).build();
+        Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
+        Class<? extends TunnelTypeBase> tunType = tZoneOptional.get().getTunnelType();
+        if (tZoneOptional.isPresent()) {
+            if (tZoneOptional.get().getSubnets() != null && !tZoneOptional.get().getSubnets().isEmpty()) {
+                for (Subnets sub : tZoneOptional.get().getSubnets()) {
+                    if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
+                        for (Vteps vtepLocal : sub.getVteps()) {
+                            for (Vteps vtepRemote : sub.getVteps()) {
+                                if (!vtepLocal.equals(vtepRemote)) {
+                                    InternalTunnelKey key = new InternalTunnelKey(vtepRemote.getDpnId(), vtepLocal.getDpnId(), tunType);
+                                    InstanceIdentifier<InternalTunnel> intIID =
+                                                    InstanceIdentifier.builder(TunnelList.class).
+                                                                    child(InternalTunnel.class, key).build();
+                                    Optional<InternalTunnel> TunnelsOptional =
+                                                    ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intIID, dataBroker);
+                                    if (TunnelsOptional.isPresent()) {
+                                        LOG.trace("Internal Tunnel added {}",TunnelsOptional.get().getTunnelInterfaceName());
+                                        tunnels.add(TunnelsOptional.get().getTunnelInterfaceName());
+                                    }
+                                }
+                            }
+                            if(hwVteps!= null && !hwVteps.isEmpty()) {
+                                for (HwVtep hwVtep : hwVteps) {
+                                    tunnels.add(getExtTunnel(hwVtep.getNode_id(), vtepLocal.getDpnId().toString(),
+                                                    tunType, dataBroker));
+                                    tunnels.add(getExtTunnel(vtepLocal.getDpnId().toString(), hwVtep.getNode_id(),
+                                                    tunType, dataBroker));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (hwVtepsExist) {
+            for (HwVtep hwVtep : hwVteps) {
+                for (HwVtep hwVtepOther : hwVteps) {
+                    if (!hwVtep.getHwIp().equals(hwVtepOther.getHwIp())) {
+                        tunnels.add(getExtTunnel(hwVtep.getNode_id(), hwVtepOther.getNode_id(), tunType, dataBroker));
+                        tunnels.add(getExtTunnel(hwVtepOther.getNode_id(), hwVtep.getNode_id(), tunType, dataBroker));
+                    }
+                }
+            }
+        }
+        return tunnels;
+    }
+    public static List<String> getInternalTunnelsofTzone(String tzone, DataBroker dataBroker) {
+        List<String> tunnels = new ArrayList<String>();
+        LOG.trace("Getting internal tunnels of {}",tzone);
+        InstanceIdentifier<TransportZone> path = InstanceIdentifier.builder(TransportZones.class).
+                        child(TransportZone.class, new TransportZoneKey(tzone)).build();
+        Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
+        if (tZoneOptional.isPresent()) {
+            if (tZoneOptional.get().getSubnets() != null && !tZoneOptional.get().getSubnets().isEmpty()) {
+                for (Subnets sub : tZoneOptional.get().getSubnets()) {
+                    if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
+                        for (Vteps vtepLocal : sub.getVteps()) {
+                            for (Vteps vtepRemote : sub.getVteps()) {
+                                if (!vtepLocal.equals(vtepRemote)) {
+                                    InternalTunnelKey key = new InternalTunnelKey(vtepRemote.getDpnId(), vtepLocal.getDpnId(), tZoneOptional.get().getTunnelType());
+                                    InstanceIdentifier<InternalTunnel> intIID =
+                                                    InstanceIdentifier.builder(TunnelList.class).
+                                                                    child(InternalTunnel.class, key).build();
+                                    Optional<InternalTunnel> TunnelsOptional =
+                                                    ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intIID, dataBroker);
+                                    if (TunnelsOptional.isPresent()) {
+                                        LOG.trace("Internal Tunnel added {}",
+                                                        TunnelsOptional.get().getTunnelInterfaceName());
+                                        tunnels.add(TunnelsOptional.get().getTunnelInterfaceName());
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return tunnels;
+    }
+    private static String getExtTunnel(String node_id, String dpId,Class<? extends TunnelTypeBase> tunType, DataBroker dataBroker) {
+        LOG.trace("getting ext tunnel for {} and dpId {}",node_id,dpId);
+        ExternalTunnelKey key = getExternalTunnelKey(dpId,node_id, tunType);
+        InstanceIdentifier<ExternalTunnel> intIID = InstanceIdentifier.builder(ExternalTunnelList.class).
+                        child(ExternalTunnel.class, key).build();
+        Optional<ExternalTunnel> TunnelsOptional =
+                        ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intIID, dataBroker);
+        if (TunnelsOptional.isPresent()) {
+            LOG.trace("ext tunnel returned {} ",TunnelsOptional.get().getTunnelInterfaceName());
+            return TunnelsOptional.get().getTunnelInterfaceName();
+        }
+        return null;
+    }
+    public static ExternalTunnelKey getExternalTunnelKey(String dst , String src, Class<? extends TunnelTypeBase> tunType) {
+        if (src.indexOf("physicalswitch") > 0) {
+            src = src.substring(0, src.indexOf("physicalswitch") - 1);
+        }
+        if (dst.indexOf("physicalswitch") > 0) {
+            dst = dst.substring(0, dst.indexOf("physicalswitch") - 1);
+        }
+        return new ExternalTunnelKey(dst, src, tunType);
+    }
+    public static List<TunnelEndPoints> getTEPsForDpn( BigInteger srcDpn, List<DPNTEPsInfo> dpnList) {
+        for (DPNTEPsInfo dpn : dpnList) {
+            if( dpn.getDPNID().equals(srcDpn)) {
+                return dpn.getTunnelEndPoints() ;
+            }
+        }
+        return null ;
+    }
+    public static TunnelList getAllInternalTunnels(DataBroker broker) {
+        InstanceIdentifier<TunnelList> tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class).build();
+        Optional<TunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, tunnelListInstanceIdentifier, broker);
+        if (tunnelList.isPresent()) {
+            return tunnelList.get();
+        }
+        return null;
+    }
+    public static InternalTunnel getInternalTunnel(String interfaceName, DataBroker broker) {
+        InternalTunnel internalTunnel = null;
+        TunnelList tunnelList = getAllInternalTunnels(broker);
+        if (tunnelList != null && tunnelList.getInternalTunnel() != null) {
+            List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
+            for (InternalTunnel tunnel : internalTunnels) {
+                if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
+                    internalTunnel = tunnel;
+                    break;
+                }
+            }
+        }
+        return internalTunnel;
+    }
+    public static ExternalTunnel getExternalTunnel(String interfaceName, DataBroker broker) {
+        ExternalTunnel externalTunnel = null;
+        List<ExternalTunnel> externalTunnels = getAllExternalTunnels(broker);
+        for (ExternalTunnel tunnel : externalTunnels) {
+            if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
+                externalTunnel = tunnel;
+                break;
+            }
+        }
+        return externalTunnel;
+    }
+    public static List<ExternalTunnel> getAllExternalTunnels(DataBroker broker) {
+        List<ExternalTunnel> result = null;
+        InstanceIdentifier<ExternalTunnelList> id = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+        Optional<ExternalTunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, id, broker);
+        if (tunnelList.isPresent()) {
+            result = tunnelList.get().getExternalTunnel();
+        }
+        if (result == null) {
+            result = Collections.emptyList();
+        }
+        return result;
+    }
+    public static String convertTunnelTypetoString(Class<? extends TunnelTypeBase> tunType ) {
+        String tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN;
+        if( tunType.equals(TunnelTypeVxlan.class))
+            tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN ;
+        else if( tunType.equals(TunnelTypeGre.class) )
+            tunnelType = ITMConstants.TUNNEL_TYPE_GRE ;
+        else if (tunnelType.equals(TunnelTypeMplsOverGre.class))
+            tunnelType = ITMConstants.TUNNEL_TYPE_MPLS_OVER_GRE;
+        return tunnelType ;
+    }
+    public static boolean isItmIfType(Class<? extends InterfaceType> ifType) {
+        if( (ifType != null) && (ifType.isAssignableFrom(Tunnel.class)) ) {
+            return true;
+        }
+        return false;
+    }
+    public static StateTunnelListKey getTunnelStateKey( org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface iface) {
+        StateTunnelListKey key = null;
+        if(isItmIfType(iface.getType())) {
+            key = new StateTunnelListKey(iface.getName());
+        }
+        return key;
+    }
+    public static void updateTunnelsCache(DataBroker broker) {
+        List<InternalTunnel> internalTunnels = getAllInternalTunnels(broker, LogicalDatastoreType.CONFIGURATION);
+        for (InternalTunnel tunnel : internalTunnels) {
+            itmCache.addInternalTunnel(tunnel);
+        }
+        List<ExternalTunnel> externalTunnels = getAllExternalTunnels(broker, LogicalDatastoreType.CONFIGURATION);
+        for (ExternalTunnel tunnel : externalTunnels) {
+            itmCache.addExternalTunnel(tunnel);
+        }
+    }
+    public static List<ExternalTunnel> getAllExternalTunnels(DataBroker dataBroker, LogicalDatastoreType datastoreType) {
+        List<ExternalTunnel> result = null;
+        InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+        Optional<ExternalTunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
+        if (tunnelList.isPresent()) {
+            result = tunnelList.get().getExternalTunnel();
+        }
+        if (result == null) {
+            result = Collections.emptyList();
+        }
+        return result;
+    }
+    public static List<InternalTunnel> getAllInternalTunnels(DataBroker dataBroker, LogicalDatastoreType datastoreType) {
+        List<InternalTunnel> result = null;
+        InstanceIdentifier<TunnelList> iid = InstanceIdentifier.builder(TunnelList.class).build();
+        Optional<TunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
+        if (tunnelList.isPresent()) {
+            result = tunnelList.get().getInternalTunnel();
+        }
+        if (result == null) {
+            result = Collections.emptyList();
+        }
+        return result;
+    }
+    public static Interface getInterface(
+                    String name, DataBroker broker) {
+        Interface result = itmCache.getInterface(name);
+        if (result == null) {
+            InstanceIdentifier<Interface> iid =
+                            InstanceIdentifier.builder(Interfaces.class)
+                            .child(Interface.class, new InterfaceKey(name)).build();
+            Optional<Interface> optInterface = read(LogicalDatastoreType.CONFIGURATION, iid, broker);
+            if (optInterface.isPresent()) {
+                result = optInterface.get();
+                itmCache.addInterface(result);
+            }
+        }
+        return result;
+    }
 }
-
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java
new file mode 100644 (file)
index 0000000..49c9bda
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.itm.listeners;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeHwvtep;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeInternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelsState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.DstInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.SrcInfoBuilder;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+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.net.InetAddresses;
+
+public class InterfaceStateListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateListener.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker broker;
+
+    public InterfaceStateListener(final DataBroker db) {
+        super(Interface.class);
+        broker = db;
+        registerListener(db);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up interface state listener", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("Interface state listener Closed");
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), InterfaceStateListener.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("ITM Interfaces State listener registration fail!", e);
+            throw new IllegalStateException("ITM Interfaces State listener registration failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, Interface iface) {
+        LOG.trace("Interface added: {}", iface);
+        if(ItmUtils.isItmIfType(iface.getType())) {
+            LOG.debug("Interface of type Tunnel added: {}", iface.getName());
+            updateItmState(iface);
+        }
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier,
+            Interface iface) {
+        LOG.trace("Interface deleted: {}", iface);
+        if(ItmUtils.isItmIfType(iface.getType())) {
+            LOG.debug("Tunnel interface deleted: {}", iface.getName());
+            StateTunnelListKey tlKey = null;
+            tlKey = ItmUtils.getTunnelStateKey(iface);
+            InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
+            LOG.trace("Deleting tunnel_state for Id: {}", stListId);
+            ItmUtils.asyncDelete(LogicalDatastoreType.OPERATIONAL, stListId, broker, ItmUtils.DEFAULT_CALLBACK);
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier,
+            Interface original, Interface update) {
+        /*
+         * update contains only delta, may not include iftype
+         * Note: This assumes type can't be edited on the fly
+         */
+        if(ItmUtils.isItmIfType(original.getType())) {
+        LOG.trace("Interface updated. Old: {} New: {}", original, update);
+            OperStatus operStatus = update.getOperStatus();
+            if( operStatus != null ) {
+                LOG.debug("Tunnel Interface {} changed state to {}", original.getName(), operStatus);
+                updateItmState(update);
+            }
+        }
+    }
+
+    private void updateItmState(Interface iface) {
+        StateTunnelListKey tlKey = null;
+        tlKey = ItmUtils.getTunnelStateKey(iface);
+        LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, iface.getName());
+        InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
+        Optional<StateTunnelList> tunnelsState = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, stListId, broker);
+        StateTunnelList tunnelStateList;
+        StateTunnelListBuilder stlBuilder;
+        boolean tunnelState = (iface.getOperStatus().equals(OperStatus.Up)) ? (true):(false);
+        if(tunnelsState.isPresent()) {
+            tunnelStateList = tunnelsState.get();
+            stlBuilder = new StateTunnelListBuilder(tunnelStateList);
+            stlBuilder.setTunnelState(tunnelState);
+            StateTunnelList stList = stlBuilder.build();
+            LOG.trace("Updating tunnel_state: {} for Id: {}",stList, stListId);
+            ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, stList, broker, ItmUtils.DEFAULT_CALLBACK);
+        } else {
+            // Create new Tunnel State
+            try {
+                /*FIXME:
+                 * A defensive try-catch to find issues without disrupting existing behavior.
+                 */
+                tunnelStateList = buildStateTunnelList(tlKey, iface.getName(), tunnelState);
+                LOG.trace("Creating tunnel_state: {} for Id: {}", tunnelStateList, stListId);
+                ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, tunnelStateList, broker,
+                                ItmUtils.DEFAULT_CALLBACK);
+            } catch (Exception e) {
+                LOG.warn("Exception trying to create tunnel state for {}", iface.getName(), e);
+            }
+        }
+    }
+
+    private StateTunnelList buildStateTunnelList(StateTunnelListKey tlKey, String name, boolean state) {
+        StateTunnelListBuilder stlBuilder = new StateTunnelListBuilder();
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+                        ItmUtils.getInterface(name, broker);
+        IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
+        ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
+        if(ifTunnel == null && parentRefs == null) {
+            return null;
+        }
+        DstInfoBuilder dstInfoBuilder = new DstInfoBuilder();
+        SrcInfoBuilder srcInfoBuilder = new SrcInfoBuilder();
+        dstInfoBuilder.setTepIp(ifTunnel.getTunnelDestination());
+        srcInfoBuilder.setTepIp(ifTunnel.getTunnelSource());
+        //TODO: Add/Improve logic for device type
+        InternalTunnel internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
+        ExternalTunnel externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
+        if(internalTunnel == null && externalTunnel == null) {
+            // both not present in cache. let us update and try again.
+            ItmUtils.updateTunnelsCache(broker);
+            internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
+            externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
+        }
+        if(internalTunnel != null) {
+            srcInfoBuilder.setTepDeviceId(internalTunnel.getSourceDPN().toString()).setTepDeviceType(TepTypeInternal.class);
+            dstInfoBuilder.setTepDeviceId(internalTunnel.getDestinationDPN().toString())
+                .setTepDeviceType(TepTypeInternal.class);
+            stlBuilder.setTransportType(internalTunnel.getTransportType());
+        } else if(externalTunnel != null) {
+            ExternalTunnel tunnel = ItmUtils.itmCache.getExternalTunnel(name);
+            srcInfoBuilder.setTepDeviceId(tunnel.getSourceDevice())
+                .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()));
+            dstInfoBuilder.setTepDeviceId(tunnel.getDestinationDevice())
+                .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()))
+                .setTepIp(ifTunnel.getTunnelDestination());
+            stlBuilder.setTransportType(tunnel.getTransportType());
+        }
+        stlBuilder.setKey(tlKey).setTunnelInterfaceName(name).setTunnelState(state)
+            .setDstInfo(dstInfoBuilder.build()).setSrcInfo(srcInfoBuilder.build());
+        return stlBuilder.build();
+    }
+
+    private Class<? extends TepTypeBase> getDeviceType(String device) {
+        if(device.startsWith("hwvtep")) {
+            return TepTypeHwvtep.class;
+        } else if(InetAddresses.isInetAddress(device)) {
+            return TepTypeExternal.class;
+        } else {
+            return TepTypeInternal.class;
+        }
+    }
+
+    private InstanceIdentifier<StateTunnelList> buildStateTunnelListId(StateTunnelListKey tlKey) {
+        InstanceIdentifier<StateTunnelList> stListId =
+                        InstanceIdentifier.builder(TunnelsState.class).child(StateTunnelList.class, tlKey).build();
+        return stListId;
+    }
+
+}
index fae12dc6454223ca69eaa989c086c9446ceb6c9e..26c8f806b00f6253c939494106f7e3deb9200e19 100644 (file)
@@ -110,7 +110,7 @@ public class TransportZoneListener extends AsyncDataTreeChangeListenerBase<Trans
         LOG.trace("Delete: Invoking deleteTunnels in ItmManager with DpnList {}", opDpnList);
         if(opDpnList.size()>0 || hwVtepList.size()>0) {
             LOG.trace("Delete: Invoking ItmManager");
-            LOG.trace("Add: Invoking ItmManager with hwVtep List {} " , hwVtepList);
+            LOG.trace("Delete: Invoking ItmManager with hwVtep List {} " , hwVtepList);
             // itmManager.deleteTunnels(opDpnList);
             DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
             ItmTepRemoveWorker removeWorker = new ItmTepRemoveWorker(opDpnList,hwVtepList, dataBroker, idManagerService, mdsalManager);
@@ -220,12 +220,15 @@ public class TransportZoneListener extends AsyncDataTreeChangeListenerBase<Trans
                     int vlanID = subnet.getVlanId();
                     LOG.trace("IpPrefix: {}, gatewayIP: {}, vlanID: {} ", ipPrefix, gatewayIP, vlanID);
                     List<Vteps> vtepsList = subnet.getVteps();
+                    if(vtepsList!=null && !vtepsList.isEmpty()) {
                     for (Vteps vteps : vtepsList) {
                         BigInteger dpnID = vteps.getDpnId();
                         String port = vteps.getPortname();
                         IpAddress ipAddress = vteps.getIpAddress();
                         LOG.trace("DpnID: {}, port: {}, ipAddress: {}", dpnID, port, ipAddress);
-                    TunnelEndPoints tunnelEndPoints = ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port, vlanID, ipPrefix, gatewayIP, zone_name, tunnel_type);
+                            TunnelEndPoints tunnelEndPoints =
+                                            ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port, vlanID, ipPrefix,
+                                                            gatewayIP, zone_name, tunnel_type);
                         List<TunnelEndPoints> tunnelEndPointsList = mapDPNToTunnelEndpt.get(dpnID);
                         if (tunnelEndPointsList != null) {
                             LOG.trace("Existing DPN info list in the Map: {} ", dpnID);
@@ -235,6 +238,7 @@ public class TransportZoneListener extends AsyncDataTreeChangeListenerBase<Trans
                             tunnelEndPointsList = new ArrayList<TunnelEndPoints>();
                             tunnelEndPointsList.add(tunnelEndPoints);
                             mapDPNToTunnelEndpt.put(dpnID, tunnelEndPointsList);
+                            }
                         }
                     }
                 }
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorChangeListener.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorChangeListener.java
new file mode 100644 (file)
index 0000000..15aa039
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.listeners;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
+import org.opendaylight.vpnservice.itm.confighelpers.HwVtep;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmMonitorToggleWorker;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmTepAddWorker;
+import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVteps;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TunnelMonitorChangeListener  extends AsyncDataTreeChangeListenerBase<TunnelMonitorEnabled, TunnelMonitorChangeListener>
+                implements  AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(TunnelMonitorChangeListener.class);
+    private final DataBroker broker;
+   // private final IInterfaceManager interfaceManager;
+
+    public TunnelMonitorChangeListener(final DataBroker db) {
+        super(TunnelMonitorEnabled.class, TunnelMonitorChangeListener.class);
+        broker = db;
+       // interfaceManager = ifManager;
+       // registerListener(db);
+    }
+
+   /* private void registerListener(final DataBroker db) {
+        try {
+            TunnelMonitorChangeListener monitorEnabledChangeListener = new TunnelMonitorChangeListener();
+            monitorEnabledListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    monitorEnabledChangeListener.getWildCardPath(), monitorEnabledChangeListener, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("ITM Monitor Interfaces DataChange listener registration fail!", e);
+            throw new IllegalStateException("ITM Monitor registration Listener failed.", e);
+        }
+    }
+*/    @Override
+    public void close() throws Exception {
+       /* if (monitorEnabledListenerRegistration != null) {
+            try {
+                monitorEnabledListenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            monitorEnabledListenerRegistration = null;
+        }
+
+        if (monitorIntervalListenerRegistration != null) {
+            try {
+                monitorIntervalListenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            monitorIntervalListenerRegistration = null;
+        }
+*/
+        LOG.info("Tunnel Monitor listeners Closed");
+    }
+
+    @Override protected InstanceIdentifier<TunnelMonitorEnabled> getWildCardPath() {
+        return InstanceIdentifier.create(TunnelMonitorEnabled.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<TunnelMonitorEnabled> key, TunnelMonitorEnabled dataObjectModification) {
+        List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+        Boolean hwVtepsExist = false;
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+        Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+        if (tZonesOptional.isPresent()) {
+            TransportZones tZones = tZonesOptional.get();
+            for (TransportZone tzone : tZones.getTransportZone()) {
+                hwVtepsExist = false;
+                hwVteps = new ArrayList<HwVtep>();
+                if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+                    for (Subnets sub : tzone.getSubnets()) {
+                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                            hwVtepsExist = true;
+                            for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+                                HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+                                                deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+                                                tzone.getTunnelType(), tzone);
+                                hwVteps.add(hwVtep);
+                            }
+                        }
+                    }
+                }
+                LOG.debug("Remove:Calling TunnelMonitorToggleWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.isEnabled());
+                ItmMonitorToggleWorker toggleWorker = new ItmMonitorToggleWorker(hwVteps, tzone.getZoneName(),
+                                false, broker, hwVtepsExist);
+                coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+            }
+        }
+    }
+
+
+    @Override protected void update(InstanceIdentifier<TunnelMonitorEnabled> key,
+                    TunnelMonitorEnabled dataObjectModificationBefore,
+                    TunnelMonitorEnabled dataObjectModificationAfter) {
+        LOG.debug("update TunnelMonitorChangeListener called with {}",dataObjectModificationAfter.isEnabled());
+        List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+        Boolean hwVtepsExist = false;
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+        Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+        if (tZonesOptional.isPresent()) {
+            TransportZones tZones = tZonesOptional.get();
+            for (TransportZone tzone : tZones.getTransportZone()) {
+                hwVtepsExist = false;
+                hwVteps = new ArrayList<HwVtep>();
+                if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+                    for (Subnets sub : tzone.getSubnets()) {
+                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                            hwVtepsExist = true;//gets set to true only if this particular tzone has
+                            LOG.debug("Update:Calling TunnelMonitorToggleWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+                            for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+                                HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+                                                deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+                                                tzone.getTunnelType(), tzone);
+                                hwVteps.add(hwVtep);
+                            }
+                        }
+                    }
+                }
+                LOG.debug("Update:Calling TunnelMonitorToggleWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModificationAfter.isEnabled());
+                ItmMonitorToggleWorker toggleWorker = new ItmMonitorToggleWorker(hwVteps, tzone.getZoneName(),
+                                dataObjectModificationAfter.isEnabled(), broker, hwVtepsExist);
+                coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+            }
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<TunnelMonitorEnabled> key, TunnelMonitorEnabled dataObjectModification) {
+        LOG.debug("add TunnelMonitorChangeListener called with {}",dataObjectModification.isEnabled());
+        List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+        Boolean hwVtepsExist = false;
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+        Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+        if (tZonesOptional.isPresent()) {
+            TransportZones tZones = tZonesOptional.get();
+            for (TransportZone tzone : tZones.getTransportZone()) {
+                hwVtepsExist = false;
+                hwVteps = new ArrayList<HwVtep>();
+                if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+                    for (Subnets sub : tzone.getSubnets()) {
+                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                            hwVtepsExist = true;
+                            for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+                                HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+                                                deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+                                                tzone.getTunnelType(), tzone);
+                                hwVteps.add(hwVtep);
+                            }
+                        }
+                    }
+                }
+                LOG.debug("Add:Calling TunnelMonitorToggleWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.isEnabled());
+                ItmMonitorToggleWorker toggleWorker = new ItmMonitorToggleWorker(hwVteps, tzone.getZoneName(),
+                                dataObjectModification.isEnabled(), broker, hwVtepsExist);
+                coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+            }
+        }
+    }
+
+    @Override protected TunnelMonitorChangeListener getDataTreeChangeListener() {
+        return TunnelMonitorChangeListener.this;
+    }
+
+}
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorIntervalListener.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/TunnelMonitorIntervalListener.java
new file mode 100644 (file)
index 0000000..42b0d70
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.listeners;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
+import org.opendaylight.vpnservice.itm.confighelpers.HwVtep;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmMonitorIntervalWorker;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmMonitorToggleWorker;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmTepAddWorker;
+import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabled;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorInterval;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVteps;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TunnelMonitorIntervalListener  extends AsyncDataTreeChangeListenerBase<TunnelMonitorInterval, TunnelMonitorIntervalListener>
+                implements  AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(TunnelMonitorIntervalListener.class);
+    private ListenerRegistration<DataChangeListener> monitorIntervalListenerRegistration;
+    private final DataBroker broker;
+
+    public TunnelMonitorIntervalListener(DataBroker db) {
+        super(TunnelMonitorInterval.class, TunnelMonitorIntervalListener.class);
+        broker = db;
+    }
+
+    @Override protected InstanceIdentifier<TunnelMonitorInterval> getWildCardPath() {
+        return InstanceIdentifier.create(TunnelMonitorInterval.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<TunnelMonitorInterval> key, TunnelMonitorInterval dataObjectModification) {
+        LOG.debug("remove TunnelMonitorIntervalListener called with {}",dataObjectModification.getInterval());
+        List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+        Boolean hwVtepsExist = false;
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+        Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+        if (tZonesOptional.isPresent()) {
+            TransportZones tZones = tZonesOptional.get();
+            for (TransportZone tzone : tZones.getTransportZone()) {
+              /*  hwVtepsExist = false;
+                hwVteps = new ArrayList<HwVtep>();
+                if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+                    for (Subnets sub : tzone.getSubnets()) {
+                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                            hwVtepsExist = true;
+                            LOG.debug("Remove:Calling TunnelMonitorIntervalWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+                            for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+                                HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+                                                deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+                                                tzone.getTunnelType(), tzone);
+                                hwVteps.add(hwVtep);
+                            }
+                        }
+                    }
+                }*/
+                //if you remove configuration, the last configured interval is only set i.e no change
+                LOG.debug("Remove:Calling TunnelMonitorIntervalWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.getInterval());
+                ItmMonitorIntervalWorker toggleWorker = new ItmMonitorIntervalWorker(hwVteps, tzone.getZoneName(),
+                                dataObjectModification.getInterval(), broker, hwVtepsExist);
+                coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+            }
+        }
+    }
+
+    @Override protected void update(InstanceIdentifier<TunnelMonitorInterval> key,
+                    TunnelMonitorInterval dataObjectModificationBefore,
+                    TunnelMonitorInterval dataObjectModificationAfter) {
+        LOG.debug("update TunnelMonitorIntervalListener called with {}",dataObjectModificationAfter.getInterval());
+        List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+        Boolean hwVtepsExist = false;
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+        Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+        if (tZonesOptional.isPresent()) {
+            TransportZones tZones = tZonesOptional.get();
+            for (TransportZone tzone : tZones.getTransportZone()) {
+                /*hwVtepsExist = false;
+                hwVteps = new ArrayList<HwVtep>();
+                if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+                    for (Subnets sub : tzone.getSubnets()) {
+                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                            hwVtepsExist = true;//gets set to true only if this particular tzone has
+                            LOG.debug("Update:Calling TunnelMonitorIntervalWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+                            for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+                                HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+                                                deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+                                                tzone.getTunnelType(), tzone);
+                                hwVteps.add(hwVtep);
+                            }
+                        }
+                    }
+                }*/
+                LOG.debug("Update:Calling TunnelMonitorIntervalWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModificationAfter.getInterval());
+                ItmMonitorIntervalWorker intervalWorker = new ItmMonitorIntervalWorker(hwVteps, tzone.getZoneName(),
+                                dataObjectModificationAfter.getInterval(), broker, hwVtepsExist);
+                coordinator.enqueueJob(tzone.getZoneName(), intervalWorker);
+            }
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<TunnelMonitorInterval> key, TunnelMonitorInterval dataObjectModification) {
+        LOG.debug("Add TunnelMonitorIntervalListener called with {}",dataObjectModification.getInterval());
+        List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+        Boolean hwVtepsExist = false;
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+        Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+        if (tZonesOptional.isPresent()) {
+            TransportZones tZones = tZonesOptional.get();
+            for (TransportZone tzone : tZones.getTransportZone()) {
+                /*hwVtepsExist = false;
+                hwVteps = new ArrayList<HwVtep>();
+                if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+                    for (Subnets sub : tzone.getSubnets()) {
+                        if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+                            hwVtepsExist = true;
+                            LOG.debug("Add:Calling TunnelMonitorIntervalWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+                            for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+                                HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+                                                deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+                                                tzone.getTunnelType(), tzone);
+                                hwVteps.add(hwVtep);
+                            }
+                        }
+                    }
+                }*/
+                LOG.debug("Add:Calling TunnelMonitorIntervalWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.getInterval());
+                ItmMonitorIntervalWorker intervalWorker = new ItmMonitorIntervalWorker(hwVteps, tzone.getZoneName(),
+                                dataObjectModification.getInterval(), broker, hwVtepsExist);
+                //conversion to milliseconds done while writing to i/f-mgr config DS
+                coordinator.enqueueJob(tzone.getZoneName(), intervalWorker);
+            }
+        }
+    }
+
+    @Override protected TunnelMonitorIntervalListener getDataTreeChangeListener() {
+        return TunnelMonitorIntervalListener.this;
+    }
+}
index 9b8b138c1b22f351f8ecd77eea260a008e6b0fed..cc9af90ab771f50040602f1cea0c2c7f7cf20687 100644 (file)
@@ -5,7 +5,6 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.vpnservice.itm.listeners;
 
 import java.math.BigInteger;
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarm.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarm.java
new file mode 100644 (file)
index 0000000..99fbd9a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.monitoring;
+
+import javax.management.AttributeChangeNotification;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import java.util.ArrayList;
+
+/**
+ * Created by emnqrrw on 10/27/2015.
+ */
+public class DataPathAlarm extends NotificationBroadcasterSupport implements DataPathAlarmMBean {
+
+    ArrayList<String> raiseAlarmObject = new ArrayList<String>();
+    ArrayList<String> clearAlarmObject = new ArrayList<String>();
+    private long sequenceNumber = 1;
+
+    public void setRaiseAlarmObject(ArrayList<String> raiseAlarmObject) {
+        this.raiseAlarmObject = raiseAlarmObject;
+
+        Notification n = new AttributeChangeNotification(this,
+                sequenceNumber++, System.currentTimeMillis(),
+                "raise alarm object notified ", "raiseAlarmObject", "ArrayList",
+                "", this.raiseAlarmObject);
+        sendNotification(n);
+    }
+
+    public ArrayList<String> getRaiseAlarmObject() {
+        return raiseAlarmObject;
+    }
+
+    public void setClearAlarmObject(ArrayList<String> clearAlarmObject) {
+        this.clearAlarmObject = clearAlarmObject;
+
+        Notification n = new AttributeChangeNotification(this,
+                sequenceNumber++, System.currentTimeMillis(),
+                "clear alarm object notified ", "clearAlarmObject", "ArrayList",
+                "", this.clearAlarmObject);
+        sendNotification(n);
+    }
+
+    public ArrayList<String> getClearAlarmObject() {
+        return clearAlarmObject;
+    }
+
+    public synchronized void raiseAlarm(String alarmName, String additionalText, String source){
+        raiseAlarmObject.add(alarmName);
+        raiseAlarmObject.add(additionalText);
+        raiseAlarmObject.add(source);
+        setRaiseAlarmObject(raiseAlarmObject);
+        raiseAlarmObject.clear();
+    }
+    public synchronized void clearAlarm(String alarmName, String additionalText, String source){
+        clearAlarmObject.add(alarmName);
+        clearAlarmObject.add(additionalText);
+        clearAlarmObject.add(source);
+        setClearAlarmObject(clearAlarmObject);
+        clearAlarmObject.clear();
+    }
+}
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarmMBean.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/DataPathAlarmMBean.java
new file mode 100644 (file)
index 0000000..8c3f21a
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.monitoring;
+
+import java.util.ArrayList;
+
+/**
+ * Created by emnqrrw on 10/27/2015.
+ */
+public interface DataPathAlarmMBean {
+    public void setRaiseAlarmObject(ArrayList<String> raiseAlarmObject);
+    public ArrayList<String> getRaiseAlarmObject();
+    public void setClearAlarmObject(ArrayList<String> clearAlarmObject);
+    public ArrayList<String> getClearAlarmObject();
+    public void raiseAlarm(String alarmName, String additionalText, String source);
+    public void clearAlarm(String alarmName, String additionalText, String source);
+}
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/ItmTunnelEventListener.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/ItmTunnelEventListener.java
new file mode 100644 (file)
index 0000000..7ff0f0d
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.monitoring;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+
+/**
+ * Created by emnqrrw on 11/2/2015.
+ */
+public class ItmTunnelEventListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+
+    private static final Logger logger = LoggerFactory.getLogger(ItmTunnelEventListener.class);
+    private final DataBroker broker;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    public static final JMXAlarmAgent alarmAgent = new JMXAlarmAgent();
+
+    public ItmTunnelEventListener(final DataBroker db){
+        super(Interface.class);
+        broker = db;
+        registerListener(db);
+        alarmAgent.registerMbean();
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                            getWildCardPath(), ItmTunnelEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            logger.error("ITM Monitor Interfaces DataChange listener registration fail!", e);
+            throw new IllegalStateException("ITM Monitor registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
+        String ifName = del.getName() ;
+        if( del.getType() != null && del.getType().equals(Tunnel.class)) {
+            InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName,broker);
+            if( internalTunnel != null) {
+                BigInteger srcDpId = internalTunnel.getSourceDPN();
+                BigInteger dstDpId = internalTunnel.getDestinationDPN();
+                String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
+                logger.trace("ITM Tunnel removed b/w srcDpn: {} and dstDpn: {} for tunnelType: {}", srcDpId, dstDpId, tunnelType);
+                clearInternalDataPathAlarm(srcDpId.toString(),dstDpId.toString(),tunnelType);
+            }else {
+                ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
+                if( externalTunnel != null) {
+                    String srcNode = externalTunnel.getSourceDevice();
+                    String dstNode = externalTunnel.getDestinationDevice();
+                    String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
+                    logger.trace("ITM Tunnel removed b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode, tunnelType);
+                    clearExternalDataPathAlarm(srcNode,dstNode,tunnelType);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+        String ifName = update.getName() ;
+        if( update.getType() != null && update.getType().equals(Tunnel.class)) {
+            InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName,broker);
+            if( internalTunnel != null) {
+                BigInteger srcDpId = internalTunnel.getSourceDPN();
+                BigInteger dstDpId = internalTunnel.getDestinationDPN();
+                String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
+                logger.trace("ITM Tunnel state event changed from :{} to :{} for Tunnel Interface - {}", isTunnelInterfaceUp(original), isTunnelInterfaceUp(update), ifName);
+                if(isTunnelInterfaceUp(update)) {
+                    logger.trace("ITM Tunnel State is UP b/w srcDpn: {} and dstDpn: {} for tunnelType {} ", srcDpId, dstDpId, tunnelType);
+                    clearInternalDataPathAlarm(srcDpId.toString(),dstDpId.toString(),tunnelType);
+                }else {
+                    logger.trace("ITM Tunnel State is DOWN b/w srcDpn: {} and dstDpn: {}", srcDpId, dstDpId);
+                    StringBuilder alarmText = new StringBuilder();
+                    alarmText.append("Data Path Connectivity is lost between ").append("openflow:").append(srcDpId).append(" and openflow:")
+                                    .append(dstDpId).append(" for tunnelType:").append(tunnelType);
+                    raiseInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType,alarmText.toString());
+                }
+            }else{
+                ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
+                if( externalTunnel != null) {
+                    String srcNode = externalTunnel.getSourceDevice();
+                    String dstNode = externalTunnel.getDestinationDevice();
+                    String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
+                    logger.trace("ITM Tunnel state event changed from :{} to :{} for Tunnel Interface - {}", isTunnelInterfaceUp(original), isTunnelInterfaceUp(update), ifName);
+                    if(isTunnelInterfaceUp(update)) {
+                        logger.trace("ITM Tunnel State is UP b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode, tunnelType);
+                        clearExternalDataPathAlarm(srcNode.toString(),dstNode.toString(),tunnelType);
+                    }else {
+                        logger.trace("ITM Tunnel State is DOWN b/w srcNode: {} and dstNode: {}", srcNode, dstNode);
+                        StringBuilder alarmText = new StringBuilder();
+                        alarmText.append("Data Path Connectivity is lost between ").append(srcNode).append(dstNode).append(" for tunnelType:").append(tunnelType);
+                        raiseExternalDataPathAlarm(srcNode, dstNode, tunnelType,alarmText.toString());
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
+        String ifName = add.getName() ;
+        if( add.getType() != null && add.getType().equals(Tunnel.class)) {
+            InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName,broker);
+            if( internalTunnel != null) {
+                BigInteger srcDpId = internalTunnel.getSourceDPN();
+                BigInteger dstDpId = internalTunnel.getDestinationDPN();
+                String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
+                if(!isTunnelInterfaceUp(add)) {
+                    logger.trace("ITM Tunnel State during tep add is DOWN b/w srcDpn: {} and dstDpn: {} for tunnelType: {}", srcDpId, dstDpId, tunnelType);
+                    StringBuilder alarmText = new StringBuilder();
+                    alarmText.append("Data Path Connection is down between ").append("openflow:").append(srcDpId).append(" and openflow:")
+                                    .append(dstDpId).append(" for tunnelType:").append(tunnelType).append(" during initial state");
+                    raiseInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType, alarmText.toString());
+                }
+            }else {
+                ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
+                if( externalTunnel != null) {
+                    String srcNode = externalTunnel.getSourceDevice();
+                    String dstNode = externalTunnel.getDestinationDevice();
+                    String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
+                    if(!isTunnelInterfaceUp(add)) {
+                        logger.trace("ITM Tunnel State during tep add is DOWN b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode, tunnelType);
+                        StringBuilder alarmText = new StringBuilder();
+                        alarmText.append("Data Path Connection is down between ").append(srcNode).append(dstNode).append(" for tunnelType:").append(tunnelType).append(" during initial state");
+                        raiseExternalDataPathAlarm(srcNode, dstNode, tunnelType,alarmText.toString());
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    public void raiseInternalDataPathAlarm(String srcDpnId,String dstDpnId,String tunnelType,String alarmText) {
+
+        StringBuilder source = new StringBuilder();
+        source.append("srcDpn=openflow:").append(srcDpnId).append("-dstDpn=openflow:").append(dstDpnId).append("-tunnelType").append(tunnelType);
+
+        logger.trace("Raising DataPathConnectionFailure alarm... alarmText {} source {} ", alarmText, source);
+        //Invokes JMX raiseAlarm method
+        alarmAgent.invokeFMraisemethod("DataPathConnectionFailure", alarmText, source.toString());
+    }
+
+    public void clearInternalDataPathAlarm(String srcDpnId,String dstDpnId,String tunnelType) {
+        StringBuilder source = new StringBuilder();
+
+        source.append("srcDpn=openflow:").append(srcDpnId).append("-dstDpn=openflow:").append(dstDpnId).append("-tunnelType").append(tunnelType);
+        logger.trace("Clearing DataPathConnectionFailure alarm of source {} ", source);
+        //Invokes JMX clearAlarm method
+        alarmAgent.invokeFMclearmethod("DataPathConnectionFailure", "Clearing ITM Tunnel down alarm", source.toString());
+    }
+
+    public void raiseExternalDataPathAlarm(String srcDevice,String dstDevice,String tunnelType, String alarmText) {
+
+        StringBuilder source = new StringBuilder();
+        source.append("srcDevice=").append(srcDevice).append("-dstDevice=").append(dstDevice).append("-tunnelType").append(tunnelType);
+
+        logger.trace("Raising DataPathConnectionFailure alarm... alarmText {} source {} ", alarmText, source);
+        //Invokes JMX raiseAlarm method
+        alarmAgent.invokeFMraisemethod("DataPathConnectionFailure", alarmText, source.toString());
+    }
+
+
+    public void clearExternalDataPathAlarm(String srcDevice,String dstDevice,String tunnelType) {
+
+        StringBuilder source = new StringBuilder();
+
+        source.append("srcDevice=").append(srcDevice).append("-dstDevice=").append(dstDevice).append("-tunnelType").append(tunnelType);
+
+        //logger.trace("Clearing DataPathConnectionFailure alarm of source {} ", source);
+        //Invokes JMX clearAlarm method
+        alarmAgent.invokeFMclearmethod("DataPathConnectionFailure", "Clearing ITM Tunnel down alarm", source.toString());
+
+    }
+
+    private boolean isTunnelInterfaceUp( Interface intf) {
+        boolean interfaceUp = (intf.getOperStatus().equals(Interface.OperStatus.Up)) ? true :false ;
+        return interfaceUp ;
+    }
+
+}
diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/JMXAlarmAgent.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/monitoring/JMXAlarmAgent.java
new file mode 100644 (file)
index 0000000..ec35d24
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.itm.monitoring;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.*;
+import java.lang.management.ManagementFactory;
+/**
+ * Created by emnqrrw on 11/2/2015.
+ */
+public class JMXAlarmAgent {
+    static Logger s_logger = LoggerFactory.getLogger(JMXAlarmAgent.class);
+    private MBeanServer mbs = null;
+    private ObjectName alarmName = null;
+    private static final String BEANNAME = "SDNC.FM:name=DataPathAlarmBean";
+    private static DataPathAlarm alarmBean= new DataPathAlarm();
+
+    public JMXAlarmAgent() {
+        // Get the platform MBeanServer
+        mbs = ManagementFactory.getPlatformMBeanServer();
+        try {
+            alarmName = new ObjectName(BEANNAME);
+        } catch (MalformedObjectNameException e) {
+            s_logger.error("ObjectName instance creation failed for BEANAME {} : {}",BEANNAME, e);
+        }
+    }
+
+    public void registerMbean() {
+        // Unique identification of MBeans
+        try {
+            // Uniquely identify the MBeans and register them with the platform MBeanServer
+            if(!mbs.isRegistered(alarmName)) {
+                mbs.registerMBean(alarmBean, alarmName);
+                s_logger.debug("Registered Mbean {} successfully", alarmName);
+            }
+        } catch(Exception e) {
+            s_logger.error("Registeration failed for Mbean {} :{}", alarmName,e);
+        }
+    }
+
+    public void unregisterMbean() {
+        try {
+            if(mbs.isRegistered(alarmName)) {
+                mbs.unregisterMBean(alarmName);
+                s_logger.debug("Unregistered Mbean {} successfully", alarmName);
+            }
+        } catch (Exception e) {
+            s_logger.error("UnRegisteration failed for Mbean {} :{}", alarmName,e);
+        }
+    }
+
+    public void invokeFMraisemethod(String alarmId,String text,String src) {
+        try {
+            mbs.invoke(alarmName, "raiseAlarm", new Object[]{alarmId, text, src}, new String[]{String.class.getName(), String.class.getName(), String.class.getName()});
+            s_logger.trace("Invoked raiseAlarm function for Mbean {} with source {}", BEANNAME, src);
+        } catch (Exception e) {
+            s_logger.error("Invoking raiseAlarm method failed for Mbean {} :{}", alarmName,e);
+        }
+    }
+
+    public void invokeFMclearmethod(String alarmId,String text,String src) {
+        try {
+            mbs.invoke(alarmName, "clearAlarm", new Object[]{alarmId, text, src}, new String[]{String.class.getName(), String.class.getName(), String.class.getName()});
+            s_logger.trace("Invoked clearAlarm function for Mbean {} with source {}",BEANNAME,src);
+        } catch (Exception e) {
+            s_logger.error("Invoking clearAlarm method failed for Mbean {} :{}", alarmName,e);
+        }
+    }
+}
index a373472b56bbf8f4d98fb977413b0cc68760c6e1..26b007a9db7f421fcc3402c3875415697b5ffce5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
@@ -15,6 +15,7 @@ import java.util.concurrent.Future;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.vpnservice.mdsalutil.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZoneKey;
@@ -81,7 +82,7 @@ public class ItmManagerRpcService implements ItmRpcService {
         BigInteger destinationDpn = input.getDestinationDpid() ;
         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
                 TunnelList.class)
-                .child(InternalTunnel.class, new InternalTunnelKey( destinationDpn,sourceDpn));
+                .child(InternalTunnel.class, new InternalTunnelKey(destinationDpn, sourceDpn, input.getTunnelType()));
 
         Optional<InternalTunnel> tnl = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
 
@@ -170,7 +171,7 @@ public class ItmManagerRpcService implements ItmRpcService {
         String dstNode = input.getDestinationNode();
         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
                 ExternalTunnelList.class)
-                .child(ExternalTunnel.class, new ExternalTunnelKey(dstNode, sourceNode));
+                .child(ExternalTunnel.class, new ExternalTunnelKey(dstNode, sourceNode, input.getTunnelType()));
 
         Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
 
@@ -193,7 +194,7 @@ public class ItmManagerRpcService implements ItmRpcService {
         LOG.info("create terminatingServiceAction on DpnId = {} for service id {} and instructions {}", input.getDpnId() , input.getServiceId(), input.getInstruction());
         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
         int serviceId = input.getServiceId() ;
-        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+        List<MatchInfo> mkMatches = getTunnelMatchesForServiceId(serviceId);
         byte[] vxLANHeader = new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
         // Flags Byte
         byte Flags = (byte) 0x08;
@@ -205,9 +206,9 @@ public class ItmManagerRpcService implements ItmRpcService {
         vxLANHeader[6] = (byte) (serviceId >> 0);
 
         // Matching metadata
-        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
-                new BigInteger(1, vxLANHeader),
-                MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
+//        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
+//                new BigInteger(1, vxLANHeader),
+//                MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
 
         Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
                 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,serviceId), 5, String.format("%s:%d","ITM Flow Entry ",serviceId),
@@ -294,7 +295,7 @@ public class ItmManagerRpcService implements ItmRpcService {
         IpAddress dstIp = input.getDestinationIp() ;
         InstanceIdentifier<ExternalTunnel> path1 = InstanceIdentifier.create(
                 ExternalTunnelList.class)
-                .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(dstIp), srcDpn.toString()));
+                .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(dstIp), srcDpn.toString(), TunnelTypeMplsOverGre.class));
 
         Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker);
 
@@ -312,7 +313,7 @@ public class ItmManagerRpcService implements ItmRpcService {
                 if (dstIp.equals(firstEndPt.getIpAddress())) {
                     InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
                             TunnelList.class)
-                            .child(InternalTunnel.class, new InternalTunnelKey(teps.getDPNID(),srcDpn));
+                            .child(InternalTunnel.class, new InternalTunnelKey(teps.getDPNID(), srcDpn, input.getTunnelType()));
 
                     Optional<InternalTunnel>
                             tnl =
@@ -436,6 +437,10 @@ public class ItmManagerRpcService implements ItmRpcService {
                     }
                 });
             }
+            else {
+                result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build());
+                return result;
+            }
             return result;
         } catch (Exception e) {
             RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
@@ -444,4 +449,123 @@ public class ItmManagerRpcService implements ItmRpcService {
         }
     }
 
+    @Override
+    public Future<RpcResult<java.lang.Void>> addL2GwMlagDevice(AddL2GwMlagDeviceInput input)
+    {
+        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        try {
+            final IpAddress hwIp = input.getIpAddress();
+            final List<String> node_id = input.getNodeId();
+            InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
+            Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker);
+            if (tZonesOptional.isPresent()) {
+                TransportZones tZones = tZonesOptional.get();
+                if (tZones.getTransportZone() == null || tZones.getTransportZone().isEmpty()) {
+                    LOG.error("No teps configured");
+                    result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
+                    return result;
+                }
+                String transportZone = tZones.getTransportZone().get(0).getZoneName();
+                if (tZones.getTransportZone().get(0).getSubnets() == null || tZones.getTransportZone().get(0).getSubnets().isEmpty()) {
+                    result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
+                    return result;
+                }
+                SubnetsKey subnetsKey = tZones.getTransportZone().get(0).getSubnets().get(0).getKey();
+                DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, node_id.get(0));
+                InstanceIdentifier<DeviceVteps> path =
+                                InstanceIdentifier.builder(TransportZones.class)
+                                                .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                                .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build();
+                DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp).setNodeId(node_id.get(0)).setTopologyId(input.getTopologyId()).build();
+                WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+                LOG.trace("writing hWvtep{}",deviceVtep);
+                t.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true);
+                if(node_id.size() == 2) {
+                    LOG.trace("second node-id {}",node_id.get(1));
+                    DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, node_id.get(1));
+                    InstanceIdentifier<DeviceVteps> path2 = InstanceIdentifier.builder(TransportZones.class)
+                                    .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                    .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey2).build();
+                    DeviceVteps deviceVtep2 = new DeviceVtepsBuilder().setKey(deviceVtepKey2).setIpAddress(hwIp).setNodeId(node_id.get(1))
+                                    .setTopologyId(input.getTopologyId()).build();
+                    LOG.trace("writing {}",deviceVtep2);
+                    t.put(LogicalDatastoreType.CONFIGURATION, path2, deviceVtep2, true);
+                }ListenableFuture<Void> futureCheck = t.submit();
+                Futures.addCallback(futureCheck, new FutureCallback<Void>() {
+                    @Override
+                    public void onSuccess(Void aVoid) {
+                        result.set(RpcResultBuilder.<Void>success().build());
+                    }
+                    @Override
+                    public void onFailure(Throwable error) {
+                        String msg = String.format("Unable to write HwVtep {} to datastore", node_id);
+                        LOG.error("Unable to write HwVtep {}, {} to datastore", node_id , hwIp);
+                        result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
+                    }
+                });
+            }
+            return result;
+        } catch (Exception e) {
+            RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
+                            withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
+            return Futures.immediateFuture(resultBuilder.build());
+        }
+    }
+    @Override
+    public Future<RpcResult<Void>> deleteL2GwMlagDevice(DeleteL2GwMlagDeviceInput input) {
+        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        try {
+            final IpAddress hwIp = input.getIpAddress();
+            final List<String> node_id = input.getNodeId();
+            InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
+            Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker);
+            if (tZonesOptional.isPresent()) {
+                TransportZones tZones = tZonesOptional.get();
+                if (tZones.getTransportZone() == null || tZones.getTransportZone().isEmpty()) {
+                    LOG.error("No teps configured");
+                    result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
+                    return result;
+                }
+                String transportZone = tZones.getTransportZone().get(0).getZoneName();
+                if (tZones.getTransportZone().get(0).getSubnets() == null || tZones.getTransportZone().get(0).getSubnets().isEmpty()) {
+                    result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
+                    return result;
+                }
+                SubnetsKey subnetsKey = tZones.getTransportZone().get(0).getSubnets().get(0).getKey();
+                DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, node_id.get(0));
+                InstanceIdentifier<DeviceVteps> path =
+                                InstanceIdentifier.builder(TransportZones.class)
+                                                .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                                .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
+                                                deviceVtepKey).build();
+                WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+                t.delete(LogicalDatastoreType.CONFIGURATION, path);
+                DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, node_id.get(1));
+                InstanceIdentifier<DeviceVteps> path2 =
+                                InstanceIdentifier.builder(TransportZones.class)
+                                                .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                                .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
+                                                deviceVtepKey2).build();
+                t.delete(LogicalDatastoreType.CONFIGURATION, path2);
+                ListenableFuture<Void> futureCheck = t.submit();
+                Futures.addCallback(futureCheck, new FutureCallback<Void>() {
+                    @Override
+                    public void onSuccess(Void aVoid) {
+                        result.set(RpcResultBuilder.<Void>success().build());
+                    }
+                    @Override
+                    public void onFailure(Throwable error) {
+                        String msg = String.format("Unable to write HwVtep {} to datastore", node_id);
+                        LOG.error("Unable to write HwVtep {}, {} to datastore", node_id , hwIp);
+                        result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
+                    }
+                });
+            }
+            return result;
+        } catch (Exception e) {
+            RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
+                            withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e);
+            return Futures.immediateFuture(resultBuilder.build());
+        }
+    }
 }
index 03a4b87e17c11c815f880e4df4dbf4640b616cce..82138f42222f6cc4e0caabe8ee74a55ae054c9f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
index e1557af14163b975718a2fb4cc45a87639e62277..0f82d2e22a65fb32902043c6d03c5950dc191726 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * 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,
index 9ec91f52f603a1092adee63e7974cb35de2509a7..58ec462710b82db02fa33b9e88f293ba9eb10a56 100644 (file)
@@ -17,7 +17,7 @@ public class ItmModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.vpn
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-       ItmProvider provider = new ItmProvider();
+        ItmProvider provider = new ItmProvider();
         provider.setMdsalApiManager(getMdsalutilDependency());
         provider.setNotificationPublishService(getNotificationPublishServiceDependency());
         provider.setNotificationService(getNotificationServiceDependency());
diff --git a/itm/itm-impl/src/main/resources/OSGI-INF/blueprint/commands.xml b/itm/itm-impl/src/main/resources/OSGI-INF/blueprint/commands.xml
new file mode 100644 (file)
index 0000000..3da7337
--- /dev/null
@@ -0,0 +1,70 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+    <reference id="itmProviderRef" interface="org.opendaylight.vpnservice.itm.api.IITMProvider" availability="optional" />
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepAdd">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepDelete">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepShow">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepCommit">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepShowState">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepConfigureTunnelType">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepMonitor">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepDeleteDatastore">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaAdd">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaShow">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaUpdate">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaDelete">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+        <command>
+            <action class="org.opendaylight.vpnservice.itm.cli.TepEnableTunnelMonitor">
+                <property name="itmProvider" ref="itmProviderRef" />
+            </action>
+        </command>
+    </command-bundle>
+</blueprint>
\ No newline at end of file
index 311efac7983d77d16a22f8d6d79a478b4b832966..b73c4f580c9e578913b0d3a2c0ea93421de0d32f 100644 (file)
@@ -27,6 +27,18 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
 public class ClusteringUtils {
 
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+        if (dataStoreJobCoordinator == null) {
+            dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+        }
+        return dataStoreJobCoordinator;
+    }
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
             String entityType, String nodeId) {
         return checkNodeEntityOwner(entityOwnershipService, new Entity(entityType, nodeId),
@@ -42,10 +54,9 @@ public class ClusteringUtils {
     public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
             Entity entity, long sleepBetweenRetries, int maxRetries) {
         SettableFuture<Boolean> checkNodeEntityfuture = SettableFuture.create();
-        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
         CheckEntityOwnerTask checkEntityOwnerTask = new CheckEntityOwnerTask(entityOwnershipService, entity,
                 checkNodeEntityfuture, sleepBetweenRetries, maxRetries);
-        dataStoreCoordinator.enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
+        getDataStoreJobCoordinator().enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
         return checkNodeEntityfuture;
     }
 
diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java
new file mode 100644 (file)
index 0000000..3d2d870
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.utils.clustering;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.*;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.cache.CacheUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+public class EntityOwnerUtils {
+    public static final String ENTITY_OWNER_CACHE = "entity.owner.cache";
+    private static final Logger LOG = LoggerFactory.getLogger(EntityOwnerUtils.class);
+
+    static {
+        createEntityOwnerCache();
+    }
+    private static void createEntityOwnerCache() {
+        if (CacheUtil.getCache(ENTITY_OWNER_CACHE) == null) {
+            CacheUtil.createCache(ENTITY_OWNER_CACHE);
+        }
+    }
+
+    private static String getEntity(String entityType, String entityName) {
+        return entityType;
+    }
+
+    private static void updateEntityOwner(String entityType, String entityName, Boolean isOwner) {
+        ConcurrentMap<String, Boolean> entityOwnerCache =
+                (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+        String entity = getEntity(entityType, entityName);
+        if (entityOwnerCache != null) {
+            LOG.trace("updating entity owner "+isOwner+ " "+entity );
+            entityOwnerCache.put(entity, isOwner);
+        }
+    }
+
+    public static boolean amIEntityOwner(String entityType, String entityName) {
+        ConcurrentMap<String, Boolean> entityOwnerCache =
+                (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+        String entity = getEntity(entityType, entityName);
+        boolean ret = false;
+        if (entityOwnerCache != null) {
+            if (entityOwnerCache.get(entity) != null) {
+                ret = entityOwnerCache.get(entity);
+            }
+        } else {
+            LOG.error("entity owner cache null");
+        }
+        LOG.trace("get entity owner result {} for type {}" ,ret ,entity);
+        return ret;
+    }
+
+    /**
+     * Registers the entityName for ownership for given entityType
+     * adds a local listener which takes care of updating the cached entity status
+     * @param entityOwnershipService
+     * @param entityType
+     * @param entityName
+     * @param listener also adds this listener for ownership events if provided
+     * @throws CandidateAlreadyRegisteredException
+     */
+    public static void registerEntityCandidateForOwnerShip  (
+            EntityOwnershipService entityOwnershipService,
+            String entityType, String entityName, EntityOwnershipListener listener)
+            throws CandidateAlreadyRegisteredException {
+        LOG.info("registering for entity ownership for type "+entityType);
+        Entity candidateEntity = new Entity(entityType, entityName);
+        EntityOwnershipCandidateRegistration candidateRegistration = entityOwnershipService.registerCandidate(
+                candidateEntity);
+        EntityOwnershipListenerRegistration listenerRegistration = entityOwnershipService.registerListener(entityType,
+                entityOwnershipListener);
+        if (listener != null) {
+            entityOwnershipService.registerListener(entityType, listener);
+        }
+        LOG.info("registered for entity ownership for type "+entityType);
+        //TODO track registrations for closing
+    }
+
+    private static Listener entityOwnershipListener = new Listener();
+    static class Listener implements EntityOwnershipListener {
+
+        @Override
+        public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+            String entityType = ownershipChange.getEntity().getType();
+            String entityName = ownershipChange.getEntity().getId().toString();
+            LOG.info("entity ownership changed for "+entityType);
+            if (ownershipChange.hasOwner() && ownershipChange.isOwner()) {
+                LOG.info("entity ownership change became owner for type "+entityType);
+                updateEntityOwner(entityType, entityName, Boolean.TRUE);
+            } else {
+                LOG.info("entity ownership lost ownership for type "+entityType);
+                updateEntityOwner(entityType, entityName, Boolean.FALSE);
+            }
+        }
+    }
+}
\ No newline at end of file
index 33eecd9af84f8988c373eb1dccc07ed563f7ed25..ec4bc5c881fb5d322bf77689902f3384f04af1e5 100644 (file)
@@ -21,5 +21,7 @@ public class HwvtepSouthboundConstants {
     public static final Object PSWITCH_URI_PREFIX = "physicalswitch";
     public static final ImmutableBiMap<Class<? extends EncapsulationTypeBase>, String> ENCAPS_TYPE_MAP = new ImmutableBiMap.Builder<Class<? extends EncapsulationTypeBase>, String>()
             .put(EncapsulationTypeVxlanOverIpv4.class, "vxlan_over_ipv4").build();
-
+    public static final String ELAN_ENTITY_TYPE = "elan";
+    public static final String ELAN_ENTITY_NAME = "elan";
+    public static final String TEP_PREFIX = "vxlan_over_ipv4:";
 }
index c1dae6c417673aa25c052c77f0b3977ea11a4102..cdb26525ef0b108049936fd3dbe6be5f0cf49365 100644 (file)
@@ -82,6 +82,11 @@ public class HwvtepSouthboundUtils {
                 .child(Node.class, new NodeKey(nodeId));
     }
 
+
+    public static InstanceIdentifier<TerminationPoint> createTerminationPointId(NodeId nodeId,
+                                                                                TerminationPointKey tpKey) {
+        return createInstanceIdentifier(nodeId).child(TerminationPoint.class, tpKey);
+    }
     /**
      * Creates the logical switches instance identifier.
      *
@@ -374,4 +379,21 @@ public class HwvtepSouthboundUtils {
         return vbBuilder.build();
     }
 
+    public static TerminationPointKey getTerminationPointKey(String ipAddress) {
+        TerminationPointKey tpKey = null;
+        String tpKeyStr = getTerminationPointKeyString(ipAddress);
+        if(tpKeyStr != null) {
+            tpKey = new TerminationPointKey(new TpId(tpKeyStr));
+        }
+        return tpKey;
+    }
+    public static String getTerminationPointKeyString(String ipAddress) {
+        String tpKeyStr = null;
+        if(ipAddress != null) {
+            tpKeyStr = new StringBuilder(HwvtepSouthboundConstants.TEP_PREFIX).
+                    append(ipAddress).toString();
+        }
+        return tpKeyStr;
+    }
+
 }
index 64756366626aab8df3cc988559ff9d75819a8d12..f4d6b4473ea07cff04b01b02c251e692c66098c0 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.vpnservice.utils.hwvtep;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -16,6 +17,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 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.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
@@ -64,10 +66,17 @@ public final class HwvtepUtils {
     public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, NodeId nodeId,
             LogicalSwitches logicalSwitch) {
         WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        putLogicalSwitch(transaction, nodeId, logicalSwitch);
+        putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
         return transaction.submit();
     }
 
+    public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, LogicalDatastoreType logicalDatastoreType,
+                                                          NodeId nodeId,
+                                                          LogicalSwitches logicalSwitch) {
+        WriteTransaction transaction = broker.newWriteOnlyTransaction();
+        putLogicalSwitch(transaction,logicalDatastoreType, nodeId, logicalSwitch);
+        return transaction.submit();
+    }
     /**
      * Put the logical switches in the transaction.
      *
@@ -82,7 +91,7 @@ public final class HwvtepUtils {
             final List<LogicalSwitches> lstSwitches) {
         if (lstSwitches != null) {
             for (LogicalSwitches logicalSwitch : lstSwitches) {
-                putLogicalSwitch(transaction, nodeId, logicalSwitch);
+                putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
             }
         }
     }
@@ -97,11 +106,11 @@ public final class HwvtepUtils {
      * @param logicalSwitch
      *            the logical switch
      */
-    public static void putLogicalSwitch(final WriteTransaction transaction, final NodeId nodeId,
-            final LogicalSwitches logicalSwitch) {
+    public static void putLogicalSwitch(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+                                        final NodeId nodeId, final LogicalSwitches logicalSwitch) {
         InstanceIdentifier<LogicalSwitches> iid = HwvtepSouthboundUtils.createLogicalSwitchesInstanceIdentifier(nodeId,
                 logicalSwitch.getHwvtepNodeName());
-        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, logicalSwitch, true);
+        transaction.put(logicalDatastoreType, iid, logicalSwitch, true);
     }
 
     /**
@@ -430,6 +439,13 @@ public final class HwvtepUtils {
         transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteMcastMac, true);
     }
 
+    public static void putRemoteMcastMac(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+                                         final NodeId nodeId,
+                                         RemoteMcastMacs remoteMcastMac) {
+        InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
+                remoteMcastMac.getKey());
+        transaction.put(logicalDatastoreType, iid, remoteMcastMac, true);
+    }
     /**
      * Gets the remote mcast mac.
      *
@@ -605,4 +621,37 @@ public final class HwvtepUtils {
         }
         return null;
     }
+
+    /**
+     * Installs a list of Mac Addresses as remote Ucast address in an external
+     * device using the hwvtep-southbound.
+     *
+     * @param deviceNodeId
+     *            NodeId if the ExternalDevice where the macs must be installed
+     *            in.
+     * @param macAddresses
+     *            List of Mac addresses to be installed in the external device.
+     * @param logicalSwitchName
+     *            the logical switch name
+     * @param remoteVtepIp
+     *            VTEP's IP in this CSS used for the tunnel with external
+     *            device.
+     */
+    public static ListenableFuture<Void> installUcastMacs(DataBroker broker,
+                                                          String deviceNodeId, List<PhysAddress> macAddresses,
+                                                          String logicalSwitchName, IpAddress remoteVtepIp) {
+        NodeId nodeId = new NodeId(deviceNodeId);
+        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+                .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
+        List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
+        for (PhysAddress mac : macAddresses) {
+            // TODO: Query ARP cache to get IP address corresponding to
+            // the MAC
+            IpAddress ipAddress = null;
+            macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
+                    phyLocatorAug));
+        }
+        return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
+    }
+
 }
diff --git a/natservice/natservice-api/pom.xml b/natservice/natservice-api/pom.xml
new file mode 100644 (file)
index 0000000..5d8b0c8
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 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
+-->
+<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.vpnservice</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <relativePath>../../commons/config-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>natservice-api</artifactId>
+  <version>${vpnservices.version}</version>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>yang-binding</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+    </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>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-api</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/natservice/natservice-api/src/main/yang/odl-nat.yang b/natservice/natservice-api/src/main/yang/odl-nat.yang
new file mode 100644 (file)
index 0000000..1ff2228
--- /dev/null
@@ -0,0 +1,160 @@
+module odl-nat {
+    namespace "urn:opendaylight:vpnservice:natservice";
+    prefix odl-nat;
+
+    import ietf-yang-types { prefix "yang"; /*revision-date 2013-07-15; */}
+    import ietf-inet-types { prefix "inet"; }
+
+    revision "2016-01-11" {
+        description "NAT Manager module";
+    }
+
+    container external-networks {
+        list networks  {
+            key id;
+            leaf id {
+                type yang:uuid;
+            }
+            leaf vpnid { type yang:uuid; }
+            leaf-list router-ids { type yang:uuid; }
+        }
+   }
+
+   container ext-routers {
+       list routers {
+           key router-name;
+           leaf router-name { type string; }
+           leaf network-id { type yang:uuid; }
+           leaf enable-snat { type boolean; }
+           leaf-list external-ips {
+                type string; //format - ipaddress\prefixlength
+           }
+           leaf-list subnet-ids { type yang:uuid; }
+           leaf ext_gw_mac_address { type string; }
+       }
+   }
+
+
+    grouping external-interface-info {
+        leaf internal-ip { type string; }
+        leaf external-ip { type string; }
+        leaf label { type uint16; config false; }
+    }
+
+    container floating-ip-info {
+        config true;
+        list router-ports {
+            key router-id;
+            leaf router-id { type string; }
+            leaf external-network-id { type yang:uuid; }
+            list ports {
+                key port-name;
+                leaf port-name { type string; }
+                list ip-mapping {
+                    key "internal-ip";
+                    uses external-interface-info;
+                }
+            }
+        }
+    }
+
+    container napt-switches {
+        list router-to-napt-switch {
+            key router-name;
+            leaf router-name { type string; }
+            leaf primary-switch-id { type uint64; }
+        }
+    }
+
+    grouping ip-port-entity {
+        leaf ip-address { type string; }
+        leaf port-num { type uint16; }
+    }
+
+    typedef protocol-types {
+        type enumeration {
+              enum TCP;
+              enum UDP;
+        }
+    }
+
+    container intext-ip-port-map {
+        config true;
+        list ip-port-mapping {
+            key router-id;
+            leaf router-id { type uint32; }
+            list intext-ip-protocol-type {
+                key protocol;
+                leaf protocol { type protocol-types; }
+                list ip-port-map {
+                    key ip-port-internal;
+                    description "internal to external ip-port mapping";
+                    leaf ip-port-internal { type string; }
+                    container ip-port-external {
+                       uses ip-port-entity;
+                    }
+                }
+            }
+         }
+    }
+
+    container snatint-ip-port-map {
+        list intip-port-map {
+            key router-id;
+            leaf router-id { type uint32; }
+            list ip-port {
+                key internal-ip;
+                leaf internal-ip { type string; }
+                list int-ip-proto-type {
+                    key protocol;
+                    leaf protocol { type protocol-types; }
+                    leaf-list ports { type uint16; }
+                }
+            }
+        }
+    }
+
+     container intext-ip-map {
+         config false;
+         list ip-mapping {
+             key segment-id;
+             leaf segment-id { type uint32; }
+             list ip-map {
+                 key internal-ip;
+                 leaf internal-ip { type string; }
+                 leaf external-ip { type string; }
+                 leaf label {type uint32;}
+             }
+         }
+     }
+
+     container router-to-vpn-mapping {
+         list routermapping {
+             key router-name;
+             leaf router-name { type string; }
+             leaf vpn-id { type uint32; }
+             leaf vpn-name { type string; }
+         }
+     }
+
+     container router-id-name {
+       list routerIds {
+           key router-id;
+           leaf router-id {type uint32;}
+           leaf router-name { type string; }
+       }
+    }
+
+    container external-ips-counter {
+        config false;
+        list external-counters{
+            key segment-id;
+            leaf segment-id { type uint32; }
+            list external-ip-counter {
+                key external-ip;
+                leaf external-ip { type string; }
+                leaf counter { type uint8; }
+            }
+        }
+    }
+}
diff --git a/natservice/natservice-impl/pom.xml b/natservice/natservice-impl/pom.xml
new file mode 100644 (file)
index 0000000..d40b99b
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 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
+-->
+<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.vpnservice</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <relativePath>../../commons/config-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>natservice-impl</artifactId>
+  <version>${vpnservices.version}</version>
+  <packaging>bundle</packaging>
+  <properties>
+    <powermock.version>1.6.4</powermock.version>
+    <mockitoall.version>1.10.19</mockitoall.version>
+</properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>natservice-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>mdsalutil-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>itm-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>bgpmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>vpnmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>fibmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>idmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>neutronvpn-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-binding-broker-impl</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>commons-net</groupId>
+        <artifactId>commons-net</artifactId>
+    </dependency>
+  <!--  Only for unit-test -->
+   <dependency>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-all</artifactId>
+        <version>${mockitoall.version}</version>
+        <scope>test</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.powermock</groupId>
+        <artifactId>powermock-api-mockito</artifactId>
+        <version>${powermock.version}</version>
+        <scope>test</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.powermock</groupId>
+        <artifactId>powermock-module-junit4</artifactId>
+        <version>${powermock.version}</version>
+        <scope>test</scope>
+        </dependency>
+    </dependencies> 
+
+</project>
diff --git a/natservice/natservice-impl/src/main/config/default-config.xml b/natservice/natservice-impl/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..4f5f357
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright (c) 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
+-->
+<snapshot>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:natservice:impl?module=natservice-impl&amp;revision=2016-01-11</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:mdsalutil:api?module=odl-mdsalutil&amp;revision=2015-04-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:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&amp;revision=2013-10-28</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:bgpmanager:api?module=bgpmanager-api&amp;revision=2015-04-20</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:mdsalutil:api?module=odl-mdsalutil&amp;revision=2015-04-10</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:natservice:impl">prefix:natservice-impl</type>
+          <name>natservice-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>
+          <rpc-registry>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+            <name>binding-rpc-broker</name>
+          </rpc-registry>
+          <bgpmanager>
+            <type xmlns:bgpmanager="urn:opendaylight:params:xml:ns:yang:bgpmanager:api">bgpmanager:bgpmanager-api</type>
+            <name>bgpmanager</name>
+          </bgpmanager>
+          <notification-service>
+            <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
+            <name>binding-notification-adapter</name>
+          </notification-service>
+          <mdsalutil>
+            <type xmlns:mdsalutil="urn:opendaylight:params:xml:ns:yang:mdsalutil:api">mdsalutil:odl-mdsalutil</type>
+            <name>mdsalutil-service</name>
+          </mdsalutil>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/DpnInVpnListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/DpnInVpnListener.java
new file mode 100644 (file)
index 0000000..12eece8
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+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.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AddDpnEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.add.dpn.event.AddEventData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RemoveDpnEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.OdlL3vpnListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DpnInVpnListener implements OdlL3vpnListener {
+    private static final Logger LOG = LoggerFactory.getLogger(DpnInVpnListener.class);
+    private DataBroker dataBroker;
+    private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+    private NaptSwitchHA naptSwitchHA;
+    private IMdsalApiManager mdsalManager;
+    private IdManagerService idManager;
+
+    public DpnInVpnListener(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
+        this.defaultRouteProgrammer = defaultRouteProgrammer;
+    }
+
+    void setNaptSwitchHA(NaptSwitchHA switchHA) {
+        naptSwitchHA = switchHA;
+    }
+
+    void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    public void onAddDpnEvent(AddDpnEvent notification) {
+/*
+        AddEventData eventData =  notification.getAddEventData();
+        BigInteger dpnId = eventData.getDpnId();
+        String vpnName = eventData.getVpnName();
+        LOG.info("Received add dpn {} in vpn {} event", dpnId, vpnName);
+        String  routerId = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+        if (routerId != null) {
+            //check router is associated to external network
+            InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+            Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+            if (routerData.isPresent()) {
+                Uuid networkId = routerData.get().getNetworkId();
+                if(networkId != null) {
+                    LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+                    long vpnId = NatUtil.readVpnId(dataBroker, vpnName);
+                    if(vpnId != NatConstants.INVALID_ID) {
+                        //Install default entry in FIB to SNAT table
+                        LOG.debug("Installing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+                        defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
+                    } else {
+                        LOG.debug("Add DPN Event: Could not read vpnId for vpnName {}", vpnName);
+                    }
+                    if (routerData.get().isEnableSnat()) {
+                        LOG.info("SNAT enabled for router {}", routerId);
+                        handleSNATForDPN(dpnId, routerId);
+                    } else {
+                        LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
+                    }
+                }
+            }
+        }
+*/
+    }
+
+    void handleSNATForDPN(BigInteger dpnId, String routerName) {
+        //Check if primary and secondary switch are selected, If not select the role
+        //Install select group to NAPT switch
+        //Install default miss entry to NAPT switch
+/*
+        BigInteger naptSwitch;
+        try {
+            Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+            if (routerId == NatConstants.INVALID_ID) {
+                LOG.error("Invalid routerId returned for routerName {}",routerName);
+                return;
+            }
+            BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+            if (naptId == null || naptId.equals(BigInteger.ZERO)) {
+                LOG.debug("No Naptswitch is selected for router {}", routerName);
+
+                naptSwitch = dpnId;
+                boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
+                if(!naptstatus) {
+                    LOG.error("Failed to update newNaptSwitch {} for routername {}",naptSwitch,routerName);
+                    return;
+                }
+                LOG.debug("Switch {} is elected as NaptSwitch for router {}",dpnId,routerName);
+
+                //installing group
+                List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInPrimarySwitch();
+                naptSwitchHA.installSnatGroupEntry(naptSwitch,bucketInfo,routerName);
+
+                naptSwitchHA.installSnatFlows(routerName,routerId,naptSwitch);
+
+            }  else {
+                LOG.debug("Napt switch with Id {} is already elected for router {}",naptId, routerName);
+                naptSwitch = naptId;
+
+                //installing group
+                List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
+                if (bucketInfo == null) {
+                    LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}",dpnId,routerName,
+                            naptSwitch);
+                    return;
+                }
+                naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
+            }
+            // Install miss entry (table 26) pointing to group
+            long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+            FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,NatConstants.ADD_FLOW);
+            if (flowEntity == null) {
+                LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}",routerName,dpnId,groupId);
+                return;
+            }
+            LOG.debug("Successfully installed flow for dpnId {} router {} group {}",dpnId,routerName,groupId);
+            mdsalManager.installFlow(flowEntity);
+        } catch (Exception ex) {
+            LOG.error("Exception in handleSNATForDPN method : {}",ex);
+        }
+*/
+    }
+
+    public void onRemoveDpnEvent(RemoveDpnEvent notification) {
+/*
+        RemoveEventData eventData = notification.getRemoveEventData();
+        BigInteger dpnId = eventData.getDpnId();
+        String vpnName = eventData.getVpnName();
+        LOG.info("Received remove dpn {} in vpn {} event", dpnId, vpnName);
+        String  routerId = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+        if (routerId != null) {
+            //check router is associated to external network
+            InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+            Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+            if (routerData.isPresent()) {
+                Uuid networkId = routerData.get().getNetworkId();
+                if(networkId != null) {
+                    LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+                    long vpnId = NatUtil.readVpnId(dataBroker, vpnName);
+                    if(vpnId != NatConstants.INVALID_ID) {
+                        //Remove default entry in FIB
+                        LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+                        defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
+                    } else {
+                        LOG.debug("Remove DPN Event: Could not read vpnId for vpnName {}", vpnName);
+                    }
+                    if (routerData.get().isEnableSnat()) {
+                        LOG.info("SNAT enabled for router {}", routerId);
+                        removeSNATFromDPN(dpnId,routerId);
+                    } else {
+                        LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
+                    }
+                }
+            }
+        }
+*/
+    }
+
+    /*void removeSNATFromDPN(BigInteger dpnId, String routerName) {
+        //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
+        //remove miss entry to NAPT switch
+        //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
+
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}",routerName);
+            return;
+        }
+        BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+        if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+            LOG.debug("No naptSwitch is selected for router {}", routerName);
+            return;
+        }
+        try {
+            boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch);
+            if (!naptStatus) {
+                LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+                        dpnId, routerName);
+            } else {
+                naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
+            }
+        } catch (Exception ex) {
+            LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);
+        }
+
+        long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+        FlowEntity flowEntity = null;
+        try {
+            flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, NatConstants.DEL_FLOW);
+            if (flowEntity == null) {
+                LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
+                return;
+            }
+            LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
+            mdsalManager.removeFlow(flowEntity);
+
+        } catch (Exception ex) {
+            LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
+            return;
+        }
+        LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
+
+        //remove group
+        GroupEntity groupEntity = null;
+        try {
+            groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+                    GroupTypes.GroupAll, null);
+            LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
+            mdsalManager.removeGroup(groupEntity);
+        } catch (Exception ex) {
+            LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
+            return;
+        }
+        LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
+    }*/
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/EventDispatcher.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/EventDispatcher.java
new file mode 100644 (file)
index 0000000..d0aad9a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.util.concurrent.BlockingQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EventDispatcher implements Runnable {
+    private BlockingQueue<NAPTEntryEvent> eventQueue;
+    private NaptEventHandler naptEventHandler;
+    private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
+
+    EventDispatcher(BlockingQueue<NAPTEntryEvent> eventQueue, NaptEventHandler naptEventHandler){
+        this.eventQueue = eventQueue;
+        this.naptEventHandler = naptEventHandler;
+    }
+
+    public void addNaptEvent(NAPTEntryEvent naptEntryEvent){
+        this.eventQueue.add(naptEntryEvent);
+    }
+
+    public void run(){
+        while(true) {
+            try {
+                NAPTEntryEvent event = eventQueue.take();
+                naptEventHandler.handleEvent(event);
+            } catch (InterruptedException e) {
+                LOG.error("EventDispatcher : Error in handling the event queue : ", e.getMessage());
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworkListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworkListener.java
new file mode 100644 (file)
index 0000000..621aea2
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import com.google.common.base.Optional;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.ArrayList;
+
+
+public class ExternalNetworkListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<Networks> implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworkListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker broker;
+    private IMdsalApiManager mdsalManager;
+
+    public ExternalNetworkListener (final DataBroker db) {
+        super(Networks.class);
+        broker = db;
+        //registerListener(db);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("ExternalNetwork Listener Closed");
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), ExternalNetworkListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("External Network DataChange listener registration fail!", e);
+            throw new IllegalStateException("External Network registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Networks> getWildCardPath() {
+        return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    @Override
+    protected void add(final InstanceIdentifier<Networks> identifier,
+                       final Networks nw) {
+        LOG.trace("External Network add mapping method - key: " + identifier + ", value=" + nw );
+        processExternalNwAdd(identifier, nw);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Networks> identifier, Networks nw) {
+        LOG.trace("External Network remove mapping method - key: " + identifier + ", value=" + nw );
+        processExternalNwDel(identifier, nw);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
+        LOG.trace("External Network update mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
+        //check if a new router has been added or an already existing router has been deleted from the external nw to router association
+        List<Uuid> oldRtrs = original.getRouterIds();
+        List<Uuid> newRtrs = update.getRouterIds();
+        if (oldRtrs != newRtrs) {
+            //handle both addition and removal of routers
+            for (Uuid rtr : newRtrs) {
+                if (oldRtrs.contains(rtr)) {
+                    oldRtrs.remove(rtr);
+                } else {
+                    // new router case
+                    //Routers added need to have the corresponding default Fib entry added to the switches in the router
+                    String routerId = rtr.getValue();
+                    addOrDelDefFibRouteToSNAT(routerId, true);
+
+                }
+            }
+
+            //Routers removed need to have the corresponding default Fib entry removed from the switches in the router
+            for (Uuid rtr : oldRtrs) {
+                String routerId = rtr.getValue();
+                addOrDelDefFibRouteToSNAT(routerId, false);
+            }
+        }
+    }
+
+    private void processExternalNwAdd(final InstanceIdentifier<Networks> identifier,
+                                      final Networks network) {
+        LOG.trace("Add event - key: {}, value: {}", identifier, network);
+        List<Uuid> routerList = network.getRouterIds();
+
+        if(routerList == null) {
+            LOG.debug("No routers associated with external network {}", identifier);
+            return;
+        }
+
+        for(Uuid router: routerList) {
+            String routerId = router.getValue();
+            addOrDelDefFibRouteToSNAT(routerId, true);
+        }
+    }
+
+    private void processExternalNwDel(final InstanceIdentifier<Networks> identifier,
+                                      final Networks network) {
+        LOG.trace("Add event - key: {}, value: {}", identifier, network);
+        List<Uuid> routerList = network.getRouterIds();
+
+        for(Uuid router: routerList) {
+            String routerId = router.getValue();
+            addOrDelDefFibRouteToSNAT(routerId, false);
+        }
+    }
+
+    private void addOrDelDefFibRouteToSNAT(String routerId, boolean create) {
+        //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerId);
+        Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (vpnInstOp.isPresent()) {
+            List<VpnToDpnList> dpnListInVpn = vpnInstOp.get().getVpnToDpnList();
+            for (VpnToDpnList dpn : dpnListInVpn) {
+                BigInteger dpnId = dpn.getDpnId();
+                long vpnId = NatUtil.readVpnId(broker, vpnInstOp.get().getVrfId());
+                if (create == true) {
+                    installDefNATRouteInDPN(dpnId, vpnId);
+                } else {
+                    removeDefNATRouteInDPN(dpnId, vpnId);
+                }
+            }
+        }
+    }
+
+    private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
+
+        InetAddress defaultIP = null;
+
+        try {
+            defaultIP = InetAddress.getByName("0.0.0.0");
+
+        } catch (UnknownHostException e) {
+            LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed  to build FIB Table Flow for Default Route to NAT table ");
+            return null;
+        }
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        //add match for default route "0.0.0.0/0"
+        //matches.add(new MatchInfo(MatchFieldType.ipv4_src, new long[] {
+        //        NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
+
+        //add match for vrfid
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.L3_FIB_TABLE, defaultIP);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+
+
+    }
+
+    private void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+        FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+        if(flowEntity == null) {
+            LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+            return;
+        }
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    private void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+        FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+        if(flowEntity == null) {
+            LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+            return;
+        }
+        mdsalManager.removeFlow(flowEntity);
+    }
+
+
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworksChangeListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalNetworksChangeListener.java
new file mode 100644 (file)
index 0000000..8f84796
--- /dev/null
@@ -0,0 +1,332 @@
+/*\r
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
+package org.opendaylight.vpnservice.natservice.internal;\r
+\r
+import com.google.common.base.Optional;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;\r
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;\r
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;\r
+import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;\r
+import org.opendaylight.yangtools.yang.common.RpcResult;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import java.math.BigInteger;\r
+import java.util.List;\r
+import java.util.concurrent.ExecutionException;\r
+import java.util.concurrent.Future;\r
+\r
+import org.opendaylight.bgpmanager.api.IBgpManager;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;\r
+\r
+/**\r
+ * Created by ESUMAMS on 1/21/2016.\r
+ */\r
+public class ExternalNetworksChangeListener extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener>\r
+{\r
+    private static final Logger LOG = LoggerFactory.getLogger( ExternalNetworksChangeListener.class);\r
+\r
+    private ListenerRegistration<DataChangeListener> listenerRegistration;\r
+    private final DataBroker dataBroker;\r
+    private IMdsalApiManager mdsalManager;\r
+    //private VpnFloatingIpHandler vpnFloatingIpHandler;\r
+    private FloatingIPListener floatingIpListener;\r
+    private ExternalRoutersListener externalRouterListener;\r
+    private OdlInterfaceRpcService interfaceManager;\r
+    private NaptManager naptManager;\r
+\r
+    private IBgpManager bgpManager;\r
+    private VpnRpcService vpnService;\r
+    private FibRpcService fibService;\r
+\r
+\r
+    private ExternalRoutersListener externalRoutersListener;\r
+\r
+    void setMdsalManager(IMdsalApiManager mdsalManager) {\r
+        this.mdsalManager = mdsalManager;\r
+    }\r
+\r
+    void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {\r
+        this.interfaceManager = interfaceManager;\r
+    }\r
+\r
+    void setFloatingIpListener(FloatingIPListener floatingIpListener) {\r
+        this.floatingIpListener = floatingIpListener;\r
+    }\r
+\r
+    void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {\r
+        this.externalRouterListener = externalRoutersListener;\r
+    }\r
+\r
+    public void setBgpManager(IBgpManager bgpManager) {\r
+        this.bgpManager = bgpManager;\r
+    }\r
+\r
+    public void setNaptManager(NaptManager naptManager) {\r
+        this.naptManager = naptManager;\r
+    }\r
+\r
+    public void setVpnService(VpnRpcService vpnService) {\r
+        this.vpnService = vpnService;\r
+    }\r
+\r
+    public void setFibService(FibRpcService fibService) {\r
+        this.fibService = fibService;\r
+    }\r
+\r
+    public void setListenerRegistration(ListenerRegistration<DataChangeListener> listenerRegistration) {\r
+        this.listenerRegistration = listenerRegistration;\r
+    }\r
+\r
+    public ExternalNetworksChangeListener(final DataBroker dataBroker ) {\r
+        super( Networks.class, ExternalNetworksChangeListener.class );\r
+        this.dataBroker = dataBroker;\r
+    }\r
+\r
+\r
+    protected InstanceIdentifier<Networks> getWildCardPath() {\r
+        return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);\r
+    }\r
+\r
+\r
+    @Override\r
+    protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {\r
+\r
+    }\r
+\r
+    @Override\r
+    protected ExternalNetworksChangeListener getDataTreeChangeListener() {\r
+        return ExternalNetworksChangeListener.this;\r
+    }\r
+\r
+    @Override\r
+    protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {\r
+        if( identifier == null || networks == null || networks.getRouterIds().isEmpty() ) {\r
+            LOG.info( "ExternalNetworksChangeListener:remove:: returning without processing since networks/identifier is null"  );\r
+            return;\r
+        }\r
+\r
+        for( Uuid routerId: networks.getRouterIds() ) {\r
+            String routerName = routerId.toString();\r
+\r
+            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =\r
+                    getRouterToNaptSwitchInstanceIdentifier( routerName);\r
+\r
+            MDSALUtil.syncDelete( dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier );\r
+\r
+            LOG.debug( "ExternalNetworksChangeListener:delete:: successful deletion of data in napt-switches container" );\r
+        }\r
+    }\r
+\r
+    private static InstanceIdentifier<RouterToNaptSwitch> getRouterToNaptSwitchInstanceIdentifier( String routerName ) {\r
+\r
+        return  InstanceIdentifier.builder( NaptSwitches.class )\r
+                        .child( RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();\r
+\r
+    }\r
+\r
+    public void close() throws Exception {\r
+        if (listenerRegistration != null) {\r
+            try {\r
+                listenerRegistration.close();\r
+            }\r
+            catch (final Exception e) {\r
+                LOG.error("Error when cleaning up ExternalNetworksChangeListener.", e);\r
+            }\r
+\r
+            listenerRegistration = null;\r
+        }\r
+        LOG.debug("ExternalNetworksChangeListener Closed");\r
+    }\r
+\r
+\r
+    @Override\r
+    protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {\r
+        //Check for VPN disassociation\r
+        Uuid originalVpn = original.getVpnid();\r
+        Uuid updatedVpn = update.getVpnid();\r
+        if(originalVpn == null && updatedVpn != null) {\r
+            //external network is dis-associated from L3VPN instance\r
+            associateExternalNetworkWithVPN(update);\r
+        } else if(originalVpn != null && updatedVpn == null) {\r
+            //external network is associated with vpn\r
+            disassociateExternalNetworkFromVPN(update, originalVpn.getValue());\r
+            //Remove the SNAT entries\r
+            removeSnatEntries(original, original.getId());\r
+        }\r
+    }\r
+\r
+    private void removeSnatEntries(Networks original, Uuid networkUuid) {\r
+        List<Uuid> routerUuids = original.getRouterIds();\r
+        for (Uuid routerUuid : routerUuids) {\r
+            Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());\r
+            if (routerId == NatConstants.INVALID_ID) {\r
+                LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerUuid.getValue());\r
+                return;\r
+            }\r
+            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);\r
+            externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), networkUuid, externalIps, false, original.getVpnid().getValue());\r
+        }\r
+    }\r
+\r
+    private void associateExternalNetworkWithVPN(Networks network) {\r
+        List<Uuid> routerIds = network.getRouterIds();\r
+        for(Uuid routerId : routerIds) {\r
+            //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
+\r
+            InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
+            Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
+            if(!optRouterPorts.isPresent()) {\r
+                LOG.debug("Could not read Router Ports data object with id: {} to handle associate ext nw {}", routerId, network.getId());\r
+                continue;\r
+            }\r
+            RouterPorts routerPorts = optRouterPorts.get();\r
+            List<Ports> interfaces = routerPorts.getPorts();\r
+            for(Ports port : interfaces) {\r
+                String portName = port.getPortName();\r
+                BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
+                if(dpnId.equals(BigInteger.ZERO)) {\r
+                    LOG.debug("DPN not found for {}, skip handling of ext nw {} association", portName, network.getId());\r
+                    continue;\r
+                }\r
+                List<IpMapping> ipMapping = port.getIpMapping();\r
+                for(IpMapping ipMap : ipMapping) {\r
+                    String externalIp = ipMap.getExternalIp();\r
+                    //remove all VPN related entries\r
+                    floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
+                }\r
+            }\r
+        }\r
+\r
+        // SNAT\r
+        for(Uuid routerId : routerIds) {\r
+            LOG.debug("NAT Service : associateExternalNetworkWithVPN() for routerId {}",  routerId);\r
+            Uuid networkId = network.getId();\r
+            if(networkId == null) {\r
+                LOG.error("NAT Service : networkId is null for the router ID {}", routerId);\r
+                return;\r
+            }\r
+            final String vpnName = network.getVpnid().getValue();\r
+            if(vpnName == null) {\r
+                LOG.error("NAT Service : No VPN associated with ext nw {} for router {}", networkId, routerId);\r
+                return;\r
+            }\r
+\r
+            BigInteger dpnId = new BigInteger("0");\r
+            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());\r
+            Optional<RouterToNaptSwitch> rtrToNapt = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch );\r
+            if(rtrToNapt.isPresent()) {\r
+                dpnId = rtrToNapt.get().getPrimarySwitchId();\r
+            }\r
+            LOG.debug("NAT Service : got primarySwitch as dpnId{} ", dpnId);\r
+\r
+            Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
+            InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> idBuilder =\r
+                            InstanceIdentifier.builder(IntextIpMap.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey(routerIdentifier));\r
+            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> id = idBuilder.build();\r
+            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);\r
+            if (ipMapping.isPresent()) {\r
+                  List<IpMap> ipMaps = ipMapping.get().getIpMap();\r
+                  for (IpMap ipMap : ipMaps) {\r
+                      String externalIp = ipMap.getExternalIp();\r
+                      LOG.debug("NAT Service : got externalIp as {}", externalIp);\r
+                      LOG.debug("NAT Service : About to call advToBgpAndInstallFibAndTsFlows for dpnId {}, vpnName {} and externalIp {}", dpnId, vpnName, externalIp);\r
+                      externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, NatUtil.getVpnId(dataBroker, routerId.getValue()), externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);\r
+                  }\r
+            } else {\r
+                LOG.warn("NAT Service : No ipMapping present fot the routerId {}", routerId);\r
+            }\r
+\r
+            long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
+            // Install 47 entry to point to 21\r
+            if(vpnId != -1) {\r
+                LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for donId {} and vpnId {}", dpnId, vpnId);\r
+                externalRouterListener.installNaptPfibEntry(dpnId, vpnId);\r
+            }\r
+\r
+        }\r
+\r
+    }\r
+\r
+    private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {\r
+        List<Uuid> routerIds = network.getRouterIds();\r
+\r
+        //long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
+        for(Uuid routerId : routerIds) {\r
+            //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
+\r
+            InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
+            Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
+            if(!optRouterPorts.isPresent()) {\r
+                LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate ext nw {}", routerId, network.getId());\r
+                continue;\r
+            }\r
+            RouterPorts routerPorts = optRouterPorts.get();\r
+            List<Ports> interfaces = routerPorts.getPorts();\r
+            for(Ports port : interfaces) {\r
+                String portName = port.getPortName();\r
+                BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
+                if(dpnId.equals(BigInteger.ZERO)) {\r
+                    LOG.debug("DPN not found for {}, skip handling of ext nw {} disassociation", portName, network.getId());\r
+                    continue;\r
+                }\r
+                List<IpMapping> ipMapping = port.getIpMapping();\r
+                for(IpMapping ipMap : ipMapping) {\r
+                    String externalIp = ipMap.getExternalIp();\r
+                    floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {\r
+        BigInteger nodeId = BigInteger.ZERO;\r
+        try {\r
+            GetDpidFromInterfaceInput\r
+                    dpIdInput =\r
+                    new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();\r
+            Future<RpcResult<GetDpidFromInterfaceOutput>>\r
+                    dpIdOutput =\r
+                    interfaceManagerRpcService.getDpidFromInterface(dpIdInput);\r
+            RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();\r
+            if (dpIdResult.isSuccessful()) {\r
+                nodeId = dpIdResult.getResult().getDpid();\r
+            } else {\r
+                LOG.error("Could not retrieve DPN Id for interface {}", ifName);\r
+            }\r
+        } catch (InterruptedException | ExecutionException e) {\r
+            LOG.error("Exception when getting dpn for interface {}", ifName,  e);\r
+        }\r
+        return nodeId;\r
+    }\r
+\r
+}\r
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalRoutersListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/ExternalRoutersListener.java
new file mode 100644 (file)
index 0000000..87b9ee6
--- /dev/null
@@ -0,0 +1,2027 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ProtocolTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+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.action.types.rev131112.action.action.OutputActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExtRouters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.RouterIdName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+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.base.Optional;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import com.google.common.util.concurrent.AsyncFunction;
+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;
+
+/**
+ * Created by EYUGSAR on 2/20/2016.
+ */
+
+public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener>{
+
+    private static final Logger LOG = LoggerFactory.getLogger( ExternalRoutersListener.class);
+    private static long label;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker dataBroker;
+    private IMdsalApiManager mdsalManager;
+    private ItmRpcService itmManager;
+    private OdlInterfaceRpcService interfaceManager;
+    private IdManagerService idManager;
+    private NaptManager naptManager;
+    private NAPTSwitchSelector naptSwitchSelector;
+    private IBgpManager bgpManager;
+    private VpnRpcService vpnService;
+    private FibRpcService fibService;
+    private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+    private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+    static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
+    private NaptEventHandler naptEventHandler;
+    private NaptPacketInHandler naptPacketInHandler;
+
+    public void setNaptEventHandler(NaptEventHandler naptEventHandler) {
+        this.naptEventHandler = naptEventHandler;
+    }
+
+    public void setNaptPacketInHandler(NaptPacketInHandler naptPacketInHandler) {
+        this.naptPacketInHandler = naptPacketInHandler;
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setItmManager(ItmRpcService itmManager) {
+        this.itmManager = itmManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+        createGroupIdPool();
+    }
+
+    void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
+        this.defaultRouteProgrammer = defaultRouteProgrammer;
+    }
+
+
+    public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+        this.interfaceManager = interfaceManager;
+    }
+
+    public void setNaptManager(NaptManager naptManager) {
+        this.naptManager = naptManager;
+    }
+
+    public void setNaptSwitchSelector(NAPTSwitchSelector naptSwitchSelector) {
+        this.naptSwitchSelector = naptSwitchSelector;
+    }
+
+    public void setBgpManager(IBgpManager bgpManager) {
+        this.bgpManager = bgpManager;
+    }
+
+    public void setVpnService(VpnRpcService vpnService) {
+        this.vpnService = vpnService;
+    }
+
+    public void setFibService(FibRpcService fibService) {
+        this.fibService = fibService;
+    }
+
+    public ExternalRoutersListener(DataBroker dataBroker )
+    {
+        super( Routers.class, ExternalRoutersListener.class );
+        this.dataBroker = dataBroker;
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
+
+        LOG.info( "NAT Service : Add external router event for {}", routers.getRouterName() );
+
+        LOG.info("Installing NAT default route on all dpns part of router {}", routers.getRouterName());
+        addOrDelDefFibRouteToSNAT(routers.getRouterName(), true);
+
+        if( !routers.isEnableSnat()) {
+            LOG.info( "SNAT is disabled for external router {} ", routers.getRouterName());
+            return;
+        }
+
+        // Populate the router-id-name container
+        String routerName = routers.getRouterName();
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(routerId)).setRouterId(routerId).setRouterName(routerName).build();
+        MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(routerId), rtrs);
+
+        handleEnableSnat(routers);
+    }
+
+    public void handleEnableSnat(Routers routers){
+        String routerName = routers.getRouterName();
+        LOG.info("NAT Service : Handling SNAT for router {}", routerName);
+
+        long segmentId = NatUtil.getVpnId(dataBroker, routerName);
+        naptManager.initialiseExternalCounter(routers, segmentId);
+
+        // Allocate Primary Napt Switch for this router
+        BigInteger primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+        LOG.debug("NAT Service : Primary NAPT switch DPN ID {}", primarySwitchId);
+        if(primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)){
+            LOG.error("NAT Service : Unable to to select the primary NAPT switch");
+        }
+        LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}", primarySwitchId, routerName);
+
+        long bgpVpnId = NatConstants.INVALID_ID;
+        Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+        if(bgpVpnUuid != null){
+            bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+        }
+        if(bgpVpnId != NatConstants.INVALID_ID){
+
+            String bgpVpnName = bgpVpnUuid.getValue();
+            LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
+            RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
+            MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
+
+            long groupId = 0;
+            long routerId = NatUtil.getVpnId(dataBroker, routerName);
+            List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+            if(switches == null){
+                LOG.error("NAT Service : No DPNS associated for the router {}", routerName);
+                return;
+            }
+            for (BigInteger dpnId : switches) {
+                // Handle switches and NAPT switches separately
+                if (!dpnId.equals(primarySwitchId)) {
+                    LOG.debug("NAT Service : Install group in Ordinary switch {}", dpnId);
+                    List<BucketInfo> bucketInfoForNonNaptSwitches = getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
+                    groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
+                }else{
+                    LOG.debug("NAT Service : Install group in Primary switch {}", dpnId);
+                    List<BucketInfo> bucketInfoForNaptSwitches = getBucketInfoForPrimaryNaptSwitch();
+                    groupId = installGroup(dpnId, routerName, bucketInfoForNaptSwitches);
+
+                    Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
+                    //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+                    if(vpnId != null && vpnId != NatConstants.INVALID_ID) {
+                        installNaptPfibEntry(dpnId, vpnId);
+                    }
+
+                }
+                installFlowsWithUpdatedVpnId(primarySwitchId, routerName, groupId, bgpVpnId, routerId);
+            }
+        }else {
+            // write metadata and punt
+            installOutboundMissEntry(routerName, primarySwitchId);
+            // Now install entries in SNAT tables to point to Primary for each router
+            List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+            for (BigInteger dpnId : switches) {
+                // Handle switches and NAPT switches separately
+                if (!dpnId.equals(primarySwitchId)) {
+                    LOG.debug("NAT Service : Handle Ordinary switch");
+                    handleSwitches(dpnId, routerName, primarySwitchId);
+                } else {
+                    LOG.debug("NAT Service : Handle NAPT switch");
+                    handlePrimaryNaptSwitch(dpnId, routerName, primarySwitchId);
+                }
+            }
+        }
+
+        // call registerMapping Api
+        LOG.debug("NAT Service : Preparing to call registerMapping for routerName {} and Id {}", routerName, segmentId);
+
+        List<Uuid> subnetList = null;
+        List<String> externalIps = null;
+
+        InstanceIdentifier<Routers> id = InstanceIdentifier
+                .builder(ExtRouters.class)
+                .child(Routers.class, new RoutersKey(routerName))
+                .build();
+
+        Optional<Routers> extRouters = read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+
+        if(extRouters.isPresent())
+        {
+            LOG.debug("NAT Service : Fetching values from extRouters model");
+            Routers routerEntry= extRouters.get();
+            subnetList = routerEntry.getSubnetIds();
+            externalIps = routerEntry.getExternalIps();
+            int counter = 0;
+            int extIpCounter = externalIps.size();
+            LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
+            for(Uuid subnet : subnetList) {
+                  LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
+                  InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
+                         .builder(Subnetmaps.class)
+                         .child(Subnetmap.class, new SubnetmapKey(subnet))
+                         .build();
+                  Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
+                  if(sn.isPresent()){
+                      // subnets
+                      Subnetmap subnetmapEntry = sn.get();
+                      String subnetString = subnetmapEntry.getSubnetIp();
+                      String[] subnetSplit = subnetString.split("/");
+                      String subnetIp = subnetSplit[0];
+                      String subnetPrefix = "0";
+                      if(subnetSplit.length ==  2) {
+                          subnetPrefix = subnetSplit[1];
+                      }
+                      IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
+                      LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}", subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
+                      //externalIps
+                      LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
+                      if(extIpCounter != 0) {
+                            if(counter < extIpCounter) {
+                                   String[] IpSplit = externalIps.get(counter).split("/");
+                                   String externalIp = IpSplit[0];
+                                   String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
+                                   if(IpSplit.length==2) {
+                                       extPrefix = IpSplit[1];
+                                   }
+                                   IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
+                                   LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
+                                   naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
+                                   LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
+                                            externalIp, extPrefix);
+
+                                   String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
+                                   LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
+                                   handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
+
+                            } else {
+                                   counter = 0;    //Reset the counter which runs on externalIps for round-robbin effect
+                                   LOG.debug("NAT Service : Counter on externalIps got reset");
+                                   String[] IpSplit = externalIps.get(counter).split("/");
+                                   String externalIp = IpSplit[0];
+                                   String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
+                                   if(IpSplit.length==2) {
+                                       extPrefix = IpSplit[1];
+                                   }
+                                   IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
+                                   LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
+                                   naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
+                                   LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
+                                            externalIp, extPrefix);
+
+                                   String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
+                                   LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
+                                   handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
+
+                            }
+                      }
+                      counter++;
+                      LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
+
+                  } else {
+                      LOG.warn("NAT Service : No internal subnets present in extRouters Model");
+                  }
+            }
+        }
+
+        LOG.info("NAT Service : handleEnableSnat() Exit");
+    }
+
+    private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
+        //Check if BGP VPN exists. If exists then invoke the new method.
+        long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
+        if(bgpVpnId != NatConstants.INVALID_ID) {
+            addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, create);
+            return;
+        }
+
+        //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
+        addOrDelDefaultFibRouteForSNAT(routerName, create);
+/*        InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerName);
+        Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        if (vpnInstOp.isPresent()) {
+            addOrDelDefaultFibRouteForSNAT(routerName, create);
+        } *//*else {
+            //Check if this router is associated with any external VPN
+            LOG.debug("Checking if router {} is associated with BGP VPN", routerName);
+            Uuid vpnId = NatUtil.getVpnForRouter(dataBroker, routerName);
+            if(vpnId != null) {
+                String vpnName = vpnId.getValue();
+                LOG.debug("Router {} is associated with VPN {}", routerName, vpnName);
+                InstanceIdentifier<VpnInstanceOpDataEntry> vid = NatUtil.getVpnInstanceOpDataIdentifier(vpnName);
+                vpnInstOp = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, vid);
+                if (vpnInstOp.isPresent()) {
+                    addOrDelDefaultFibRouteForSNAT(routerName, vpnInstOp.get(), create);
+                }
+            }
+        }*/
+    }
+
+    private void addOrDelDefaultFibRouteForSNAT(String routerName, boolean create) {
+/*
+        List<VpnToDpnList> dpnListInVpn = vpnInstOp.getVpnToDpnList();
+        List<BigInteger> switches = new ArrayList<>();
+        if(dpnListInVpn == null || dpnListInVpn.isEmpty()) {
+            LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
+            switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+            if(switches == null || switches.isEmpty()){
+                LOG.error("NAT Service : addOrDelDefaultFibRouteForSNAT : NO SWITCHES ARE PART OF ROUTER {}", routerName);
+                return;
+            }
+        }else{
+            for (VpnToDpnList dpn : dpnListInVpn) {
+                switches.add(dpn.getDpnId());
+            }
+        }
+*/
+        List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+        long routerId = NatUtil.readVpnId(dataBroker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
+            return;
+        }
+        for (BigInteger dpnId : switches) {
+            if (create == true) {
+                defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
+            } else {
+                defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
+            }
+        }
+    }
+
+    private void addOrDelDefaultFibRouteForSNATWIthBgpVpn(String routerName, long bgpVpnId, boolean create) {
+        List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
+        if(dpnIds == null || dpnIds.isEmpty()) {
+            LOG.debug("NAT Service : Current no dpns part of router {} to program default NAT route", routerName);
+            return;
+        }
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        for (BigInteger dpnId : dpnIds) {
+            if (create == true) {
+                if(bgpVpnId != NatConstants.INVALID_ID) {
+                    defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
+                }else{
+                    defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
+                }
+            } else {
+                if(bgpVpnId != NatConstants.INVALID_ID) {
+                    defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
+                }else{
+                    defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
+                }
+            }
+        }
+    }
+
+    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
+    {
+        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+        Optional<T> result = Optional.absent();
+        try
+        {
+            result = tx.read(datastoreType, path).get();
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+
+        return result;
+    }
+
+    public void close() throws Exception
+    {
+        if (listenerRegistration != null)
+        {
+            try
+            {
+                listenerRegistration.close();
+            }
+            catch (final Exception e)
+            {
+                LOG.error("Error when cleaning up ExternalRoutersListener.", e);
+            }
+
+            listenerRegistration = null;
+        }
+        LOG.debug("ExternalRoutersListener Closed");
+    }
+
+    protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
+        if(routerId != NatConstants.INVALID_ID) {
+            LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
+            createOutboundTblEntry(primarySwitchId, routerId);
+        } else {
+            LOG.error("NAT Service : Unable to fetch Router Id  for RouterName {}, failed to createAndInstallMissEntry", routerName);
+        }
+    }
+
+    public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
+        return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+    }
+
+    public BigInteger getCookieOutboundFlow(long routerId) {
+        return NatConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
+                BigInteger.valueOf(routerId));
+    }
+
+    protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
+        LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+        BigInteger cookie = getCookieOutboundFlow(routerId);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
+                5, flowRef, 0, 0,
+                cookie, matches, instructions);
+        LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
+        return flowEntity;
+    }
+
+    public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
+        LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
+        FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
+        LOG.debug("NAT Service : Installing flow {}", flowEntity);
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+        RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
+        try {
+            Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+                                                                                 .setSourceDpid(srcDpId)
+                                                                                 .setDestinationDpid(dstDpId)
+//                                                                                .setTunnelType(tunType)
+                                                                                .build());
+            rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                tunType = TunnelTypeGre.class ;
+                result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+                        .setSourceDpid(srcDpId)
+                        .setDestinationDpid(dstDpId)
+//                        .setTunnelType(tunType)
+                        .build());
+                rpcResult = result.get();
+                if(!rpcResult.isSuccessful()) {
+                    LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+                } else {
+                    return rpcResult.getResult().getInterfaceName();
+                }
+                LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+            } else {
+                return rpcResult.getResult().getInterfaceName();
+            }
+        } catch (InterruptedException | ExecutionException | NullPointerException e) {
+            LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId);
+        }
+
+        return null;
+    }
+
+    protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
+        LOG.debug("NAT Service : getEgressActionsForInterface called for interface {}", ifName);
+        List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
+        try {
+            Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
+                interfaceManager.getEgressActionsForInterface(
+                    new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
+            RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
+            } else {
+                List<Action> actions =
+                    rpcResult.getResult().getAction();
+                for (Action action : actions) {
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
+                    if (actionClass instanceof OutputActionCase) {
+                        listActionInfo.add(new ActionInfo(ActionType.output,
+                                                          new String[] {((OutputActionCase)actionClass).getOutputAction()
+                                                                            .getOutputNodeConnector().getValue()}));
+                    } else if (actionClass instanceof PushVlanActionCase) {
+                        listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
+                    } else if (actionClass instanceof SetFieldCase) {
+                        if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
+                            int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
+                            listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
+                                                              new String[] { Long.toString(vlanVid) }));
+                        }
+                    }
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception when egress actions for interface {}", ifName, e);
+        }
+        return listActionInfo;
+    }
+
+    protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+        LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId, bucketInfo.get(0));
+        // Install the select group
+        long groupId = createGroupId(getGroupIdKey(routerName));
+        GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
+        LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
+        mdsalManager.installGroup(groupEntity);
+        // Install miss entry pointing to group
+        FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo){
+        long groupId = createGroupId(getGroupIdKey(routerName));
+        GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
+        LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
+        mdsalManager.installGroup(groupEntity);
+        return groupId;
+    }
+
+    public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
+
+        LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}", dpId, routerName, groupId );
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
+
+        ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+                        BigInteger.valueOf(routerId)}) ;
+        actionsInfo.add(actionSetField);
+        LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
+        actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+        String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+
+        LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
+        return flowEntity;
+    }
+
+    // TODO : Replace this with ITM Rpc once its available with full functionality
+    protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
+        LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}", dpnId, routerName);
+        FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
+        mdsalManager.installFlow(flowEntity);
+
+    }
+
+    private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
+
+        BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.tunnel_id, new  BigInteger[] {routerId }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
+                { routerId, MetaDataUtil.METADATA_MASK_VRFID }));
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
+                { NatConstants.OUTBOUND_NAPT_TABLE }));
+        String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
+                NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_TS_TABLE, matches, instructions);
+        return flowEntity;
+    }
+
+    public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
+        return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+    }
+
+    public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
+        return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+            append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+    }
+
+    private String getGroupIdKey(String routerName){
+        String groupIdKey = new String("snatmiss." + routerName);
+        return groupIdKey;
+    }
+
+    protected long createGroupId(String groupIdKey) {
+        AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+            .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
+            .build();
+        try {
+            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+            RpcResult<AllocateIdOutput> rpcResult = result.get();
+            return rpcResult.getResult().getIdValue();
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.trace("",e);
+        }
+        return 0;
+    }
+
+    protected void createGroupIdPool() {
+        CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+            .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
+            .setLow(NatConstants.SNAT_ID_LOW_VALUE)
+            .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
+            .build();
+        try {
+            Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+                if ((result != null) && (result.get().isSuccessful())) {
+                    LOG.debug("NAT Service : Created GroupIdPool");
+                } else {
+                    LOG.error("NAT Service : Unable to create GroupIdPool");
+                }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to create PortPool for NAPT Service",e);
+        }
+    }
+
+    protected void handleSwitches (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
+        LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
+        List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+        String ifNamePrimary = getTunnelInterfaceName( dpnId, primarySwitchId);
+        List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+        if(ifNamePrimary != null) {
+            LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
+            listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
+        }
+        BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+
+        listBucketInfo.add(0, bucketPrimary);
+        installSnatMissEntry(dpnId, listBucketInfo, routerName);
+
+    }
+    List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId, BigInteger primarySwitchId, String routerName) {
+        List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+        String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
+        List<BucketInfo> listBucketInfo = new ArrayList<>();
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+        if (ifNamePrimary != null) {
+            LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
+            listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
+        }
+        BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+
+        listBucketInfo.add(0, bucketPrimary);
+        return listBucketInfo;
+    }
+    protected void handlePrimaryNaptSwitch (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
+
+           /*
+            * Primary NAPT Switch â€“ bucket Should always point back to its own Outbound Table
+            */
+
+            LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
+
+            List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+            List<ActionInfo> listActionInfoPrimary =  new ArrayList<ActionInfo>();
+            listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
+            BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+            listBucketInfo.add(0, bucketPrimary);
+
+            long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+            installSnatMissEntry(dpnId, listBucketInfo, routerName);
+            installTerminatingServiceTblEntry(dpnId, routerName);
+            //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
+            installNaptPfibEntry(dpnId, routerId);
+            Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
+           //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+            if(vpnId != null && vpnId != NatConstants.INVALID_ID) {
+                installNaptPfibEntry(dpnId, vpnId);
+            }
+    }
+
+    List<BucketInfo> getBucketInfoForPrimaryNaptSwitch(){
+        List<BucketInfo> listBucketInfo = new ArrayList<>();
+        List<ActionInfo> listActionInfoPrimary =  new ArrayList<>();
+        listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
+        BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+        listBucketInfo.add(0, bucketPrimary);
+        return listBucketInfo;
+    }
+
+    public void installNaptPfibEntry(BigInteger dpnId, long segmentId) {
+        LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and segmentId {} ", dpnId, segmentId);
+        FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
+        mdsalManager.installFlow(naptPfibFlowEntity);
+    }
+
+    public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
+
+        LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, segmentId {}", dpId, segmentId );
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+        ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+        listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+        instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
+
+        String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, segmentId);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
+                NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+
+        LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
+        return flowEntity;
+    }
+
+    private void handleSnatReverseTraffic(BigInteger dpnId, long routerId, String externalIp) {
+        LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
+        Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+        if(networkId == null) {
+            LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
+            return;
+        }
+        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+        if(vpnName == null) {
+            LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip configuration {} in router {}",
+                    networkId, externalIp, routerId);
+            return;
+        }
+        advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
+        LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
+    }
+
+    public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName, final long routerId, final String externalIp,
+                                                VpnRpcService vpnService, final FibRpcService fibService, final IBgpManager bgpManager, final DataBroker dataBroker,
+                                                final Logger log){
+        LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} and externalIp {}", dpnId, tableId, vpnName, externalIp);
+        //Generate VPN label for the external IP
+        GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+        Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
+
+        //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
+        ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture), new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
+
+            @Override
+            public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
+                if (result.isSuccessful()) {
+                    LOG.debug("NAT Service : inside apply with result success");
+                    GenerateVpnLabelOutput output = result.getResult();
+                    long label = output.getLabel();
+
+                    //Inform BGP
+                    String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+                    String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
+                    NatUtil.addPrefixToBGP(bgpManager, rd, externalIp, nextHopIp, label, log);
+
+                    //Get IPMaps from the DB for the router ID
+                    List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
+                    if (dbIpMaps != null) {
+                        for (IpMap dbIpMap : dbIpMaps) {
+                            String dbExternalIp = dbIpMap.getExternalIp();
+                            //Select the IPMap, whose external IP is the IP for which FIB is installed
+                            if (externalIp.equals(dbExternalIp)) {
+                                String dbInternalIp = dbIpMap.getInternalIp();
+                                IpMapKey dbIpMapKey = dbIpMap.getKey();
+                                LOG.debug("Setting label {} for internalIp {} and externalIp {}", label, dbInternalIp, externalIp);
+                                IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp).setExternalIp(dbExternalIp).setLabel(label).build();
+                                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
+                                break;
+                            }
+                        }
+                    } else {
+                        LOG.error("NAT Service : Failed to write label {} for externalIp {} for routerId {} in DS", label, externalIp, routerId);
+                    }
+
+                    //Install custom FIB routes
+                    List<Instruction> customInstructions = new ArrayList<>();
+                    customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(0));
+                    makeTunnelTableEntry(dpnId, label, customInstructions);
+                    makeLFibTableEntry(dpnId, label, tableId);
+
+                    CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId)
+                            .setIpAddress(externalIp).setServiceId(label).setInstruction(customInstructions).build();
+                    Future<RpcResult<Void>> future = fibService.createFibEntry(input);
+                    return JdkFutureAdapters.listenInPoolThread(future);
+                } else {
+                    LOG.error("NAT Service : inside apply with result failed");
+                    String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
+                    return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                }
+            }
+        });
+
+            Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
+
+                @Override
+                public void onFailure(Throwable error) {
+                    log.error("NAT Service : Error in generate label or fib install process", error);
+                }
+
+                @Override
+                public void onSuccess(RpcResult<Void> result) {
+                    if (result.isSuccessful()) {
+                        log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
+                    } else {
+                        log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
+                    }
+                }
+            });
+     }
+
+    private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[]{0x8847L}));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+        Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
+        instructions.add(writeInstruction);
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
+
+        // Install the flow entry in L3_LFIB_TABLE
+        String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+                10, flowRef, 0, 0,
+                COOKIE_VM_LFIB_TABLE, matches, instructions);
+
+        mdsalManager.installFlow(dpId, flowEntity);
+
+        LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+    }
+
+    private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+
+        LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
+
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+
+        Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d", "TST Flow Entry ", serviceId),
+                0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
+
+        mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+    }
+
+    protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
+        InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
+                RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
+        return id;
+    }
+
+    private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
+        return new StringBuilder(64).append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
+        String routerName = original.getRouterName();
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+        Uuid networkId = original.getNetworkId();
+
+        // Check if its update on SNAT flag
+        boolean originalSNATEnabled = original.isEnableSnat();
+        boolean updatedSNATEnabled = update.isEnableSnat();
+        LOG.debug("NAT Service : update of externalRoutersListener called with originalFlag and updatedFlag as {} and {}", originalSNATEnabled, updatedSNATEnabled);
+        if(originalSNATEnabled != updatedSNATEnabled) {
+            if(originalSNATEnabled) {
+                //SNAT disabled for the router
+                Uuid networkUuid = original.getNetworkId();
+                LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
+                if (routerId == NatConstants.INVALID_ID) {
+                    LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
+                    return;
+                }
+                List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+                handleDisableSnat(routerName, networkUuid, externalIps, false, null);
+            } else {
+                LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
+                handleEnableSnat(original);
+            }
+        }
+
+        //Check if the Update is on External IPs
+        LOG.debug("NAT Service : Checking if this is update on External IPs");
+        List<String> originalExternalIpsList = original.getExternalIps();
+        List<String> updatedExternalIpsList = update.getExternalIps();
+        Set<String> originalExternalIps = Sets.newHashSet(originalExternalIpsList);
+        Set<String> updatedExternalIps = Sets.newHashSet(updatedExternalIpsList);
+
+        //Check if the External IPs are added during the update.
+        SetView<String> addedExternalIps = Sets.difference(updatedExternalIps, originalExternalIps);
+        if(addedExternalIps.size() != 0) {
+            LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
+            for (String addedExternalIp : addedExternalIps) {
+                /*
+                    1) Do nothing in the IntExtIp model.
+                    2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
+                */
+                String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
+                String externalIp = externalIpParts[0];
+                String externalIpPrefix = externalIpParts[1];
+                String externalpStr = externalIp + "/" + externalIpPrefix;
+                LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the router ID {} in the ExternalIpsCounter model.",
+                        externalpStr, routerId);
+                naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
+            }
+            LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
+        }
+
+        //Check if the External IPs are removed during the update.
+        SetView<String> removedExternalIps = Sets.difference(originalExternalIps, updatedExternalIps);
+        if(removedExternalIps.size() > 0) {
+            LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
+            List<String> removedExternalIpsAsList = new ArrayList<>();
+            for (String removedExternalIp : removedExternalIps) {
+             /*
+                1) Remove the mappings in the IntExt IP model which has external IP.
+                2) Remove the external IP in the ExternalCounter model.
+                3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the least loaded external IP.
+                   Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
+                4) Increase the count of the allocated external IP by one.
+                5) Advertise to the BGP if external IP is allocated for the first time for the router i.e. the route for the external IP is absent.
+                6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs and also from the model.
+                7) Advertise to the BGP for removing the route for the removed external IPs.
+              */
+
+                String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
+                String externalIp = externalIpParts[0];
+                String externalIpPrefix = externalIpParts[1];
+                String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
+
+                LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS entries for removed external IP {}", externalIpAddrStr);
+                Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+                String vpnName = "";
+                if(vpnUuId != null){
+                    vpnName = vpnUuId.getValue();
+                }
+                clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
+
+                LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
+                //Get the internal IPs which are associated to the removed external IPs
+                List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
+                List<String> removedInternalIps = new ArrayList<>();
+                for(IpMap ipMap : ipMaps){
+                    if(ipMap.getExternalIp().equals(externalIpAddrStr)){
+                        removedInternalIps.add(ipMap.getInternalIp());
+                    }
+                }
+
+                LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
+                for(String removedInternalIp : removedInternalIps){
+                    LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the router ID {} from the IntExtIP model",
+                            removedInternalIp, routerId);
+                    naptManager.removeFromIpMapDS(routerId, removedInternalIp);
+                }
+
+                LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the router ID {} from the ExternalIpsCounter model.",
+                        externalIpAddrStr, routerId );
+                naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
+                removedExternalIpsAsList.add(externalIpAddrStr);
+
+                LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets whose external IPs were removed.");
+                for(String removedInternalIp : removedInternalIps) {
+                    allocateExternalIp(dpnId, routerId, networkId, removedInternalIp);
+                }
+
+                LOG.debug("NAT Service : Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs.");
+                //Get the internalIP and internal Port which were associated to the removed external IP.
+                List<Integer> externalPorts = new ArrayList<>();
+                Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
+                InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier.builder(IntextIpPortMap.class)
+                        .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
+                Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
+                if (ipPortMapping.isPresent()) {
+                    List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get().getIntextIpProtocolType();
+                    for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+                        ProtocolTypes protoType = intextIpProtocolType.getProtocol();
+                        List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+                        for(IpPortMap ipPortMap : ipPortMaps){
+                            IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+                            if(ipPortExternal.getIpAddress().equals(externalIp)){
+                                externalPorts.add(ipPortExternal.getPortNum());
+                                List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
+                                if(removedInternalIpPorts != null){
+                                    removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
+                                    protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
+                                }else{
+                                    removedInternalIpPorts = new ArrayList<>();
+                                    removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
+                                    protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
+                                }
+                            }
+                        }
+                    }
+                }
+
+                //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP.
+                Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap.entrySet();
+                Map<String, List<String>> internalIpPortMap = new HashMap<>();
+                for(Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts){
+                    ProtocolTypes protocolType = (ProtocolTypes)protoTypesIntIpPort.getKey();
+                    List<String> removedInternalIpPorts = (List<String>)protoTypesIntIpPort.getValue();
+                    for(String removedInternalIpPort : removedInternalIpPorts){
+                        //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP
+                        naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
+                        //Remove the IP port incomint packer map.
+                        naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
+                        String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
+                        if(removedInternalIpPortParts.length == 2){
+                            String removedInternalIp = removedInternalIpPortParts[0];
+                            String removedInternalPort = removedInternalIpPortParts[1];
+                            List<String> removedInternalPortsList =  internalIpPortMap.get(removedInternalPort);
+                            if (removedInternalPortsList != null){
+                                removedInternalPortsList.add(removedInternalPort);
+                                internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
+                            }else{
+                                removedInternalPortsList = new ArrayList<>();
+                                removedInternalPortsList.add(removedInternalPort);
+                                internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
+                            }
+                        }
+                    }
+                }
+
+                // Delete the entry from SnatIntIpPortMap DS
+                Set<String> internalIps = internalIpPortMap.keySet();
+                for(String internalIp : internalIps){
+                    LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the model SnatIntIpPortMap", internalIp);
+                    naptManager.removeFromSnatIpPortDS(routerId, internalIp);
+                }
+
+                naptManager.removeNaptPortPool(externalIp);
+
+                LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed external IP {}", externalIp);
+                for(Integer externalPort : externalPorts) {
+                    //Remove the NAPT translation entries from Inbound NAPT table
+                    naptEventHandler.removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, externalIp, externalPort);
+                }
+
+                Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
+                for(Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
+                    String internalIp = internalIpPort.getKey();
+                    LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for the removed internal IP {}", internalIp);
+                    List<String> internalPorts = internalIpPort.getValue();
+                    for(String internalPort : internalPorts){
+                        //Remove the NAPT translation entries from Outbound NAPT table
+                        naptEventHandler.removeNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, Integer.valueOf(internalPort));
+                    }
+                }
+            }
+            LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
+        }
+
+        //Check if its Update on subnets
+        LOG.debug("NAT Service : Checking if this is update on subnets");
+        List<Uuid> originalSubnetIdsList = original.getSubnetIds();
+        List<Uuid> updatedSubnetIdsList = update.getSubnetIds();
+        Set<Uuid> originalSubnetIds = Sets.newHashSet(originalSubnetIdsList);
+        Set<Uuid> updatedSubnetIds = Sets.newHashSet(updatedSubnetIdsList);
+        SetView<Uuid> addedSubnetIds = Sets.difference(updatedSubnetIds, originalSubnetIds);
+
+        //Check if the Subnet IDs are added during the update.
+        if(addedSubnetIds.size() != 0){
+            LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
+            for(Uuid addedSubnetId : addedSubnetIds){
+                /*
+                1) Select the least loaded external IP for the subnet and store the mapping of the subnet IP and the external IP in the IntExtIp model.
+                2) Increase the count of the selected external IP by one.
+                3) Advertise to the BGP if external IP is allocated for the first time for the router i.e. the route for the external IP is absent.
+                */
+                String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
+                if(subnetIp != null) {
+                    allocateExternalIp(dpnId, routerId, networkId, subnetIp);
+                }
+            }
+            LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
+        }
+
+        //Check if the Subnet IDs are removed during the update.
+        SetView<Uuid> removedSubnetIds = Sets.difference(originalSubnetIds, updatedSubnetIds);
+        if(removedSubnetIds.size() != 0){
+            LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
+            for(Uuid removedSubnetId : removedSubnetIds){
+                String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
+                if(subnetAddr != null){
+                    /*
+                    1) Remove the subnet IP and the external IP in the IntExtIp map
+                    2) Decrease the count of the coresponding external IP by one.
+                    3) Advertise to the BGP for removing the routes of the corresponding external IP if its not allocated to any other internal IP.
+                    */
+                    LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and internal IP {}", routerId, subnetAddr[0]);
+                    naptManager.removeFromIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
+                }
+            }
+            LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
+        }
+    }
+
+    private void allocateExternalIp(BigInteger dpnId, long routerId, Uuid networkId, String subnetIp){
+        String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
+        if (leastLoadedExtIpAddr != null) {
+            String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
+            String leastLoadedExtIp = externalIpParts[0];
+            String leastLoadedExtIpPrefix = externalIpParts[1];
+            String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
+            IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
+            String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
+            subnetIp = subnetIpParts[0];
+            String subnetIpPrefix = subnetIpParts[1];
+            IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
+            LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal IP {} and prefix {} -> external IP {} and prefix {}",
+                    routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
+            naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
+
+
+            //Check if external IP is already assigned a route. (i.e. External IP is previously allocated to any of the subnets)
+            //If external IP is already assigned a route, (, do not re-advertise to the BGP
+            if(checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr)){
+                return;
+            }
+
+            //Re-advertise to the BGP for the external IP, which is allocated to the subnet for the first time and hence not having a route.
+            //Get the VPN Name using the network ID
+            final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+            if (vpnName != null) {
+                LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
+                advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId,
+                        leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, vpnService, fibService, bgpManager, dataBroker, LOG);
+            }
+        }
+    }
+
+    private boolean checkExternalIpLabel(long routerId, String externalIp){
+        List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
+        for(IpMap ipMap : ipMaps){
+            if(ipMap.getExternalIp().equals(externalIp)){
+                if (ipMap.getLabel() != null){
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
+        LOG.trace("NAT Service : Router delete method");
+        {
+        /*
+            ROUTER DELETE SCENARIO
+            1) Get the router ID from the event.
+            2) Build the cookie information from the router ID.
+            3) Get the primary and secondary switch DPN IDs using the router ID from the model.
+            4) Build the flow with the cookie value.
+            5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
+            6) Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
+            7) Get the list of external IP address maintained for the router ID.
+            8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
+            9) Withdraw the corresponding routes from the BGP.
+         */
+
+            if (identifier == null || router == null) {
+                LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: returning without processing since routers is null");
+                return;
+            }
+
+            String routerName = router.getRouterName();
+            LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
+            addOrDelDefFibRouteToSNAT(routerName, false);
+            Uuid networkUuid = router.getNetworkId();
+            Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+            if (routerId == NatConstants.INVALID_ID) {
+                LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
+                return;
+            }
+            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+            handleDisableSnat(routerName, networkUuid, externalIps, true, null);
+        }
+    }
+
+    public void handleDisableSnat(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
+        LOG.info("NAT Service : handleDisableSnat() Entry");
+        try {
+            Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+            BigInteger naptSwitchDpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+            LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
+            if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)){
+                LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the router ID {} from RouterNaptSwitch model", routerId);
+                return;
+            }
+            removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
+            removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
+            try {
+                clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
+            } catch (Exception ex) {
+                LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
+            }
+
+            //Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained for the router ID.
+            LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the router ID {} in the DS", routerId);
+            naptManager.removeMapping(routerId);
+
+            if(routerFlag) {
+                removeNaptSwitch(routerName);
+            } else {
+                updateNaptSwitch(routerName, BigInteger.ZERO);
+            }
+
+            LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
+            naptManager.removeExternalCounter(routerId);
+        } catch (Exception ex) {
+            LOG.error("Exception while handling disableSNAT : {}", ex);
+        }
+        LOG.info("NAT Service : handleDisableSnat() Exit");
+    }
+
+    public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
+        LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
+        try {
+            Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+            BigInteger naptSwitchDpnId = null;
+            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerName);
+            Optional<RouterToNaptSwitch> rtrToNapt = read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch);
+            if (rtrToNapt.isPresent()) {
+                naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
+            }
+            LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
+
+            removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
+            try {
+                clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
+            } catch (Exception ex) {
+                LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
+            }
+          } catch (Exception ex) {
+            LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
+        }
+        LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
+    }
+
+    public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
+        RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
+                .setPrimarySwitchId(naptSwitchId).build();
+        try {
+            MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
+        } catch (Exception ex) {
+            LOG.error("Failed to write naptSwitch {} for router {} in ds",
+                    naptSwitchId,routerName);
+        }
+        LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
+                naptSwitchId,routerName);
+    }
+
+    protected void removeNaptSwitch(String routerName){
+        // Remove router and switch from model
+        InstanceIdentifier<RouterToNaptSwitch> id = InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+        LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
+        MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+     public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
+
+        LOG.debug("NAT Service : Remove NAPT flows from Active switch");
+        BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+
+        //Remove the PSNAT entry which forwards the packet to Terminating Service table
+        String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, routerName);
+        FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
+
+        LOG.info("NAT Service : Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+        mdsalManager.removeFlow(pSNatFlowEntity);
+
+        //Remove the group entry which resubmits the packet to the Terminating Service table or to the out port accordingly.
+        long groupId = createGroupId(getGroupIdKey(routerName));
+        List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+        GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
+
+        LOG.info("NAT Service : Remove the group {} for the active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
+        mdsalManager.removeGroup(pSNatGroupEntity);
+
+        //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
+        String tsFlowRef = getFlowRefTs(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
+        FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
+
+        LOG.info("NAT Service : Remove the flow in the " + NatConstants.TERMINATING_SERVICE_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+        mdsalManager.removeFlow(tsNatFlowEntity);
+
+        //Remove the Outbound flow entry which forwards the packet to FIB Table
+        String outboundNatFlowRef = getFlowRefOutbound(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+        FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
+
+        LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+        mdsalManager.removeFlow(outboundNatFlowEntity);
+
+        //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
+        String natPfibFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, routerId);
+        FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
+
+        LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+        mdsalManager.removeFlow(natPfibFlowEntity);
+
+        //Long vpnId = NatUtil.getVpnId(dataBroker, routerId); - This does not work since ext-routers is deleted already - no network info
+        //Get the VPN ID from the ExternalNetworks model
+        long vpnId = -1;
+        if( (vpnName == null) || (vpnName.isEmpty()) ) {
+            // ie called from router delete cases
+            Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+            LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
+            if(vpnUuid != null) {
+                vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId );
+            }
+        } else {
+            // ie called from disassociate vpn case
+            LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
+            vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+            LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
+        }
+
+        if(vpnId != NatConstants.INVALID_ID){
+           //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+           String natPfibVpnFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, vpnId);
+           FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
+           LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and VPN ID {}", dpnId, vpnId);
+           mdsalManager.removeFlow(natPfibVpnFlowEntity);
+        }
+
+        //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+        IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+        if(ipPortMapping == null){
+            LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
+            return;
+        }
+
+        List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+        for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+            List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+            for(IpPortMap ipPortMap : ipPortMaps){
+                String ipPortInternal = ipPortMap.getIpPortInternal();
+                String[] ipPortParts = ipPortInternal.split(":");
+                if(ipPortParts.length != 2) {
+                    LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
+                    return;
+                }
+                String internalIp = ipPortParts[0];
+                String internalPort = ipPortParts[1];
+
+                //Build the flow for the outbound NAPT table
+                String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
+                FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+                LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+                mdsalManager.removeFlow(outboundNaptFlowEntity);
+
+                IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+                String externalIp = ipPortExternal.getIpAddress();
+                int externalPort = ipPortExternal.getPortNum();
+
+                //Build the flow for the inbound NAPT table
+                switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
+                FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+                LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+                mdsalManager.removeFlow(inboundNaptFlowEntity);
+            }
+        }
+    }
+
+     public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
+
+         LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
+         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+
+         //Remove the NAPT PFIB TABLE entry
+         long vpnId = -1;
+         if(vpnName != null) {
+             // ie called from disassociate vpn case
+             LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
+             vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+             LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
+         }
+
+         if(vpnId != NatConstants.INVALID_ID){
+            //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+            String natPfibVpnFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, vpnId);
+            FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
+            LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and VPN ID {}", dpnId, vpnId);
+            mdsalManager.removeFlow(natPfibVpnFlowEntity);
+
+             // Remove IP-PORT active NAPT entries and release port from IdManager
+             //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+             IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+             if(ipPortMapping == null){
+                 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
+                 return;
+             }
+             List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+             for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+                 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+                 for(IpPortMap ipPortMap : ipPortMaps){
+                     String ipPortInternal = ipPortMap.getIpPortInternal();
+                     String[] ipPortParts = ipPortInternal.split(":");
+                     if(ipPortParts.length != 2) {
+                         LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
+                         return;
+                     }
+                     String internalIp = ipPortParts[0];
+                     String internalPort = ipPortParts[1];
+
+                     //Build the flow for the outbound NAPT table
+                     String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
+                     FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+                     LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+                     mdsalManager.removeFlow(outboundNaptFlowEntity);
+
+                     IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+                     String externalIp = ipPortExternal.getIpAddress();
+                     int externalPort = ipPortExternal.getPortNum();
+
+                     //Build the flow for the inbound NAPT table
+                     switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
+                     FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+                     LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+                     mdsalManager.removeFlow(inboundNaptFlowEntity);
+
+                     // Finally release port from idmanager
+                     String internalIpPort = internalIp +":"+internalPort;
+                     naptManager.removePortFromPool(internalIpPort, externalIp);
+
+                     //Remove sessions from models
+                     naptManager.removeIpPortMappingForRouterID(routerId);
+                     naptManager.removeIntIpPortMappingForRouterID(routerId);
+                 }
+             }
+         } else {
+             LOG.error("NAT Service : Invalid vpnId {}", vpnId);
+         }
+     }
+
+    public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId){
+        LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
+
+        //Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
+        List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
+        if(allSwitchList == null || allSwitchList.isEmpty()){
+            LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
+            return;
+        }
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        for (BigInteger dpnId : allSwitchList) {
+            if (!naptSwitchDpnId.equals(dpnId)) {
+                LOG.info("NAT Service : Handle Ordinary switch");
+
+                //Remove the PSNAT entry which forwards the packet to Terminating Service table
+                String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, String.valueOf(routerName));
+                FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
+
+                LOG.info("Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the non active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+                mdsalManager.removeFlow(pSNatFlowEntity);
+
+                //Remove the group entry which resubmits the packet to the Terminating Service table or to the out port accordingly.
+                long groupId = createGroupId(getGroupIdKey(routerName));
+                List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+                GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
+
+                LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
+                mdsalManager.removeGroup(pSNatGroupEntity);
+
+            }
+        }
+    }
+
+    public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps, String vpnName) {
+        //Withdraw the corresponding routes from the BGP.
+        //Get the network ID using the router ID.
+        LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {}, network Id {} and vpnName {}",
+                externalIps,routerId,networkUuid, vpnName);
+        if(networkUuid == null ){
+            LOG.error("NAT Service : networkId is null");
+            return;
+        }
+
+        if (externalIps == null || externalIps.isEmpty()) {
+            LOG.debug("NAT Service : externalIps is null");
+            return;
+        }
+
+        if(vpnName ==null) {
+            //Get the VPN Name using the network ID
+            vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
+            if (vpnName == null) {
+                LOG.error("No VPN associated with ext nw {} for the router {}",
+                        networkUuid, routerId);
+                return;
+            }
+        }
+        LOG.debug("Retrieved vpnName {} for networkId {}",vpnName,networkUuid);
+
+        //Remove custom FIB routes
+        //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
+        for (String extIp : externalIps) {
+            clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
+        }
+    }
+
+    private void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName){
+        //Inform BGP about the route removal
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        NatUtil.removePrefixFromBGP(bgpManager, rd, extIp, LOG);
+
+        LOG.debug("Removing fib entry for externalIp {} in routerId {}",extIp,routerId);
+        //Get IPMaps from the DB for the router ID
+        List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
+        if (dbIpMaps == null || dbIpMaps.isEmpty()) {
+            LOG.error("NAT Service : IPMaps not found for router {}",routerId);
+            return;
+        }
+
+        long tempLabel = NatConstants.INVALID_ID;
+        for (IpMap dbIpMap : dbIpMaps) {
+            String dbExternalIp = dbIpMap.getExternalIp();
+            LOG.debug("Retrieved dbExternalIp {} for router id {}",dbExternalIp,routerId);
+            //Select the IPMap, whose external IP is the IP for which FIB is installed
+            if (extIp.equals(dbExternalIp)) {
+                tempLabel = dbIpMap.getLabel();
+                LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",tempLabel,dbExternalIp,routerId);
+                break;
+            }
+        }
+        if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
+            LOG.error("NAT Service : Label not found for externalIp {} with router id {}",extIp,routerId);
+            return;
+        }
+
+        final long label = tempLabel;
+        final String externalIp = extIp;
+
+        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
+        Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
+
+        ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
+
+            @Override
+            public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+                //Release label
+                if (result.isSuccessful()) {
+                    removeTunnelTableEntry(dpnId, label);
+                    removeLFibTableEntry(dpnId, label);
+                    RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+                    Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
+                    return JdkFutureAdapters.listenInPoolThread(labelFuture);
+                } else {
+                    String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+                    LOG.error(errMsg);
+                    return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                }
+            }
+
+        });
+
+        Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
+            }
+
+            @Override
+            public void onSuccess(RpcResult<Void> result) {
+                if (result.isSuccessful()) {
+                    LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
+                } else {
+                    LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+                }
+            }
+        });
+    }
+
+    private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
+        LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+        // Matching metadata
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+                5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+                COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+        mdsalManager.removeFlow(dpnId, flowEntity);
+        LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+    }
+
+    private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x8847L }));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+        String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+        LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
+
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+                10, flowRef, 0, 0,
+                COOKIE_VM_LFIB_TABLE, matches, null);
+
+        mdsalManager.removeFlow(dpnId, flowEntity);
+
+        LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+    }
+
+    protected InstanceIdentifier<Routers> getWildCardPath()
+    {
+        return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
+    }
+
+
+    /**
+     * router association to vpn
+     *
+     */
+    public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName){
+        LOG.debug("NAT Service : Router associated to BGP VPN");
+        if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
+            long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
+
+            LOG.debug("BGP VPN ID value {} ", bgpVpnId);
+
+            if(bgpVpnId != NatConstants.INVALID_ID){
+                LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
+                RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
+                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
+
+                // Get the allocated Primary NAPT Switch for this router
+                long routerId = NatUtil.getVpnId(dataBroker, routerName);
+                LOG.debug("Router ID value {} ", routerId);
+                BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+
+                LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
+                addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, true);
+
+                // Get the group ID
+                long groupId = createGroupId(getGroupIdKey(routerName));
+                installFlowsWithUpdatedVpnId(primarySwitchId, routerName, groupId, bgpVpnId, routerId);
+            }
+        }
+    }
+
+    /**
+     * router disassociation from vpn
+     *
+     */
+    public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName){
+        LOG.debug("NAT Service : Router dissociated from BGP VPN");
+        if(chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
+            long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
+            LOG.debug("BGP VPN ID value {} ", bgpVpnId);
+
+            // Get the allocated Primary NAPT Switch for this router
+            long routerId = NatUtil.getVpnId(dataBroker, routerName);
+            LOG.debug("Router ID value {} ", routerId);
+            BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+
+            LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
+            addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, NatConstants.INVALID_ID, true);
+
+            // Get the group ID
+            long groupId = createGroupId(getGroupIdKey(routerName));
+            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, groupId, NatConstants.INVALID_ID, routerId);
+        }
+    }
+
+    boolean chkExtRtrAndSnatEnbl(Uuid routerUuid){
+        InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class).child
+                (Routers.class, new RoutersKey(routerUuid.getValue())).build();
+        Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
+        if (routerData.isPresent() && routerData.get().isEnableSnat()) {
+            return true;
+        }
+        return false;
+    }
+
+    public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long groupId, long bgpVpnId, long routerId){
+        long changedVpnId = bgpVpnId;
+        String logMsg = "NAT Service : Update the BGP VPN ID {}";
+        if (bgpVpnId == NatConstants.INVALID_ID){
+            changedVpnId = routerId;
+            logMsg = "NAT Service : Update the router ID {}";
+        }
+
+        LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the primary switch {}",
+                changedVpnId, groupId, primarySwitchId);
+        FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(primarySwitchId, routerName, groupId, changedVpnId);
+        mdsalManager.installFlow(flowEntity);
+
+        LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet" +
+                " to the table 46 in the Primary switch {}",  changedVpnId, primarySwitchId);
+        installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
+
+        LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the" +
+                " controller in the Primary switch {}", changedVpnId, primarySwitchId);
+        createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
+
+        LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the Primary switch {}",
+                changedVpnId, primarySwitchId);
+        installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
+
+        LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the INBOUND NAPT table (table ID 44)" +
+                        " in the Primary switch {}", changedVpnId, primarySwitchId);
+        updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
+
+        List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+        for(BigInteger dpnId : switches) {
+            // Update the BGP VPN ID in the SNAT miss entry to group
+            if( !dpnId.equals(primarySwitchId) ) {
+                LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
+                        changedVpnId, groupId, dpnId);
+                flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
+                mdsalManager.installFlow(flowEntity);
+            }
+        }
+    }
+
+    public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId){
+        //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+        IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+        if(ipPortMapping == null){
+            LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
+            return;
+        }
+
+        List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+        for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+            List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+            for(IpPortMap ipPortMap : ipPortMaps){
+                String ipPortInternal = ipPortMap.getIpPortInternal();
+                String[] ipPortParts = ipPortInternal.split(":");
+                if(ipPortParts.length != 2) {
+                    LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
+                    return;
+                }
+                String internalIp = ipPortParts[0];
+                String internalPort = ipPortParts[1];
+
+                ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
+                NAPTEntryEvent.Protocol protocol;
+                switch (protocolTypes){
+                    case TCP:
+                        protocol = NAPTEntryEvent.Protocol.TCP;
+                        break;
+                    case UDP:
+                        protocol = NAPTEntryEvent.Protocol.UDP;
+                        break;
+                    default:
+                        protocol = NAPTEntryEvent.Protocol.TCP;
+                }
+                SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
+                SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
+                long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
+                naptEventHandler.buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
+                        internalAddress, externalAddress, protocol);
+                naptEventHandler.buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
+                        externalAddress, internalAddress, protocol);
+
+            }
+        }
+    }
+
+    public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId, long changedVpnId) {
+
+        LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} changed VPN ID {}", dpId, routerName, groupId, changedVpnId );
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<InstructionInfo> instructions = new ArrayList<>();
+        List<ActionInfo> actionsInfo = new ArrayList<>();
+
+        ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+                BigInteger.valueOf(changedVpnId)}) ;
+        actionsInfo.add(actionSetField);
+        LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
+        actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+        String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+
+        LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
+        return flowEntity;
+    }
+
+    // TODO : Replace this with ITM Rpc once its available with full functionality
+    protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName, long changedVpnId) {
+        LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
+        FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
+        mdsalManager.installFlow(flowEntity);
+
+    }
+
+    private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
+        LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpId, routerName, changedVpnId);
+        BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
+        BigInteger bgpVpnIdAsBigInt = BigInteger.valueOf(changedVpnId);
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.tunnel_id, new  BigInteger[] {bgpVpnIdAsBigInt }));
+
+        List<InstructionInfo> instructions = new ArrayList<>();
+        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
+                { bgpVpnIdAsBigInt, MetaDataUtil.METADATA_MASK_VRFID }));
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
+                { NatConstants.OUTBOUND_NAPT_TABLE }));
+        String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
+                NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_TS_TABLE, matches, instructions);
+        return flowEntity;
+    }
+
+    public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
+        LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}", dpnId, routerId, changedVpnId);
+        FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
+        LOG.debug("NAT Service : Installing flow {}", flowEntity);
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
+        LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}", dpId, routerId, changedVpnId);
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[]{0x0800L}));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[]{
+                BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
+
+        List<InstructionInfo> instructions = new ArrayList<>();
+        List<ActionInfo> actionsInfos = new ArrayList<>();
+        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
+
+        String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+        BigInteger cookie = getCookieOutboundFlow(routerId);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
+                5, flowRef, 0, 0,
+                cookie, matches, instructions);
+        LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
+        return flowEntity;
+    }
+
+    public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
+        LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}", dpnId, segmentId, changedVpnId);
+        FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
+        mdsalManager.installFlow(naptPfibFlowEntity);
+    }
+
+    public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
+
+        LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+        ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+        listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+        instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
+
+        String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, segmentId);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
+                NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+
+        LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
+        return flowEntity;
+    }
+
+    @Override
+    protected ExternalRoutersListener getDataTreeChangeListener()
+    {
+        return ExternalRoutersListener.this;
+    }
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPHandler.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPHandler.java
new file mode 100644 (file)
index 0000000..8b1ad65
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+
+public interface FloatingIPHandler {
+
+    void onAddFloatingIp(BigInteger dpnId, String routerId, Uuid networkId, String interfaceName, String externalIp,
+                         String internalIp);
+
+    void onRemoveFloatingIp(BigInteger dpnId, String routerId, Uuid networkId, String externalIp, String internalIp,
+                            long label);
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/FloatingIPListener.java
new file mode 100644 (file)
index 0000000..1240f26
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.FloatingIpInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.NetworksKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by emhamla on 1/18/2016.
+ */
+public class FloatingIPListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<IpMapping> implements AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker broker;
+    private OdlInterfaceRpcService interfaceManager;
+    private IMdsalApiManager mdsalManager;
+    private FloatingIPHandler handler;
+
+
+    public FloatingIPListener (final DataBroker db) {
+        super(IpMapping.class);
+        broker = db;
+        registerListener(db);
+    }
+
+    void setFloatingIpHandler(FloatingIPHandler handler) {
+        this.handler = handler;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("FloatingIP Listener Closed");
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), FloatingIPListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("FloatingIP DataChange listener registration fail!", e);
+            throw new IllegalStateException("FloatingIP Listener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<IpMapping> getWildCardPath() {
+        return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class).child(IpMapping.class);
+    }
+
+    public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+        this.interfaceManager = interfaceManager;
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    @Override
+    protected void add(final InstanceIdentifier<IpMapping> identifier,
+                       final IpMapping mapping) {
+        LOG.trace("FloatingIPListener add ip mapping method - key: " + identifier + ", value=" + mapping );
+        processFloatingIPAdd(identifier, mapping);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<IpMapping> identifier, IpMapping mapping) {
+        LOG.trace("FloatingIPListener remove ip mapping method - key: " + identifier + ", value=" + mapping );
+        processFloatingIPDel(identifier, mapping);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<IpMapping> identifier, IpMapping original, IpMapping update) {
+        LOG.trace("FloatingIPListener update ip mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
+    }
+
+    public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
+        BigInteger nodeId = BigInteger.ZERO;
+        try {
+            GetDpidFromInterfaceInput
+                    dpIdInput =
+                    new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
+            Future<RpcResult<GetDpidFromInterfaceOutput>>
+                    dpIdOutput =
+                    interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
+            RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
+            if (dpIdResult.isSuccessful()) {
+                nodeId = dpIdResult.getResult().getDpid();
+            } else {
+                LOG.error("Could not retrieve DPN Id for interface {}", ifName);
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Exception when getting dpn for interface {}", ifName,  e);
+        }
+        return nodeId;
+    }
+
+    private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long vpnId) {
+        return buildPreDNATFlowEntity(dpId, internalIp, externalIp, routerId, vpnId, NatConstants.INVALID_ID);
+    }
+
+    private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpn) {
+        LOG.info("Bulding DNAT Flow entity for ip {} ", externalIp);
+
+        long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
+        LOG.debug("Segment id {} in build preDNAT Flow", segmentId);
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+                externalIp, "32" }));
+
+//        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+//                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.set_destination_ip, new String[]{ internalIp, "32" }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf
+                (segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.DNAT_TABLE }));
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PDNAT_TABLE, routerId, externalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PDNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+    }
+
+
+
+    private FlowEntity buildDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
+        return buildDNATFlowEntity(dpId, internalIp, externalIp, routerId, NatConstants.INVALID_ID);
+    }
+
+    private FlowEntity buildDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long associatedVpn) {
+
+        LOG.info("Bulding DNAT Flow entity for ip {} ", externalIp);
+
+        long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
+        LOG.debug("Segment id {} in build DNAT", segmentId);
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+        //        externalIp, "32" }));
+                  internalIp, "32" }));
+
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+//        actionsInfos.add(new ActionInfo(ActionType.set_destination_ip, new String[]{ internalIp, "32" }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+//        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf
+//                (routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+        actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.L3_FIB_TABLE }));
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.DNAT_TABLE, routerId, externalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.DNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+
+    }
+
+    private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long routerId) {
+        return buildPreSNATFlowEntity(dpId, internalIp, externalIp, vpnId, routerId, NatConstants.INVALID_ID);
+    }
+
+    private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long routerId, long associatedVpn) {
+
+        LOG.info("Building PSNAT Flow entity for ip {} ", internalIp);
+
+        long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
+
+        LOG.debug("Segment id {} in build preSNAT flow", segmentId);
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] {
+                internalIp, "32" }));
+
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[]{ externalIp, "32" }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.SNAT_TABLE }));
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PSNAT_TABLE, routerId, internalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+    }
+
+    private FlowEntity buildSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, String macAddress) {
+
+        LOG.info("Building SNAT Flow entity for ip {} ", internalIp);
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] {
+        //        internalIp, "32" }));
+                  externalIp, "32" }));
+
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+//        actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[]{ externalIp, "32" }));
+
+        //TODO: Set external gateway mac address
+        if(!Strings.isNullOrEmpty(macAddress)) {
+            LOG.debug("Setting ext gw mac address {} in SNAT {} flow action", macAddress, internalIp);
+            actionsInfos.add(new ActionInfo(ActionType.set_field_eth_dest, new String[]{ macAddress }));
+        }
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        //instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+        actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.L3_FIB_TABLE }));
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.SNAT_TABLE, vpnId, internalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.SNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+
+
+    }
+
+    private void createDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpnId) {
+        FlowEntity pFlowEntity = buildPreDNATFlowEntity(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId );
+        mdsalManager.installFlow(pFlowEntity);
+
+        FlowEntity flowEntity = buildDNATFlowEntity(dpnId, internalIp, externalIp, routerId, associatedVpnId);
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId) {
+        FlowEntity pFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, internalIp, externalIp, routerId );
+        mdsalManager.removeFlow(pFlowEntity);
+
+        FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, externalIp, routerId);
+        mdsalManager.removeFlow(flowEntity);
+    }
+
+    private void createSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long vpnId, long routerId, String macAddress, long associatedVpnId) {
+        FlowEntity pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
+        mdsalManager.installFlow(pFlowEntity);
+
+        FlowEntity flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, macAddress);
+        mdsalManager.installFlow(flowEntity);
+
+    }
+
+    private void removeSNATTblEntry(BigInteger dpnId, String internalIp, long routerId, String externalIp, long vpnId) {
+        FlowEntity pFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId, externalIp);
+        mdsalManager.removeFlow(pFlowEntity);
+
+        FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, internalIp, vpnId, externalIp);
+        mdsalManager.removeFlow(flowEntity);
+
+    }
+
+    private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> pIdentifier) {
+        Optional<RouterPorts> rtrPort = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, pIdentifier);
+        if(!rtrPort.isPresent()) {
+            LOG.error("Unable to read router port entry for {}", pIdentifier);
+            return null;
+        }
+
+        Uuid extNwId = rtrPort.get().getExternalNetworkId();
+        return extNwId;
+    }
+
+    private long getVpnId(Uuid extNwId) {
+        InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class, new NetworksKey(extNwId)).build();
+        Optional<Networks> nw = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, nwId);
+        if(!nw.isPresent()) {
+            LOG.error("Unable to read external network for {}", extNwId);
+            return NatConstants.INVALID_ID;
+        }
+
+        Uuid vpnUuid = nw.get().getVpnid();
+        if(vpnUuid == null) {
+            return NatConstants.INVALID_ID;
+        }
+
+        //Get the id using the VPN UUID (also vpn instance name)
+        return NatUtil.readVpnId(broker, vpnUuid.getValue());
+    }
+
+    private void processFloatingIPAdd(final InstanceIdentifier<IpMapping> identifier,
+                                      final IpMapping mapping) {
+        LOG.trace("Add event - key: {}, value: {}", identifier, mapping);
+
+        final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
+        final PortsKey pKey = identifier.firstKeyOf(Ports.class);
+        String interfaceName = pKey.getPortName();
+
+        InstanceIdentifier<RouterPorts> pIdentifier = identifier.firstIdentifierOf(RouterPorts.class);
+        createNATFlowEntries(interfaceName, mapping, pIdentifier, routerId);
+    }
+
+    private void processFloatingIPDel(final InstanceIdentifier<IpMapping> identifier,
+                                      final IpMapping mapping) {
+        LOG.trace("Del event - key: {}, value: {}", identifier, mapping);
+
+        final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
+        final PortsKey pKey = identifier.firstKeyOf(Ports.class);
+        String interfaceName = pKey.getPortName();
+
+        InstanceIdentifier<RouterPorts> pIdentifier = identifier.firstIdentifierOf(RouterPorts.class);
+        removeNATFlowEntries(interfaceName, mapping, pIdentifier, routerId);
+    }
+
+    private InetAddress getInetAddress(String ipAddr) {
+        InetAddress ipAddress = null;
+        try {
+            ipAddress = InetAddress.getByName(ipAddr);
+        } catch (UnknownHostException e) {
+            LOG.error("UnknowHostException for ip {}", ipAddr);
+        }
+        return ipAddress;
+    }
+
+    private boolean validateIpMapping(IpMapping mapping) {
+        return getInetAddress(mapping.getInternalIp()) != null &&
+                    getInetAddress(mapping.getExternalIp()) != null;
+    }
+
+    void createNATFlowEntries(String interfaceName, final IpMapping mapping,
+                              final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName) {
+        if(!validateIpMapping(mapping)) {
+            LOG.warn("Not a valid ip addresses in the mapping {}", mapping);
+            return;
+        }
+
+        //Get the DPN on which this interface resides
+        BigInteger dpnId = getDpnForInterface(interfaceManager, interfaceName);
+
+        if(dpnId.equals(BigInteger.ZERO)) {
+             LOG.error("No DPN for interface {}. NAT flow entries for ip mapping {} will not be installed", 
+                     interfaceName, mapping);
+             return;
+        }
+
+        long routerId = NatUtil.getVpnId(broker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Could not retrieve router id for {} to create NAT Flow entries", routerName);
+            return;
+        }
+        //Check if the router to vpn association is present
+        //long associatedVpnId = NatUtil.getAssociatedVpn(broker, routerName);
+        Uuid associatedVpn = NatUtil.getVpnForRouter(broker, routerName);
+        long associatedVpnId = NatConstants.INVALID_ID;
+        if(associatedVpn == null) {
+            LOG.debug("Router {} is not assicated with any BGP VPN instance", routerName);
+        } else {
+            LOG.debug("Router {} is associated with VPN Instance with Id {}", routerName, associatedVpn);
+            associatedVpnId = NatUtil.getVpnId(broker, associatedVpn.getValue());
+            LOG.debug("vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
+            //routerId = associatedVpnId;
+        }
+
+        Uuid extNwId = getExtNetworkId(pIdentifier);
+        if(extNwId == null) {
+            LOG.error("External network associated with interface {} could not be retrieved", interfaceName);
+            LOG.error("NAT flow entries will not be installed {}", mapping);
+            return;
+        }
+        long vpnId = getVpnId(extNwId);
+        if(vpnId < 0) {
+            LOG.error("No VPN associated with Ext nw {}. Unable to create SNAT table entry for fixed ip {}", 
+                    extNwId, mapping.getInternalIp());
+            return;
+        }
+
+        //Create the DNAT and SNAT table entries
+        createDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId, vpnId, associatedVpnId);
+
+
+        String macAddr = getExternalGatewayMacAddress(routerName);
+        createSNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), vpnId, routerId, macAddr, associatedVpnId);
+
+        handler.onAddFloatingIp(dpnId, routerName, extNwId, interfaceName, mapping.getExternalIp(), mapping
+                .getInternalIp());
+    }
+
+    void createNATFlowEntries(BigInteger dpnId,  String interfaceName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
+        long routerId = NatUtil.getVpnId(broker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Could not retrieve router id for {} to create NAT Flow entries", routerName);
+            return;
+        }
+        //Check if the router to vpn association is present
+        long associatedVpnId = NatUtil.getAssociatedVpn(broker, routerName);
+        if(associatedVpnId == NatConstants.INVALID_ID) {
+            LOG.debug("Router {} is not assicated with any BGP VPN instance", routerName);
+        } else {
+            LOG.debug("Router {} is associated with VPN Instance with Id {}", routerName, associatedVpnId);
+            //routerId = associatedVpnId;
+        }
+        
+        long vpnId = getVpnId(externalNetworkId);
+        if(vpnId < 0) {
+            LOG.error("Unable to create SNAT table entry for fixed ip {}", internalIp);
+            return;
+        }
+        //Create the DNAT and SNAT table entries
+        createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId);
+
+        String macAddr = getExternalGatewayMacAddress(routerName);
+        createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, macAddr, associatedVpnId);
+
+        handler.onAddFloatingIp(dpnId, routerName, externalNetworkId, interfaceName, externalIp, internalIp);
+    }
+
+    void createNATOnlyFlowEntries(BigInteger dpnId,  String interfaceName, String routerName, String associatedVPN, Uuid externalNetworkId, String internalIp, String externalIp) {
+        //String segmentId = associatedVPN == null ? routerName : associatedVPN;
+        LOG.debug("Retrieving vpn id for VPN {} to proceed with create NAT Flows", routerName);
+        long routerId = NatUtil.getVpnId(broker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Could not retrieve vpn id for {} to create NAT Flow entries", routerName);
+            return;
+        }
+        long associatedVpnId = NatUtil.getVpnId(broker, associatedVPN);
+        LOG.debug("Associated VPN Id {} for router {}", associatedVpnId, routerName);
+        long vpnId = getVpnId(externalNetworkId);
+        if(vpnId < 0) {
+            LOG.error("Unable to create SNAT table entry for fixed ip {}", internalIp);
+            return;
+        }
+        //Create the DNAT and SNAT table entries
+        //createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId);
+        FlowEntity pFlowEntity = buildPreDNATFlowEntity(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId );
+        mdsalManager.installFlow(pFlowEntity);
+
+        FlowEntity flowEntity = buildDNATFlowEntity(dpnId, internalIp, externalIp, routerId, associatedVpnId);
+        mdsalManager.installFlow(flowEntity);
+
+        String macAddr = getExternalGatewayMacAddress(routerName);
+        //createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, macAddr);
+        pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
+        mdsalManager.installFlow(pFlowEntity);
+
+        flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, macAddr);
+        mdsalManager.installFlow(flowEntity);
+
+    }
+
+    private String getExternalGatewayMacAddress(String routerName) {
+        InstanceIdentifier<Routers> routersIdentifier = NatUtil.buildRouterIdentifier(routerName);
+        Optional<Routers> optRouters = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, routersIdentifier);
+        if(optRouters.isPresent()) {
+            Routers routers = optRouters.get();
+            return routers.getExtGwMacAddress();
+        }
+        return "";
+    }
+
+    void removeNATFlowEntries(String interfaceName, final IpMapping mapping,
+                              final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName) {
+
+        //Get the DPN on which this interface resides
+        BigInteger dpnId = getDpnForInterface(interfaceManager, interfaceName);
+        if(dpnId.equals(BigInteger.ZERO)) {
+            LOG.info("Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
+            return;
+        }
+
+        long routerId = NatUtil.getVpnId(broker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+            return;
+        }
+        //if(routerId == NatConstants.INVALID_ID) {
+        //The router could be associated with BGP VPN
+        Uuid associatedVPN = NatUtil.getVpnForRouter(broker, routerName);
+        long associatedVpnId = NatConstants.INVALID_ID;
+        if(associatedVPN == null) {
+            LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+        } else {
+            LOG.debug("Retrieving vpn id for VPN {} to proceed with remove NAT Flows", associatedVPN.getValue());
+            associatedVpnId = NatUtil.getVpnId(broker, associatedVPN.getValue());
+        }
+
+        //Delete the DNAT and SNAT table entries
+        removeDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId);
+
+        Uuid extNwId = getExtNetworkId(pIdentifier);
+        if(extNwId == null) {
+            LOG.error("External network associated with interface {} could not be retrieved", interfaceName);
+            return;
+        }
+        long vpnId = getVpnId(extNwId);
+        if(vpnId < 0) {
+            LOG.error("No VPN associated with ext nw {}. Unable to delete SNAT table entry for fixed ip {}", 
+                    extNwId, mapping.getInternalIp());
+            return;
+        }
+        removeSNATTblEntry(dpnId, mapping.getInternalIp(), routerId, mapping.getExternalIp(), vpnId);
+
+        long label = getOperationalIpMapping(routerName, interfaceName, mapping.getInternalIp());
+        if(label < 0) {
+            LOG.error("Could not retrieve label for prefix {} in router {}", mapping.getInternalIp(), routerId);
+            return;
+        }
+        //Uuid extNwId = getExtNetworkId(pIdentifier);
+//        Uuid extNwId = getExternalNetworkForRouter(routerName);
+//        if(extNwId == null) {
+//            LOG.error("External network associated with router {} could not be retrieved", routerName);
+//            return;
+//        }
+        handler.onRemoveFloatingIp(dpnId, routerName, extNwId, mapping.getExternalIp(), mapping.getInternalIp(), (int) label);
+        removeOperationalDS(routerName, interfaceName, mapping.getInternalIp(), mapping.getExternalIp());
+
+    }
+
+    void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
+        long routerId = NatUtil.getVpnId(broker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+            return;
+        }
+
+        long vpnId = NatUtil.getVpnId(broker, vpnName);
+        if(vpnId == NatConstants.INVALID_ID) {
+            LOG.warn("VPN Id not found for {} to remove NAT flow entries {}", vpnName, internalIp);
+        }
+
+        //Delete the DNAT and SNAT table entries
+        removeDNATTblEntry(dpnId, internalIp, externalIp, routerId);
+
+        removeSNATTblEntry(dpnId, internalIp, routerId, externalIp, vpnId);
+
+        long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
+        if(label < 0) {
+            LOG.error("Could not retrieve label for prefix {} in router {}", internalIp, routerId);
+            return;
+        }
+        //handler.onRemoveFloatingIp(dpnId, routerName, externalNetworkId, externalIp, internalIp, (int)label);
+        ((VpnFloatingIpHandler)handler).cleanupFibEntries(dpnId, vpnName, externalIp, label);
+        removeOperationalDS(routerName, interfaceName, internalIp, externalIp);
+    }
+
+    void removeNATOnlyFlowEntries(BigInteger dpnId, String interfaceName, String routerName, String associatedVPN,
+                                                                          String internalIp, String externalIp) {
+        String segmentId = associatedVPN == null ? routerName : associatedVPN;
+        LOG.debug("Retrieving vpn id for VPN {} to proceed with remove NAT Flows", segmentId);
+        long routerId = NatUtil.getVpnId(broker, segmentId);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Could not retrieve vpn id for {} to remove NAT Flow entries", segmentId);
+            return;
+        }
+        //Delete the DNAT and SNAT table entries
+        removeDNATTblEntry(dpnId, internalIp, externalIp, routerId);
+
+        //removeSNATTblEntry(dpnId, internalIp, routerId, externalIp);
+    }
+
+    private long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
+        InstanceIdentifier<IpMapping> ipMappingIdentifier = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
+        Optional<IpMapping> ipMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, ipMappingIdentifier);
+        if(ipMapping.isPresent()) {
+            return ipMapping.get().getLabel();
+        }
+        return NatConstants.INVALID_ID;
+    }
+
+    private Uuid getExternalNetworkForRouter(String routerId) {
+        InstanceIdentifier<RouterPorts> identifier = NatUtil.getRouterPortsId(routerId);
+        Optional<RouterPorts> optRouterPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+        if(optRouterPorts.isPresent()) {
+            RouterPorts routerPorts = optRouterPorts.get();
+            return routerPorts.getExternalNetworkId();
+        }
+        return null;
+    }
+
+    void updateOperationalDS(String routerId, String interfaceName, int label, String internalIp, String externalIp) {
+
+        LOG.info("Updating operational DS for floating ip config : {} with label {}", internalIp, label);
+        InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
+        Optional<Ports> optPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portsId);
+        IpMapping ipMapping = new IpMappingBuilder().setKey(new IpMappingKey(internalIp)).setInternalIp(internalIp)
+                .setExternalIp(externalIp).setLabel(label).build();
+        if(optPorts.isPresent()) {
+            LOG.debug("Ports {} entry already present. Updating ipmapping for internal ip {}", interfaceName, internalIp);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portsId.child(IpMapping.class, new IpMappingKey(internalIp)), ipMapping);
+        } else {
+            LOG.debug("Adding Ports entry {} along with ipmapping {}", interfaceName, internalIp);
+            List<IpMapping> ipMappings = new ArrayList<>();
+            ipMappings.add(ipMapping);
+            Ports ports = new PortsBuilder().setKey(new PortsKey(interfaceName)).setPortName(interfaceName).setIpMapping(ipMappings).build();
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
+        }
+    }
+
+    void removeOperationalDS(String routerId, String interfaceName, String internalIp, String externalIp) {
+        LOG.info("Remove operational DS for floating ip config: {}", internalIp);
+        InstanceIdentifier<IpMapping> ipMappingId = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, ipMappingId);
+    }
+
+    private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
+
+        LOG.info("Bulding Delete DNAT Flow entity for ip {} ", externalIp);
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PDNAT_TABLE, routerId, externalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PDNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+        return flowEntity;
+    }
+
+
+
+    private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
+
+        LOG.info("Bulding Delete DNAT Flow entity for ip {} ", externalIp);
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.DNAT_TABLE, routerId, externalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.DNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+        return flowEntity;
+
+    }
+
+    private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId, String externalIp) {
+
+        LOG.info("Building Delete PSNAT Flow entity for ip {} ", internalIp);
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PSNAT_TABLE, routerId, internalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+        return flowEntity;
+    }
+
+    private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId, String externalIp) {
+
+        LOG.info("Building Delete SNAT Flow entity for ip {} ", internalIp);
+
+        String flowRef = NatUtil.getFlowRef(dpId, NatConstants.SNAT_TABLE, routerId, internalIp);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.SNAT_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+        return flowEntity;
+
+
+    }
+}
+
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/IPAddress.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/IPAddress.java
new file mode 100644 (file)
index 0000000..fd8698c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+public class IPAddress {
+
+    private String ipAddress;
+    private int prefixLength;
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+    public int getPrefixLength() {
+        return prefixLength;
+    }
+
+    public IPAddress(String ipAddress, int prefixLength) {
+        this.ipAddress = ipAddress;
+        this.prefixLength = prefixLength;
+    }
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/InterfaceStateEventListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/InterfaceStateEventListener.java
new file mode 100644 (file)
index 0000000..169e452
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import com.google.common.collect.Lists;
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+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.vpnservice.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ProtocolTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+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.base.Optional;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class InterfaceStateEventListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateEventListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker dataBroker;
+    private IMdsalApiManager mdsalManager;
+    private FloatingIPListener floatingIPListener;
+    private NaptManager naptManager;
+    private NeutronvpnService neutronVpnService;
+
+    public InterfaceStateEventListener(final DataBroker db){
+        super(Interface.class);
+        dataBroker = db;
+        registerListener(db);
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setFloatingIpListener(FloatingIPListener floatingIPListener) {
+        this.floatingIPListener = floatingIPListener;
+    }
+
+    public void setNeutronVpnService(NeutronvpnService neutronVpnService) {
+        this.neutronVpnService = neutronVpnService;
+    }
+
+    public void setNaptManager(NaptManager naptManager) {
+        this.naptManager = naptManager;
+
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), InterfaceStateEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("Interface DataChange listener registration failed", e);
+            throw new IllegalStateException("Nexthop Manager registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface delintrf) {
+        LOG.trace("NAT Service : Interface {} removed event received", delintrf);
+        try {
+            if (delintrf != null) {
+                String interfaceName = delintrf.getName();
+                LOG.trace("NAT Service : Port removed event received for interface {} ", interfaceName);
+
+                BigInteger dpnId = NatUtil.getDpIdFromInterface(delintrf);
+                LOG.trace("NAT Service : PORT_REMOVE: Interface {} down in Dpn {}", interfaceName, dpnId);
+
+                String routerName = getRouterIdForPort(dataBroker, interfaceName);
+                if (routerName != null) {
+                    processInterfaceRemoved(interfaceName, routerName);
+                    removeSnatEntriesForPort(interfaceName,routerName);
+                } else {
+                    LOG.debug("NAT Service : PORT_REMOVE: Router Id is null either Interface {} is not associated " +
+                                "to router or failed to retrieve routerId due to exception", interfaceName);
+                }
+            }
+        } catch(Exception e) {
+            LOG.error("NAT Service : Exception caught in InterfaceOperationalStateRemove : {}", e);
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+        LOG.trace("NAT Service : Operation Interface update event - Old: {}, New: {}", original, update);
+        String interfaceName = update.getName();
+        if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
+            LOG.trace("NAT Service : Port UP event received for interface {} ", interfaceName);
+        } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
+            try {
+                LOG.trace("NAT Service : Port DOWN event received for interface {} ", interfaceName);
+
+                BigInteger dpnId = NatUtil.getDpIdFromInterface(update);
+                LOG.trace("NAT Service : PORT_DOWN: Interface {} down in Dpn {}", interfaceName, dpnId);
+
+                String routerName = getRouterIdForPort(dataBroker, interfaceName);
+                if (routerName != null) {
+                    removeSnatEntriesForPort(interfaceName,routerName);
+                } else {
+                    LOG.debug("NAT Service : PORT_DOWN: Router Id is null, either Interface {} is not associated " +
+                            "to router or failed to retrieve routerId due to exception", interfaceName);
+                }
+            } catch (Exception ex) {
+                LOG.error("NAT Service : Exception caught in InterfaceOperationalStateDown : {}",ex);
+            }
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
+        LOG.trace("NAT Service : Interface {} up event received", intrf);
+        try {
+            String interfaceName = intrf.getName();
+            LOG.trace("NAT Service : Port added event received for interface {} ", interfaceName);
+            String routerId = getRouterIdForPort(dataBroker,interfaceName);
+            if (routerId != null) {
+                processInterfaceAdded(interfaceName, routerId);
+            }
+        } catch (Exception ex) {
+        LOG.error("NAT Service : Exception caught in Interface Operational State Up event: {}", ex);
+        }
+    }
+
+    private void removeSnatEntriesForPort(String interfaceName,String routerName) {
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("NAT Service : routerId not found for routername {}",routerName);
+            return;
+        }
+        BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker,routerName);
+        if (naptSwitch == null) {
+            LOG.error("NAT Service : NaptSwitch is not elected for router {} with Id {}",routerName,routerId);
+            return;
+        }
+        //getInternalIp for port
+        List<String> fixedIps = getFixedIpsForPort(interfaceName);
+        if (fixedIps == null) {
+            LOG.debug("NAT Service : Internal Ips not found for InterfaceName {} in router {} with id {}",interfaceName,routerName,routerId);
+            return;
+        }
+        List<ProtocolTypes> protocolTypesList = getPortocolList();
+        for (String internalIp : fixedIps) {
+            LOG.debug("NAT Service : Internal Ip retrieved for interface {} is {} in router with Id {}",interfaceName,internalIp,routerId);
+            for(ProtocolTypes protocol : protocolTypesList) {
+                List<Integer> portList = NatUtil.getInternalIpPortListInfo(dataBroker, routerId, internalIp, protocol);
+                if (portList != null) {
+                    for (Integer portnum : portList) {
+                        //build and remove the flow in outbound table
+                        try {
+                            removeNatFlow(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum);
+                        } catch (Exception ex) {
+                            LOG.error("NAT Service : Failed to remove snat flow for internalIP {} with Port {} protocol {} for routerId {} " +
+                                    "in OUTBOUNDTABLE of NaptSwitch {}: {}",internalIp,portnum,protocol,routerId,naptSwitch,ex);
+                        }
+                        //Get the external IP address and the port from the model
+                        NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString()) ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
+                        IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
+                                internalIp, String.valueOf(portnum), proto);
+                        if (ipPortExternal == null) {
+                            LOG.error("Mapping for internalIp {} with port {} is not found in router with Id {}",internalIp,portnum,routerId);
+                            return;
+                        }
+                        String externalIpAddress = ipPortExternal.getIpAddress();
+                        Integer portNumber = ipPortExternal.getPortNum();
+
+                        //build and remove the flow in inboundtable
+                        try {
+                            removeNatFlow(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,routerId, externalIpAddress, portNumber);
+                        } catch (Exception ex) {
+                            LOG.error("NAT Service : Failed to remove snat flow internalIP {} with Port {} protocol {} for routerId {} " +
+                                    "in INBOUNDTABLE of naptSwitch {} : {}",externalIpAddress,portNumber,protocol,routerId,naptSwitch,ex);
+                        }
+
+                        String internalIpPort = internalIp + ":" + portnum;
+                        // delete the entry from IntExtIpPortMap DS
+                        try {
+                            naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
+                            naptManager.removePortFromPool(internalIpPort,externalIpAddress);
+                        } catch (Exception ex){
+                            LOG.error("NAPT Service : releaseIpExtPortMapping failed, Removal of ipportmap {} for router {} failed {}" ,
+                                    internalIpPort, routerId, ex);
+                        }
+                    }
+                    // delete the entry from SnatIntIpPortMap DS
+                    LOG.debug("NAT Service : Removing InternalIp :{} portlist :{} for protocol :{} of router {}",internalIp,portList,protocol,routerId);
+                    naptManager.removeFromSnatIpPortDS(routerId,internalIp);
+                } else {
+                    LOG.debug("NAT Service : No {} session for interface {} with internalIP {} in router with id {}",protocol,interfaceName,internalIp,routerId);
+                }
+            }
+        }
+    }
+
+    private String getRouterIdForPort(DataBroker dataBroker,String interfaceName) {
+        String vpnName = null, routerName = null;
+        if (NatUtil.isVpnInterfaceConfigured(dataBroker, interfaceName)) {
+            //getVpnInterface
+            VpnInterface vpnInterface = null;
+            try {
+                vpnInterface = NatUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
+            } catch (Exception ex) {
+                LOG.error("NAT Service : Unable to process for interface {} as it is not configured", interfaceName);
+            }
+            if (vpnInterface != null) {
+                //getVpnName
+                try {
+                    vpnName = vpnInterface.getVpnInstanceName();
+                    LOG.debug("NAT Service : Retrieved VpnName {}", vpnName);
+                } catch (Exception e) {
+                    LOG.error("NAT Service : Unable to get vpnname for vpninterface {} - {}", vpnInterface, e);
+                }
+                if (vpnName != null) {
+                    try {
+                        routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+                    } catch (Exception e) {
+                        LOG.error("NAT Service : Unable to get routerId for vpnName {} - {}", vpnName, e);
+                    }
+                    if (routerName != null) {
+                        //check router is associated to external network
+                        if (NatUtil.isSnatEnabledForRouterId(dataBroker, routerName)) {
+                            LOG.debug("NAT Service : Retreived Router Id {} for vpnname {} associated to interface {}",
+                                    routerName,vpnName,interfaceName);
+                            return routerName;
+                        } else {
+                            LOG.info("NAT Service : Interface {} associated to routerId {} is not associated to external network",
+                                    interfaceName, routerName);
+                        }
+                    } else {
+                        LOG.debug("Router is not associated to vpnname {} for interface {}",vpnName,interfaceName);
+                    }
+                } else {
+                    LOG.debug("NAT Service : vpnName not found for vpnInterface {} of port {}",vpnInterface,interfaceName);
+                }
+            }
+        } else {
+            LOG.debug("NAT Service : Interface {} is not a vpninterface",interfaceName);
+        }
+        return null;
+    }
+
+    private List<ProtocolTypes> getPortocolList() {
+        List<ProtocolTypes> protocollist = Lists.newArrayList();
+        protocollist.add(ProtocolTypes.TCP);
+        protocollist.add(ProtocolTypes.UDP);
+        return protocollist;
+    }
+
+    private BigInteger getNaptSwitchforRouter(DataBroker broker,String routerName) {
+        InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class).child
+                (RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+        Optional<RouterToNaptSwitch> routerToNaptSwitchData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, rtrNaptSw);
+        if (routerToNaptSwitchData.isPresent()) {
+            RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
+            return routerToNaptSwitchInstance.getPrimarySwitchId();
+        }
+        return null;
+    }
+
+    private void removeNatFlow(BigInteger dpnId, short tableId,Long routerId, String ipAddress,int ipPort) {
+
+        String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
+        FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+
+        mdsalManager.removeFlow(snatFlowEntity);
+        LOG.debug("NAT Service : Removed the flow in table {} for the switch with the DPN ID {} for router {} ip {} port {}",
+                tableId,dpnId,routerId,ipAddress,ipPort);
+    }
+
+    private void processInterfaceAdded(String portName, String rtrId) {
+        LOG.trace("Processing Interface Add Event for interface {}", portName);
+        String routerId = getRouterIdForPort(dataBroker, portName);
+        List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
+        if (ipMappingList == null || ipMappingList.isEmpty()) {
+            LOG.trace("Ip Mapping list is empty/null for portname {}", portName);
+            return;
+        }
+        InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
+        for (IpMapping ipMapping : ipMappingList) {
+            floatingIPListener.createNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
+        }
+    }
+
+    private void processInterfaceRemoved(String portName, String rtrId) {
+        LOG.trace("Processing Interface Removed Event for interface {}", portName);
+        String routerId = getRouterIdForPort(dataBroker, portName);
+        List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
+        if (ipMappingList == null || ipMappingList.isEmpty()) {
+            LOG.trace("Ip Mapping list is empty/null for portName {}", portName);
+            return;
+        }
+        InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
+        for (IpMapping ipMapping : ipMappingList) {
+            floatingIPListener.removeNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
+        }
+    }
+
+    private List<IpMapping> getIpMappingForPortName(String portName, String routerId) {
+        InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
+        Optional<Ports> port = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier);
+        if(!port.isPresent()) {
+            LOG.error("NAT Service : Unable to read router port entry for router ID {} and port name {}", routerId, portName);
+            return null;
+        }
+        List<IpMapping> ipMappingList = port.get().getIpMapping();
+        return ipMappingList;
+    }
+
+    private List<String> getFixedIpsForPort (String interfname) {
+        LOG.debug("getFixedIpsForPort method is called for interface {}",interfname);
+        try {
+            Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
+                    neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
+                            .setPortId(new Uuid(interfname)).build());
+
+            RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                LOG.warn("NAT Service : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}", rpcResult.getErrors());
+            } else {
+                return rpcResult.getResult().getFixedIPs();
+            }
+        } catch (InterruptedException | ExecutionException | NullPointerException ex ) {
+            LOG.error("NAT Service : Exception while receiving fixedIps for port {}",interfname);
+        }
+        return null;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("NAT Service : Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("NAT Service : Interface listener Closed");
+    }
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTEntryEvent.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTEntryEvent.java
new file mode 100644 (file)
index 0000000..8a16f7c
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+
+public class NAPTEntryEvent {
+    private String ipAddress;
+    private int portNumber;
+    private Long routerId;
+    private Operation op;
+    private Protocol protocol;
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public int getPortNumber() {
+        return portNumber;
+    }
+
+    public Long getRouterId() {
+        return routerId;
+    }
+
+    public Operation getOperation() {
+        return op;
+    }
+
+    public Protocol getProtocol() {
+        return protocol;
+    }
+
+    NAPTEntryEvent(String ipAddress, int portNumber, Long routerId, Operation op, Protocol protocol){
+        this.ipAddress = ipAddress;
+        this.portNumber = portNumber;
+        this.routerId = routerId;
+        this.op = op;
+        this.protocol = protocol;
+    }
+
+    public enum Operation{
+        ADD, DELETE;
+    }
+
+    public enum Protocol{
+        TCP, UDP;
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTSwitchSelector.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NAPTSwitchSelector.java
new file mode 100644 (file)
index 0000000..682911c
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExtRouters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class NAPTSwitchSelector {
+    private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
+
+    private DataBroker dataBroker;
+    public NAPTSwitchSelector(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    BigInteger selectNewNAPTSwitch(String routerName) {
+        LOG.info("NAT Service : Select a new NAPT switch for router {}", routerName);
+        Map<BigInteger, Integer> naptSwitchWeights = constructNAPTSwitches();
+        List<BigInteger> routerSwitches = getDpnsForVpn(routerName);
+        if(routerSwitches == null || routerSwitches.isEmpty()) {
+            LOG.debug("NAT Service : No switches are part of router {}", routerName);
+            LOG.error("NAT Service : NAPT SWITCH SELECTION STOPPED DUE TO NO DPNS SCENARIO FOR ROUTER {}", routerName);
+            return BigInteger.ZERO;
+        }
+
+        Set<SwitchWeight> switchWeights = new TreeSet<>();
+        for(BigInteger dpn : routerSwitches) {
+            if(naptSwitchWeights.get(dpn) != null) {
+                switchWeights.add(new SwitchWeight(dpn, naptSwitchWeights.get(dpn)));
+            } else {
+                switchWeights.add(new SwitchWeight(dpn, 0));
+            }
+        }
+
+        BigInteger primarySwitch;
+
+        if(!switchWeights.isEmpty()) {
+
+            LOG.debug("NAT Service : Current switch weights for router {} - {}", routerName, switchWeights);
+
+            Iterator<SwitchWeight> it = switchWeights.iterator();
+            RouterToNaptSwitchBuilder routerToNaptSwitchBuilder = new RouterToNaptSwitchBuilder().setRouterName(routerName);
+            if ( switchWeights.size() == 1 )
+            {
+                SwitchWeight singleSwitchWeight = null;
+                while(it.hasNext() ) {
+                    singleSwitchWeight = it.next();
+                }
+                primarySwitch = singleSwitchWeight.getSwitch();
+                RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
+                
+                MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
+
+                LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container for single switch" );
+                return primarySwitch;
+            }
+            else
+            {
+                SwitchWeight firstSwitchWeight = null;
+                while(it.hasNext() ) {
+                    firstSwitchWeight = it.next();
+                }
+                primarySwitch = firstSwitchWeight.getSwitch();
+                RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
+                
+                MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
+
+                LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container");
+                return primarySwitch;
+            }
+        } else {
+
+                primarySwitch = BigInteger.ZERO;
+
+                LOG.debug("NAT Service : switchWeights empty, primarySwitch: {} ", primarySwitch);
+                return primarySwitch;
+        }
+
+
+    }
+
+    private Map<BigInteger, Integer> constructNAPTSwitches() {
+        Optional<NaptSwitches> optNaptSwitches = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
+        Map<BigInteger, Integer> switchWeights = new HashMap<>();
+
+        if(optNaptSwitches.isPresent()) {
+            NaptSwitches naptSwitches = optNaptSwitches.get();
+            List<RouterToNaptSwitch> routerToNaptSwitches = naptSwitches.getRouterToNaptSwitch();
+
+            for(RouterToNaptSwitch naptSwitch : routerToNaptSwitches) {
+                BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
+                //update weight
+                Integer weight = switchWeights.get(primarySwitch);
+                if(weight == null) {
+                    switchWeights.put(primarySwitch, 1);
+                } else {
+                    switchWeights.put(primarySwitch, ++weight);
+                }
+            }
+        }
+        return switchWeights;
+    }
+
+    private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
+        return InstanceIdentifier.create(NaptSwitches.class);
+    }
+
+    private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
+        return InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+    }
+
+    public List<BigInteger> getDpnsForVpn(String routerName ) {
+        LOG.debug( "NAT Service : getVpnToDpnList called for RouterName {}", routerName );
+        long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
+        if(bgpVpnId != NatConstants.INVALID_ID){
+            return NatUtil.getDpnsForRouter(dataBroker, routerName);
+        }
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(routerName))
+                .build();
+
+        List<BigInteger> dpnsInVpn = new ArrayList<>();
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+
+        if(vpnInstanceOpData.isPresent()) {
+            LOG.debug( "NAT Service : getVpnToDpnList able to fetch vpnInstanceOpData" );
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpData.get();
+            List<VpnToDpnList> vpnDpnList = vpnInstanceOpDataEntry.getVpnToDpnList();
+            if(vpnDpnList != null) {
+                for(VpnToDpnList vpnToDpn: vpnDpnList) {
+                    dpnsInVpn.add(vpnToDpn.getDpnId());
+                }
+            }
+        }
+
+        if(dpnsInVpn == null || dpnsInVpn.isEmpty()) {
+            LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
+            dpnsInVpn = NatUtil.getDpnsForRouter(dataBroker, routerName);
+            if(dpnsInVpn == null || dpnsInVpn.isEmpty()){
+                LOG.debug("NAT Service : No switches are part of router {}", routerName);
+                return dpnsInVpn;
+            }
+        }
+
+        LOG.debug( "NAT Service : getVpnToDpnList returning vpnDpnList {}", dpnsInVpn);
+        return dpnsInVpn;
+
+
+    }
+
+    private static class SwitchWeight implements Comparable<SwitchWeight>
+    {
+        private BigInteger swich;
+        private int weight;
+
+        public SwitchWeight( BigInteger swich, int weight )
+        {
+            this.swich = swich;
+            this.weight = weight;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((swich == null) ? 0 : swich.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;
+            SwitchWeight other = (SwitchWeight) obj;
+            if (swich == null) {
+                if (other.swich != null)
+                    return false;
+            } else if (!swich.equals(other.swich))
+                return false;
+            return true;
+        }
+
+        public BigInteger getSwitch() {
+            return swich;
+        }
+
+        public int getWeight() { 
+            return weight;
+        }
+
+        public void incrementWeight() {
+            ++ weight;
+        }
+
+        @Override
+        public int compareTo(SwitchWeight o) {
+            return o.getWeight() - weight;
+        }
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptEventHandler.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptEventHandler.java
new file mode 100644 (file)
index 0000000..3191ebb
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.ArrayList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NaptEventHandler {
+    private NaptManager naptManager;
+    private static final Logger LOG = LoggerFactory.getLogger(NaptEventHandler.class);
+    private static IMdsalApiManager mdsalManager;
+    private DataBroker dataBroker;
+
+    public NaptEventHandler(final DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setNaptManager(NaptManager naptManager) {
+        this.naptManager = naptManager;
+    }
+
+
+    public void handleEvent(NAPTEntryEvent naptEntryEvent){
+    /*
+            Flow programming logic of the OUTBOUND NAPT TABLE :
+            1) Get the internal IP address, port number, router ID from the event.
+            2) Use the NAPT service getExternalAddressMapping() to get the External IP and the port.
+            3) Build the flow for replacing the Internal IP and port with the External IP and port.
+              a) Write the matching criteria.
+              b) Match the router ID in the metadata.
+              d) Write the VPN ID to the metadata.
+              e) Write the other data.
+              f) Set the apply actions instruction with the action setfield.
+            4) Write the flow to the OUTBOUND NAPT Table and forward to FIB table for routing the traffic.
+
+            Flow programming logic of the INBOUND NAPT TABLE :
+            Same as Outbound table logic except that :
+            1) Build the flow for replacing the External IP and port with the Internal IP and port.
+            2) Match the VPN ID in the metadata.
+            3) Write the router ID to the metadata.
+            5) Write the flow to the INBOUND NAPT Table and forward to FIB table for routing the traffic.
+    */
+        Long routerId = naptEntryEvent.getRouterId();
+        LOG.info("NAT Service : handleEvent() entry for IP {}, port {}, routerID {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+
+        //Get the DPN ID
+        BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+        long bgpVpnId = NatConstants.INVALID_ID;
+        if(dpnId == null ){
+            LOG.warn("NAT Service : dpnId is null. Assuming the router ID {} as the BGP VPN ID and proceeding....", routerId);
+            bgpVpnId = routerId;
+            LOG.debug("NAT Service : BGP VPN ID {}", bgpVpnId);
+            String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
+            String routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+            routerId = NatUtil.getVpnId(dataBroker, routerName);
+            LOG.debug("NAT Service : Router ID {}", routerId);
+            dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+            if(dpnId == null){
+                LOG.error("NAT Service : dpnId is null for the router {}", routerId);
+                return;
+            }
+        }
+        if(naptEntryEvent.getOperation() == NAPTEntryEvent.Operation.ADD) {
+            LOG.debug("NAT Service : Inside Add operation of NaptEventHandler");
+
+            //Get the external network ID from the ExternalRouter model
+            Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+            if(networkId == null ){
+                LOG.error("NAT Service : networkId is null");
+                return;
+            }
+
+            //Get the VPN ID from the ExternalNetworks model
+            Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+            if(vpnUuid == null ){
+                LOG.error("NAT Service : vpnUuid is null");
+                return;
+            }
+            Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+
+            //Get the internal IpAddress, internal port number from the event
+            String internalIpAddress = naptEntryEvent.getIpAddress();
+            int internalPort = naptEntryEvent.getPortNumber();
+            SessionAddress internalAddress = new SessionAddress(internalIpAddress, internalPort);
+            NAPTEntryEvent.Protocol protocol = naptEntryEvent.getProtocol();
+
+            //Get the external IP address for the corresponding internal IP address
+            SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, naptEntryEvent.getProtocol());
+            if(externalAddress == null ){
+                if(externalAddress == null){
+                    LOG.error("NAT Service : externalAddress is null");
+                    return;
+                }
+            }
+            //Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
+            buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, internalAddress, externalAddress, protocol);
+            buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, externalAddress, internalAddress, protocol);
+
+        }else{
+            LOG.debug("NAT Service : Inside delete Operation of NaptEventHandler");
+            removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
+        }
+
+        LOG.info("NAT Service : handleNaptEvent() exited for IP, port, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+    }
+
+    public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId, long bgpVpnId, SessionAddress actualSourceAddress,
+                                         SessionAddress translatedSourceAddress, NAPTEntryEvent.Protocol protocol){
+        LOG.debug("NAT Service : Build and install NAPT flows in InBound and OutBound tables for dpnId {} and routerId {}", dpnId, routerId);
+        //Build the flow for replacing the actual IP and port with the translated IP and port.
+        String actualIp = actualSourceAddress.getIpAddress();
+        int actualPort = actualSourceAddress.getPortNumber();
+        String translatedIp = translatedSourceAddress.getIpAddress();
+        String translatedPort = String.valueOf(translatedSourceAddress.getPortNumber());
+        int idleTimeout=0;
+        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+            idleTimeout = NatConstants.DEFAULT_NAPT_IDLE_TIMEOUT;
+        }
+        long metaDataValue = routerId;
+        String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(metaDataValue), actualIp, actualPort);
+
+        long intranetVpnId;
+        if(bgpVpnId != NatConstants.INVALID_ID){
+            intranetVpnId = bgpVpnId;
+        }else{
+            intranetVpnId = routerId;
+        }
+        LOG.debug("NAT Service : Intranet VPN ID {}", intranetVpnId);
+        LOG.debug("NAT Service : Router ID {}", routerId);
+        FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef, NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME,
+                idleTimeout, 0, NatUtil.getCookieNaptFlow(metaDataValue), buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
+                buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId, protocol));
+
+        snatFlowEntity.setSendFlowRemFlag(true);
+
+        LOG.debug("NAT Service : Installing the NAPT flow in the table {} for the switch with the DPN ID {} ", tableId, dpnId);
+        mdsalManager.installFlow(snatFlowEntity);
+    }
+
+    private static List<MatchInfo> buildAndGetMatchInfo(String ip, int port, short tableId, NAPTEntryEvent.Protocol protocol, long segmentId, long vpnId){
+        MatchInfo ipMatchInfo = null;
+        MatchInfo portMatchInfo = null;
+        MatchInfo protocolMatchInfo = null;
+        InetAddress ipAddress = null;
+        String ipAddressAsString = null;
+        try {
+            ipAddress = InetAddress.getByName(ip);
+            ipAddressAsString = ipAddress.getHostAddress();
+
+        } catch (UnknownHostException e) {
+            LOG.error("NAT Service : UnknowHostException in buildAndGetMatchInfo. Failed  to build NAPT Flow for  ip {}", ipAddress);
+            return null;
+        }
+
+        MatchInfo metaDataMatchInfo = null;
+        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+            ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_source, new String[] {ipAddressAsString, "32" });
+            if(protocol == NAPTEntryEvent.Protocol.TCP) {
+                protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
+                portMatchInfo = new MatchInfo(MatchFieldType.tcp_src, new long[]{port});
+            } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+                protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
+                portMatchInfo = new MatchInfo(MatchFieldType.udp_src, new long[]{port});
+            }
+            metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID});
+        }else{
+            ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });         
+            if(protocol == NAPTEntryEvent.Protocol.TCP) {
+                protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
+                portMatchInfo = new MatchInfo(MatchFieldType.tcp_dst, new long[]{port});
+            } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+                protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
+                portMatchInfo = new MatchInfo(MatchFieldType.udp_dst, new long[]{port});
+            }
+            //metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID});
+        }
+        ArrayList<MatchInfo> matchInfo = new ArrayList<>();
+        matchInfo.add(new MatchInfo(MatchFieldType.eth_type, new long[] { 0x0800L }));
+        matchInfo.add(ipMatchInfo);
+        matchInfo.add(protocolMatchInfo);
+        matchInfo.add(portMatchInfo);
+        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+            matchInfo.add(metaDataMatchInfo);
+        }
+        return matchInfo;
+    }
+
+    private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, String port, long segmentId, long vpnId, short tableId, NAPTEntryEvent.Protocol protocol) {
+        ActionInfo ipActionInfo = null;
+        ActionInfo portActionInfo = null;
+        ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+        ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+
+        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+            ipActionInfo = new ActionInfo(ActionType.set_source_ip, new String[] {ipAddress});
+            if(protocol == NAPTEntryEvent.Protocol.TCP) {
+               portActionInfo = new ActionInfo( ActionType.set_tcp_source_port, new String[] {port});
+            } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+               portActionInfo = new ActionInfo( ActionType.set_udp_source_port, new String[] {port});
+            }
+            instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID}));
+        }else{
+            ipActionInfo = new ActionInfo(ActionType.set_destination_ip, new String[] {ipAddress});
+            if(protocol == NAPTEntryEvent.Protocol.TCP) {
+               portActionInfo = new ActionInfo( ActionType.set_tcp_destination_port, new String[] {port});
+            } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+               portActionInfo = new ActionInfo( ActionType.set_udp_destination_port, new String[] {port});
+            }
+            instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID}));
+        }
+
+        listActionInfo.add(ipActionInfo);
+        listActionInfo.add(portActionInfo);
+
+        instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
+        instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.NAPT_PFIB_TABLE }));
+
+        return instructionInfo;
+    }
+
+    void removeNatFlows(BigInteger dpnId, short tableId ,long segmentId, String ip, int port){
+        if(dpnId == null || dpnId.equals(BigInteger.ZERO)){
+            LOG.error("NAT Service : DPN ID {} is invalid" , dpnId);
+        }
+        LOG.debug("NAT Service : Remove NAPT flows for dpnId {}, segmentId {}, ip {} and port {} ", dpnId, segmentId, ip, port);
+
+        //Build the flow with the port IP and port as the match info.
+        String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(segmentId), ip, port);
+        FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+        LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NatConstants.INBOUND_NAPT_TABLE, dpnId);
+        mdsalManager.removeFlow(snatFlowEntity);
+
+    }
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java
new file mode 100644 (file)
index 0000000..6e2722a
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.RemovedReasonFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+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.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.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import java.math.BigInteger;
+
+public class NaptFlowRemovedEventHandler implements SalFlowListener{
+    private DataBroker dataBroker;
+    private final EventDispatcher naptEventdispatcher;
+    private static final Logger LOG = LoggerFactory.getLogger(NaptFlowRemovedEventHandler.class);
+    private final NaptPacketInHandler naptPacketInHandler;
+    private IMdsalApiManager mdsalManager;
+    private NaptManager naptManager;
+
+    public NaptFlowRemovedEventHandler(EventDispatcher eventDispatcher, DataBroker dataBroker, NaptPacketInHandler handler,
+                                       IMdsalApiManager mdsalManager, NaptManager naptManager) {
+        this.naptEventdispatcher = eventDispatcher;
+        this.dataBroker = dataBroker;
+        this.naptPacketInHandler = handler;
+        this.mdsalManager = mdsalManager;
+        this.naptManager = naptManager;
+    }
+
+    @Override
+    public void onSwitchFlowRemoved(SwitchFlowRemoved switchFlowRemoved) {
+
+/*
+        If the removed flow is from the OUTBOUND NAPT table :
+        1) Get the ActionInfo of the flow.
+        2) From the ActionInfo of the flow get the internal IP address, port and the protocol.
+        3) Get the Metadata matching info of the flow.
+        4) From the Metadata matching info of the flow get router ID.
+        5) Querry the container intext-ip-port-map using the router ID
+           and the internal IP address, port to get the external IP address, port
+        6) Instantiate an NaptEntry event and populate the external IP address, port and the router ID.
+        7) Place the NaptEntry event to the queue.
+*/
+
+        short tableId = switchFlowRemoved.getTableId();
+        RemovedReasonFlags removedReasonFlag = switchFlowRemoved.getRemovedReason();
+
+        if (tableId == NatConstants.OUTBOUND_NAPT_TABLE && removedReasonFlag.isIDLETIMEOUT()) {
+            LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() entry");
+
+            //Get the internal internal IP address and the port number from the IPv4 match.
+            Ipv4Prefix internalIpv4Address = null;
+            Layer3Match layer3Match = switchFlowRemoved.getMatch().getLayer3Match();
+            if (layer3Match instanceof Ipv4Match) {
+                Ipv4Match internalIpv4Match = (Ipv4Match) layer3Match;
+                internalIpv4Address = internalIpv4Match.getIpv4Source();
+            }
+            if(internalIpv4Address == null){
+                LOG.error("NaptFlowRemovedEventHandler : Matching internal IP is null while retrieving the value from the Outbound NAPT flow");
+                return;
+            }
+            //Get the internal IP as a string
+            String internalIpv4AddressAsString = internalIpv4Address.getValue();
+            String[] internalIpv4AddressParts = internalIpv4AddressAsString.split("/");
+            String internalIpv4HostAddress = null;
+            if(internalIpv4AddressParts.length >= 1){
+                internalIpv4HostAddress = internalIpv4AddressParts[0];
+            }
+
+            //Get the protocol from the layer4 match
+            NAPTEntryEvent.Protocol protocol = null;
+            Integer internalPortNumber = null;
+            Layer4Match layer4Match = switchFlowRemoved.getMatch().getLayer4Match();
+            if (layer4Match instanceof TcpMatch) {
+                TcpMatchFields tcpMatchFields = (TcpMatchFields)layer4Match;
+                internalPortNumber = tcpMatchFields.getTcpSourcePort().getValue();
+                protocol = NAPTEntryEvent.Protocol.TCP;
+            }else if (layer4Match instanceof UdpMatch){
+                UdpMatchFields udpMatchFields = (UdpMatchFields)layer4Match;
+                internalPortNumber = udpMatchFields.getUdpSourcePort().getValue();
+                protocol = NAPTEntryEvent.Protocol.UDP;
+            }
+            if(protocol == null){
+                LOG.error("NaptFlowRemovedEventHandler : Matching protocol is null while retrieving the value from the Outbound NAPT flow");
+                return;
+            }
+
+            //Get the router ID from the metadata.
+            Long routerId;
+            BigInteger metadata = switchFlowRemoved.getMatch().getMetadata().getMetadata();
+            if(MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
+                routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
+            }else {
+                LOG.error("NaptFlowRemovedEventHandler : Null exception while retrieving routerId");
+                return;
+            }
+
+            //Get the external IP address and the port from the model
+            IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
+            if(ipPortExternal == null){
+                LOG.error("NaptFlowRemovedEventHandler : IpPortExternal is null while querried from the model");
+                return;
+            }
+            String externalIpAddress = ipPortExternal.getIpAddress();
+            int externalPortNumber = ipPortExternal.getPortNum();
+
+            //Create an NAPT event and place it in the queue.
+            NAPTEntryEvent naptEntryEvent =  new NAPTEntryEvent(externalIpAddress, externalPortNumber, routerId, NAPTEntryEvent.Operation.DELETE, protocol);
+            naptEventdispatcher.addNaptEvent(naptEntryEvent);
+
+            //Get the DPN ID from the Node
+            InstanceIdentifier<Node> nodeRef = switchFlowRemoved.getNode().getValue().firstIdentifierOf(Node.class);
+            String dpn = nodeRef.firstKeyOf(Node.class).getId().getValue();
+            BigInteger dpnId = getDpnId(dpn);
+            String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(metadata), internalIpv4HostAddress, internalPortNumber);
+
+            //Inform the MDSAL manager to inform about the flow removal.
+            LOG.debug("NaptFlowRemovedEventHandler : DPN ID {}, Metadata {}, SwitchFlowRef {}, internalIpv4HostAddress{}", dpnId, metadata, switchFlowRef, internalIpv4AddressAsString);
+            FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+            mdsalManager.removeFlow(snatFlowEntity);
+
+            LOG.debug("Received flow removed notification due to idleTimeout of flow from switch for flowref {}",switchFlowRef);
+            //Remove the SourceIP:Port key from the Napt packet handler map.
+            String internalIpPortKey = internalIpv4HostAddress + ":" + internalPortNumber;
+            naptPacketInHandler.removeIncomingPacketMap(internalIpPortKey);
+
+            //Remove the mapping of internal fixed ip/port to external ip/port from the datastore.
+            SessionAddress internalSessionAddress = new SessionAddress(internalIpv4HostAddress, internalPortNumber);
+            naptManager.releaseIpExtPortMapping(routerId, internalSessionAddress, protocol);
+            LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() exit");
+        }else {
+            LOG.debug("Received flow removed notification due to flowdelete from switch for flowref");
+        }
+
+    }
+
+    private BigInteger getDpnId(String node) {
+        //openflow:1]
+        String temp[] = node.split(":");
+        BigInteger dpnId = new BigInteger(temp[1]);
+        return dpnId;
+
+    }
+
+    @Override
+    public void onFlowAdded(FlowAdded arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onFlowRemoved(FlowRemoved arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onFlowUpdated(FlowUpdated arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onNodeErrorNotification(NodeErrorNotification arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java
new file mode 100644 (file)
index 0000000..157b437
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 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
+ */
+
+/*
+ * Created eyugsar 2016/12/1
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCounters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCountersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternalBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import  org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+public class NaptManager  {
+    private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
+    private final DataBroker broker;
+    private IdManagerService idManager;
+    private static final long LOW_PORT = 49152L;
+    private static final long HIGH_PORT = 65535L;
+    private static boolean EXTSUBNET_FLAG = false;
+    private static boolean NEXT_EXTIP_FLAG = false;
+
+    public NaptManager(final DataBroker db) {
+        this.broker = db;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    protected void createNaptPortPool(String PoolName) {
+         LOG.debug("NAPT Service : createPortPool requested for : {}", PoolName);
+         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+             .setPoolName(PoolName)
+             .setLow(LOW_PORT)
+             .setHigh(HIGH_PORT)
+             .build();
+         try {
+             Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+             if ((result != null) && (result.get().isSuccessful())) {
+                 LOG.debug("NAPT Service : Created PortPool");
+             } else {
+                 LOG.error("NAPT Service : Unable to create PortPool");
+             }
+         } catch (InterruptedException | ExecutionException e) {
+             LOG.error("Failed to create PortPool for NAPT Service",e);
+         }
+    }
+
+    void removeNaptPortPool(String poolName) {
+        DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
+        LOG.debug("NAPT Service : Remove Napt port pool requested for : {}", poolName);
+        try {
+            Future<RpcResult<Void>> result = idManager.deleteIdPool(deleteIdPoolInput);
+            if ((result != null) && (result.get().isSuccessful())) {
+                LOG.debug("NAPT Service : Deleted PortPool {}", poolName);
+            } else {
+                LOG.error("NAPT Service : Unable to delete PortPool {}", poolName);
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to delete PortPool {} for NAPT Service", poolName, e);
+        }
+    }
+
+     // 1. napt service functions
+     /**
+      * this method is used to inform this service of what external IP address to be used
+      * as mapping when requested one for the internal IP address given in the input
+      * @param segmentId â€“ segmentation in which the mapping to be used. Eg; routerid
+      * @param internal subnet prefix or ip address
+      * @param external subnet prefix or ip address
+      */
+
+      public void registerMapping(long segmentId, IPAddress internal, IPAddress external) {
+
+          LOG.debug("NAPT Service : registerMapping called with segmentid {}, internalIp {}, prefix {}, externalIp {} and prefix {} ", segmentId, internal.getIpAddress(),
+                internal.getPrefixLength(), external.getIpAddress(), external.getPrefixLength());
+        // Create Pool per ExternalIp and not for all IPs in the subnet. Create new Pools during getExternalAddressMapping if exhausted.
+        String externalIpPool;
+        if (external.getPrefixLength() !=0 && external.getPrefixLength() != NatConstants.DEFAULT_PREFIX) {  // subnet case
+            String externalSubnet = new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
+            LOG.debug("NAPT Service : externalSubnet is : {}", externalSubnet);
+            SubnetUtils subnetUtils = new SubnetUtils(externalSubnet);
+            SubnetInfo subnetInfo = subnetUtils.getInfo();
+            externalIpPool = subnetInfo.getLowAddress();
+        } else {  // ip case
+            externalIpPool = external.getIpAddress();
+        }
+        createNaptPortPool(externalIpPool);
+
+        // Store the ip to ip map in Operational DS
+        String internalIp = internal.getIpAddress();
+        if(internal.getPrefixLength() != 0) {
+            internalIp =  new StringBuilder(64).append(internal.getIpAddress()).append("/").append(internal.getPrefixLength()).toString();
+        }
+        String externalIp = external.getIpAddress();
+        if(external.getPrefixLength() != 0) {
+            externalIp =  new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
+        }
+        updateCounter(segmentId, externalIp, true);
+        //update the actual ip-map
+        IpMap ipm = new IpMapBuilder().setKey(new IpMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp).build();
+        MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getIpMapIdentifier(segmentId, internalIp), ipm);
+        LOG.debug("NAPT Service : registerMapping exit after updating DS with internalIP {}, externalIP {}", internalIp, externalIp);
+     }
+
+      public void updateCounter(long segmentId, String externalIp, boolean isAdd){
+          short counter = 0;
+          InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId)).child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
+          Optional <ExternalIpCounter> externalIpCounter = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+          if (externalIpCounter.isPresent()) {
+              counter = externalIpCounter.get().getCounter();
+              if(isAdd){
+                  counter++;
+                  LOG.debug("NAT Service : externalIp and counter after increment are {} and {}", externalIp, counter);
+              }else{
+                  if(counter > 0){
+                    counter--;
+                  }
+                  LOG.debug("NAT Service : externalIp and counter after decrement are {} and {}", externalIp, counter);
+              }
+
+          }else if(isAdd){
+              counter = 1;
+          }
+
+          //update the new counter value for this externalIp
+          ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder().setKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter(counter).build();
+          MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(segmentId, externalIp), externalIpCounterData);
+
+      }
+
+     /**
+      * method to get external ip/port mapping when provided with internal ip/port pair
+      * If already a mapping exist for the given input, then the existing mapping is returned
+      * instead of overwriting with new ip/port pair.
+      * @param segmentId
+      * @param sourceAddress - internal ip address/port pair
+      * @return external ip address/port
+      */
+     public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress, NAPTEntryEvent.Protocol protocol) {
+         LOG.debug("NAPT Service : getExternalAddressMapping called with segmentId {}, internalIp {} and port {}",
+                 segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber());
+        /*
+         1. Get Internal IP, Port in IP:Port format
+         2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port
+         3. If True return SessionAddress of ExternalIp and Port
+         4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port
+         */
+
+         //SessionAddress externalIpPort = new SessionAddress();
+         String internalIpPort = new StringBuilder(64).append(sourceAddress.getIpAddress()).append(":").append(sourceAddress.getPortNumber()).toString();
+
+         // First check existing Port Map.
+         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+         if(existingIpPort != null) {
+             // populate externalIpPort from IpPortMap and return
+             LOG.debug("NAPT Service : getExternalAddressMapping successfully returning existingIpPort as {} and {}", existingIpPort.getIpAddress(), existingIpPort.getPortNumber());
+             return existingIpPort;
+         } else {
+             // Now check in ip-map
+             String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress());
+             if(externalIp == null) {
+                 LOG.error("NAPT Service : getExternalAddressMapping, Unexpected error, internal to external ip map does not exist");
+                 return null;
+             } else {
+                 /* Logic assuming internalIp is always ip and not subnet
+                  * case 1: externalIp is ip
+                  *        a) goto externalIp pool and getPort and return
+                  *        b) else return error
+                  * case 2: externalIp is subnet
+                  *        a) Take first externalIp and goto that Pool and getPort
+                  *             if port -> return
+                  *             else Take second externalIp and create that Pool and getPort
+                  *             if port ->return
+                  *             else
+                  *             Continue same with third externalIp till we exhaust subnet
+                  *        b) Nothing worked return error
+                  */
+                 SubnetUtils externalIpSubnet;
+                 List<String> allIps = new ArrayList<String>();
+                 String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX);
+                 if( !externalIp.contains(subnetPrefix) ) {
+                    EXTSUBNET_FLAG = true;
+                    externalIpSubnet = new SubnetUtils(externalIp);
+                    allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses());
+                    LOG.debug("NAPT Service : total count of externalIps available {}", externalIpSubnet.getInfo().getAddressCount());
+                 } else {
+                     LOG.debug("NAPT Service : getExternalAddress single ip case");
+                     if(externalIp.contains(subnetPrefix)) {
+                         String[] externalIpSplit = externalIp.split("/");
+                         String extIp = externalIpSplit[0];
+                         externalIp = extIp; //remove /32 what we got from checkIpMap
+                     }
+                     allIps.add(externalIp);
+                 }
+
+                 for(String extIp : allIps) {
+                    LOG.info("NAPT Service : Looping externalIPs with externalIP now as {}", extIp);
+                    if(NEXT_EXTIP_FLAG) {
+                        createNaptPortPool(extIp);
+                        LOG.debug("NAPT Service : Created Pool for next Ext IP {}", extIp);
+                    }
+                    AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+                        .setPoolName(extIp).setIdKey(internalIpPort)
+                        .build();
+                     try {
+                        Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+                        RpcResult<AllocateIdOutput> rpcResult;
+                        if ((result != null) && (result.get().isSuccessful())) {
+                            LOG.debug("NAPT Service : Got id from idManager");
+                            rpcResult = result.get();
+                        } else {
+                            LOG.error("NAPT Service : getExternalAddressMapping, idManager could not allocate id retry if subnet");
+                            if(!EXTSUBNET_FLAG) {
+                                LOG.error("NAPT Service : getExternalAddressMapping returning null for single IP case, may be ports exhausted");
+                                return null;
+                            }
+                            LOG.debug("NAPT Service : Could be ports exhausted case, try with another externalIP if possible");
+                            NEXT_EXTIP_FLAG = true;
+                            continue;
+                        }
+                        int extPort= rpcResult.getResult().getIdValue().intValue();
+                        SessionAddress externalIpPort = new SessionAddress(extIp, extPort);
+                        // Write to ip-port-map before returning
+                        IpPortExternalBuilder ipExt = new IpPortExternalBuilder();
+                        IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort).build();
+                        IpPortMap ipm = new IpPortMapBuilder().setKey(new IpPortMapKey(internalIpPort))
+                                .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build();
+                        LOG.debug("NAPT Service : getExternalAddressMapping writing into ip-port-map with externalIP {} and port {}",
+                                ipPortExt.getIpAddress(), ipPortExt.getPortNum());
+                        try {
+                            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+                                           getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm);
+                        } catch (UncheckedExecutionException uee) {
+                            LOG.error("NAPT Service : Failed to write into ip-port-map with exception {}", uee.getMessage() );
+                        }
+
+                         // Write to snat-internal-ip-port-info
+                         String internalIpAddress = sourceAddress.getIpAddress();
+                         int ipPort = sourceAddress.getPortNumber();
+                         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+                         List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,internalIpAddress,protocolType);
+                         if (portList == null) {
+                             portList = Lists.newArrayList();
+                         }
+                         portList.add(ipPort);
+
+                         IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
+                         IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
+                         try {
+                             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+                                     NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType), intIpProtocolType);
+                         } catch (Exception ex) {
+                             LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
+                         }
+
+                         LOG.debug("NAPT Service : getExternalAddressMapping successfully returning externalIP {} and port {}",
+                                         externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
+                        return externalIpPort;
+                    } catch(InterruptedException | ExecutionException  e) {
+                        LOG.error("NAPT Service : getExternalAddressMapping, Exception caught  {}",e);
+                        return null;
+                    }
+                }// end of for loop
+             }// end of else ipmap present
+         }// end of else check ipmap
+         LOG.error("NAPT Service: getExternalAddressMapping returning null, nothing worked or externalIPs exhausted");
+         return null;
+     }
+
+
+     /**
+      * release the existing mapping of internal ip/port to external ip/port pair
+      * if no mapping exist for given internal ip/port, it returns false
+      * @param segmentId
+      * @param address
+      * @return true if mapping exist and the mapping is removed successfully
+      */
+
+     public boolean releaseAddressMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
+
+         LOG.debug("NAPT Service : releaseAddressMapping called with segmentId {}, internalIP {}, port {}", segmentId, address.getIpAddress(), address.getPortNumber());
+         // delete entry from IpPort Map and IP Map if exists
+         String internalIpPort = new StringBuilder(64).append(address.getIpAddress()).append(":").append(address.getPortNumber()).toString();
+         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+         if(existingIpPort != null) {
+             // delete the entry from IpPortMap DS
+             try {
+                 removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
+             } catch (Exception e){
+                 LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" , internalIpPort, segmentId, e);
+                 return false;
+             }
+         } else {
+             LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
+             return false;
+         }
+         String existingIp = checkIpMap(segmentId, address.getIpAddress());
+         if(existingIp != null) {
+             // delete the entry from IpMap DS
+             try {
+                 removeFromIpMapDS(segmentId, address.getIpAddress());
+             } catch (Exception e){
+                 LOG.error("NAPT Service : Removal of  ipmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
+                 return false;
+             }
+             //delete the entry from snatIntIpportinfo
+             try {
+                 removeFromSnatIpPortDS(segmentId, address.getIpAddress());
+             } catch (Exception e){
+                 LOG.error("NAPT Service : releaseAddressMapping failed, Removal of snatipportmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
+                 return false;
+             }
+         } else {
+             LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpMap DS", segmentId, internalIpPort);
+             return false;
+         }
+         // Finally release port from idmanager
+         removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
+
+         LOG.debug("NAPT Service : Exit of releaseAddressMapping successfully for segmentId {} and internalIpPort {}", segmentId, internalIpPort);  
+         return true;
+
+     }
+
+    protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
+        String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
+        SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+        if(existingIpPort != null) {
+            // delete the entry from IpPortMap DS
+            try {
+                removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
+                // Finally release port from idmanager
+                removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
+            } catch (Exception e){
+                LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" ,
+                        internalIpPort, segmentId, e);
+            }
+        } else {
+            LOG.error("NAPT Service : releaseIpExtPortMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
+        }
+
+        //delete the entry of port for InternalIp from snatIntIpportMappingDS
+        try {
+            removeSnatIntIpPortDS(segmentId,address, protocol);
+        } catch (Exception e){
+            LOG.error("NAPT Service : releaseSnatIpPortMapping failed, Removal of snatipportmap {} for router {} failed {}" ,
+                    address.getIpAddress(), segmentId, e);
+        }
+    }
+
+     /**
+      * removes the internal ip to external ip mapping if present
+      * @param segmentId
+      * @return true if successfully removed
+      */
+     public boolean removeMapping(long segmentId) {
+         try {
+             removeIpMappingForRouterID(segmentId);
+             removeIpPortMappingForRouterID(segmentId);
+             removeIntIpPortMappingForRouterID(segmentId);
+         } catch (Exception e){
+             LOG.error("NAPT Service : Removal of  IPMapping for router {} failed {}" , segmentId, e);
+             return false;
+         }
+
+         //TODO :  This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
+        return false;
+     }
+
+     // 2. Utility functions
+     protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
+         InstanceIdentifier<IpMap> id = InstanceIdentifier.builder(
+                 IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segid)).child(IpMap.class, new IpMapKey(internal)).build();
+         return id;
+     }
+
+     protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(long segmentId, String external) {
+         InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId))
+                 .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
+         return id;
+     }
+
+    public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
+        InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
+        Optional<IpMapping> ipMappingListData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (ipMappingListData.isPresent()) {
+            IpMapping ipMapping = ipMappingListData.get();
+            return ipMapping.getIpMap();
+        }
+        return null;
+    }
+
+    protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
+        InstanceIdentifier<IpMapping> id = InstanceIdentifier.builder(
+                IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
+        return id;
+    }
+
+     protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal, NAPTEntryEvent.Protocol protocol) {
+         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+         InstanceIdentifier<IpPortMap> id = InstanceIdentifier.builder(
+                 IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segid)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)).
+                 child(IpPortMap.class, new IpPortMapKey(internal)).build();
+         return id;
+     }
+
+     protected SessionAddress checkIpPortMap(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
+
+         LOG.debug("NAPT Service : checkIpPortMap called with segmentId {} and internalIpPort {}", segmentId, internalIpPort);
+         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+         // check if ip-port-map node is there
+         InstanceIdentifierBuilder<IntextIpProtocolType> idBuilder =
+                         InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType));
+         InstanceIdentifier<IntextIpProtocolType> id = idBuilder.build();
+         Optional<IntextIpProtocolType> intextIpProtocolType = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+         if (intextIpProtocolType.isPresent()) {
+               List<IpPortMap> ipPortMaps = intextIpProtocolType.get().getIpPortMap();
+               for (IpPortMap ipPortMap : ipPortMaps) {
+                    if (ipPortMap.getIpPortInternal().equals(internalIpPort)) {
+                       LOG.debug("NAPT Service : IpPortMap : {}", ipPortMap);
+                       SessionAddress externalIpPort = new SessionAddress(ipPortMap.getIpPortExternal().getIpAddress(),
+                                ipPortMap.getIpPortExternal().getPortNum());
+                       LOG.debug("NAPT Service : checkIpPortMap returning successfully externalIP {} and port {}",
+                               externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
+                       return externalIpPort;
+                    }
+               }
+         }
+         // return null if not found
+         LOG.error("NAPT Service : no-entry in checkIpPortMap, returning NULL [should be OK] for segmentId {} and internalIPPort {}", segmentId, internalIpPort);
+         return null;
+     }
+
+     protected String checkIpMap(long segmentId, String internalIp) {
+
+         LOG.debug("NAPT Service : checkIpMap called with segmentId {} and internalIp {}", segmentId, internalIp);
+         String externalIp;
+         // check if ip-map node is there
+         InstanceIdentifierBuilder<IpMapping> idBuilder =
+                         InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
+         InstanceIdentifier<IpMapping> id = idBuilder.build();
+         Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+         if (ipMapping.isPresent()) {
+               List<IpMap> ipMaps = ipMapping.get().getIpMap();
+               for (IpMap ipMap : ipMaps) {
+                    if (ipMap.getInternalIp().equals(internalIp)) {
+                       LOG.debug("NAPT Service : IpMap : {}", ipMap);
+                       externalIp = ipMap.getExternalIp().toString();
+                       LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
+                       return externalIp;
+                    } else if (ipMap.getInternalIp().contains("/")) { // subnet case
+                        SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
+                        SubnetInfo subnetInfo = subnetUtils.getInfo();
+                        if (subnetInfo.isInRange(internalIp)) {
+                            LOG.debug("NAPT Service : internalIp {} found to be IpMap of internalIpSubnet {}", internalIp, ipMap.getInternalIp());
+                            externalIp = ipMap.getExternalIp().toString();
+                            LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
+                            return externalIp;
+                        }
+                    }
+               }
+         }
+         // return null if not found
+         LOG.error("NAPT Service : checkIpMap failed, returning NULL for segmentId {} and internalIp {}", segmentId, internalIp);
+         return null;
+      }
+
+    protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address,NAPTEntryEvent.Protocol protocol) {
+        LOG.trace("NAPT Service : removeSnatIntIpPortDS method called for IntIpport {} of router {} ",address,segmentId);
+        ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+        List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,address.getIpAddress(),protocolType);
+        if (portList == null || portList.isEmpty() || !portList.contains(address.getPortNumber())) {
+           LOG.debug("Internal IP {} for port {} entry not found in SnatIntIpPort DS",address.getIpAddress(),address.getPortNumber());
+           return;
+        }
+        LOG.trace("NAPT Service : PortList {} retrieved for InternalIp {} of router {}",portList,address.getIpAddress(),segmentId);
+        Integer port = address.getPortNumber();
+        portList.remove(port);
+
+        IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
+        IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
+        try {
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType), intIpProtocolType);
+        } catch (Exception ex) {
+            LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
+        }
+        LOG.debug("NAPT Service : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore : {}"
+                ,address.getIpAddress(),address.getPortNumber(),segmentId);
+    }
+
+    protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
+        InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+                (IntipPortMap.class, new IntipPortMapKey(segmentId)).child(IpPort.class, new IpPortKey(internalIp)).build();
+        // remove from SnatIpPortDS
+        LOG.debug("NAPT Service : Removing SnatIpPort from datastore : {}", intIp);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
+
+    }
+
+    protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
+         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+         removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
+    }
+
+    protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) {
+        InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
+                .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
+                .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
+        InstanceIdentifier<IpPortMap> id = idBuilder.build();
+        // remove from ipportmap DS
+        LOG.debug("NAPT Service : Removing ipportmap from datastore : {}", id);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
+    }
+
+     protected void removeFromIpMapDS(long segmentId, String internalIp) {
+         InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+                 .child(IpMapping.class, new IpMappingKey(segmentId))
+                 .child(IpMap.class, new IpMapKey(internalIp));
+         InstanceIdentifier<IpMap> id = idBuilder.build();
+         // Get externalIp and decrement the counter
+         String externalIp = null;
+         Optional<IpMap> ipMap = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+         if (ipMap.isPresent()) {
+             externalIp = ipMap.get().getExternalIp();
+             LOG.debug("NAT Service : externalIP is {}", externalIp);
+         }else{
+             LOG.warn("NAT Service : ipMap not present for the internal IP {}", internalIp);
+         }
+
+         if(externalIp!=null) {
+             updateCounter(segmentId, externalIp, false);
+             // remove from ipmap DS
+             LOG.debug("NAPT Service : Removing ipmap from datastore");
+             MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+         }else{
+             LOG.warn("NAT Service : externalIp not present for the internal IP {}", internalIp);
+         }
+     }
+
+    private void removeIpMappingForRouterID(long segmentId) {
+        InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+                .child(IpMapping.class, new IpMappingKey(segmentId));
+        InstanceIdentifier<IpMapping> id = idBuilder.build();
+        // Get all externalIps and decrement their counters before deleting the ipmap
+        String externalIp = null;
+        Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (ipMapping.isPresent()) {
+              List<IpMap> ipMaps = ipMapping.get().getIpMap();
+              for (IpMap ipMap : ipMaps) {
+                  externalIp = ipMap.getExternalIp();
+                  LOG.debug("NAT Service : externalIP is {}", externalIp);
+                  if(externalIp!=null) {
+                      updateCounter(segmentId, externalIp, false);
+                  }
+              }
+        }
+        // remove from ipmap DS
+        LOG.debug("NAPT Service : Removing Ipmap for router {} from datastore",segmentId);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+    void removeIpPortMappingForRouterID(long segmentId) {
+        InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
+                .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
+        // remove from IntExtIpPortmap DS
+        LOG.debug("NAPT Service : Removing IntExtIpPort map for router {} from datastore",segmentId);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idBuilder);
+    }
+
+    void removeIntIpPortMappingForRouterID(long segmentId) {
+        InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+                (IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
+        // remove from SnatIntIpPortmap DS
+        LOG.debug("NAPT Service : Removing SnatIntIpPort from datastore : {}", intIp);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
+    }
+
+     void removePortFromPool(String internalIpPort, String externalIp) {
+         LOG.debug("NAPT Service : removePortFromPool method called");
+         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
+                                        setPoolName(externalIp)
+                                        .setIdKey(internalIpPort).build();
+         try {
+             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
+             RpcResult<Void> rpcResult = result.get();
+             if(!rpcResult.isSuccessful()) {
+                 LOG.error("NAPT Service : idmanager failed to remove port from pool {}", rpcResult.getErrors());
+             }
+             LOG.debug("NAPT Service : Removed port from pool for InternalIpPort {} with externalIp {}",internalIpPort,externalIp);
+         } catch (InterruptedException | ExecutionException e) {
+             LOG.error("NAPT Service : idmanager failed with Exception {} when removing entry in pool with key {}, ", e, internalIpPort);
+         }
+     }
+
+    protected void initialiseExternalCounter(Routers routers, long routerId){
+        LOG.debug("NAPT Service : Initialise External IPs counter");
+        List<String> externalIps = routers.getExternalIps();
+
+        //update the new counter value for this externalIp
+        for(String externalIp : externalIps) {
+            String[] IpSplit = externalIp.split("/");
+            String extIp = IpSplit[0];
+            String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
+            if(IpSplit.length==2) {
+                extPrefix = IpSplit[1];
+            }
+            extIp = extIp + "/" + extPrefix;
+            initialiseNewExternalIpCounter(routerId, extIp);
+        }
+    }
+
+    protected void initialiseNewExternalIpCounter(long routerId, String ExternalIp){
+        ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder().setKey(new ExternalIpCounterKey(ExternalIp)).
+                setExternalIp(ExternalIp).setCounter((short) 0).build();
+        MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(routerId, ExternalIp), externalIpCounterData);
+    }
+
+    protected void removeExternalCounter(long routerId){
+        // Remove from external-counters model
+        InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
+        LOG.debug("NAPT Service : Removing ExternalCounterd from datastore");
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+    protected void removeExternalIpCounter(long routerId, String externalIp){
+        // Remove from external-counters model
+        InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class,
+                new ExternalCountersKey(routerId)).child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
+        LOG.debug("NAPT Service : Removing ExternalIpsCounter from datastore");
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptPacketInHandler.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptPacketInHandler.java
new file mode 100644 (file)
index 0000000..34795b1
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
+import org.opendaylight.vpnservice.mdsalutil.packet.TCP;
+import org.opendaylight.vpnservice.mdsalutil.packet.UDP;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.HashSet;
+import com.google.common.primitives.Ints;
+
+public class NaptPacketInHandler implements PacketProcessingListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NaptPacketInHandler.class);
+    private final static HashSet<String> incomingPacketMap = new HashSet<>();
+    private final EventDispatcher naptEventdispatcher;
+
+    public NaptPacketInHandler(EventDispatcher eventDispatcher) {
+        this.naptEventdispatcher = eventDispatcher;
+    }
+
+    @Override
+    public void onPacketReceived(PacketReceived packetReceived) {
+        String internalIPAddress = "";
+        int portNumber = 0;
+        long routerId = 0L;
+        NAPTEntryEvent.Operation operation = NAPTEntryEvent.Operation.ADD;
+        NAPTEntryEvent.Protocol protocol;
+
+        Short tableId = packetReceived.getTableId().getValue();
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("packet: {}, tableId {}", packetReceived, tableId);
+        }
+
+        if (tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+            LOG.debug("NAT Service : NAPTPacketInHandler Packet for Outbound NAPT Table");
+            byte[] inPayload = packetReceived.getPayload();
+            Ethernet ethPkt = new Ethernet();
+            if (inPayload != null) {
+                try {
+                    ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
+                } catch (Exception e) {
+                    LOG.warn("Failed to decode Packet", e);
+                    return;
+                }
+                if (ethPkt.getPayload() instanceof IPv4) {
+                    IPv4 ipPkt = (IPv4) ethPkt.getPayload();
+                    byte[] ipSrc = Ints.toByteArray(ipPkt.getSourceAddress());
+
+                    internalIPAddress = NatUtil.toStringIpAddress(ipSrc, LOG);
+                    LOG.trace("Retrieved internalIPAddress {}", internalIPAddress);
+                    if (ipPkt.getPayload() instanceof TCP) {
+                        TCP tcpPkt = (TCP) ipPkt.getPayload();
+                        portNumber = tcpPkt.getSourcePort();
+                        if(portNumber < 0){
+                            portNumber = 32767 + portNumber + 32767 + 2;
+                            LOG.trace("Retrieved and extracted TCP portNumber {}", portNumber);
+                        }
+                        protocol = NAPTEntryEvent.Protocol.TCP;
+                        LOG.trace("Retrieved TCP portNumber {}", portNumber);
+                    } else if (ipPkt.getPayload() instanceof UDP) {
+                        UDP udpPkt = (UDP) ipPkt.getPayload();
+                        portNumber = udpPkt.getSourcePort();
+                        if(portNumber < 0){
+                            portNumber = 32767 + portNumber + 32767 + 2;
+                            LOG.trace("Retrieved and extracted UDP portNumber {}", portNumber);
+                        }
+                        protocol = NAPTEntryEvent.Protocol.UDP;
+                        LOG.trace("Retrieved UDP portNumber {}", portNumber);
+                    } else {
+                        LOG.error("Incoming Packet is neither TCP or UDP packet");
+                        return;
+                    }
+                } else {
+                    LOG.error("Incoming Packet is not IPv4 packet");
+                    return;
+                }
+
+                if(internalIPAddress != null) {
+                    String sourceIPPortKey = internalIPAddress + ":" + portNumber;
+                    LOG.debug("NAT Service : sourceIPPortKey {} mapping maintained in the map", sourceIPPortKey);
+                    if (!incomingPacketMap.contains(sourceIPPortKey)) {
+                        incomingPacketMap.add(internalIPAddress + portNumber);
+
+                        BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata();
+                        routerId = (metadata.and(MetaDataUtil.METADATA_MASK_VRFID)).longValue();
+                        if( routerId <= 0) {
+                            LOG.error("Nat Service : Router ID is invalid");
+                            return;
+                        }
+                        //send to Event Queue
+                        NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(internalIPAddress,portNumber,routerId,
+                                operation,protocol);
+                        naptEventdispatcher.addNaptEvent(naptEntryEvent);
+                    } else {
+                        LOG.trace("Ignore the packet, already processed");
+                    }
+                }else {
+                    LOG.error("Nullpointer exception in retrieving internalIPAddress");
+                }
+            }
+        }else {
+            LOG.trace("Packet is not from the Outbound NAPT table");
+        }
+    }
+
+    public void removeIncomingPacketMap(String sourceIPPortKey) {
+        incomingPacketMap.remove(sourceIPPortKey);
+        LOG.debug("NAT Service : sourceIPPortKey {} mapping is removed from map", sourceIPPortKey);
+    }
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptSwitchHA.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptSwitchHA.java
new file mode 100644 (file)
index 0000000..795dff3
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import com.google.common.base.Optional;
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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.action.types.rev131112.action.action.OutputActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class NaptSwitchHA {
+    private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
+    private final DataBroker dataBroker;
+    private IMdsalApiManager mdsalManager;
+    private ItmRpcService itmManager;
+    private OdlInterfaceRpcService interfaceManager;
+    private IdManagerService idManager;
+    private NAPTSwitchSelector naptSwitchSelector;
+    private ExternalRoutersListener externalRouterListener;
+    private IBgpManager bgpManager;
+    private VpnRpcService vpnService;
+    private FibRpcService fibService;
+
+    public NaptSwitchHA(DataBroker broker,NAPTSwitchSelector selector){
+        dataBroker = broker;
+        naptSwitchSelector = selector;
+    }
+
+    public void setItmManager(ItmRpcService itmManager) {
+        this.itmManager = itmManager;
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+        this.interfaceManager = interfaceManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
+        this.externalRouterListener = externalRoutersListener;
+    }
+
+    public void setBgpManager(IBgpManager bgpManager) {
+        this.bgpManager = bgpManager;
+    }
+
+    public void setVpnService(VpnRpcService vpnService) {
+        this.vpnService = vpnService;
+    }
+
+    public void setFibService(FibRpcService fibService) {
+        this.fibService = fibService;
+    }
+
+    /* This method checks the switch that gone down is a NaptSwitch for a router.
+       If it is a NaptSwitch
+          1) selects new NAPT switch
+          2) installs nat flows in new NAPT switch
+          table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
+          3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
+          4) Remove nat flows in oldNaptSwitch
+     */
+    /*public void handleNaptSwitchDown(BigInteger dpnId){
+
+        LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
+        BigInteger naptSwitch;
+        try {
+            NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
+            if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
+                LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
+                return;
+            }
+            for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
+                String routerName = routerToNaptSwitch.getRouterName();
+                naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
+                boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
+                if (!naptStatus) {
+                    LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+                            dpnId, routerName);
+                } else {
+                    removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
+                    return;
+                }
+            }
+        } catch (Exception ex) {
+            LOG.error("Exception in handleNaptSwitchDown method {}",ex);
+        }
+    }*/
+
+    protected void removeSnatFlowsInOldNaptSwitch(String routerName, BigInteger naptSwitch) {
+        //remove SNAT flows in old NAPT SWITCH
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}",routerName);
+            return;
+        }
+
+        //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
+        String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
+        FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
+
+        LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
+                ,NatConstants.TERMINATING_SERVICE_TABLE, naptSwitch, routerId);
+        mdsalManager.removeFlow(tsNatFlowEntity);
+
+        //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
+        String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+        FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
+                NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
+        LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
+                ,NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
+        mdsalManager.removeFlow(outboundNatFlowEntity);
+
+        //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic matching on the router ID.
+        String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, routerId);
+        FlowEntity naptPFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptPFibflowRef);
+        LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
+                NatConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
+        mdsalManager.removeFlow(naptPFibFlowEntity);
+
+        //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic matching on the vpn ID.
+        Long vpnId = getVpnIdForRouter(routerId);
+        if (vpnId != NatConstants.INVALID_ID) {
+            String naptFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, vpnId);
+            FlowEntity naptFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptFibflowRef);
+            LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and vpnId {}",
+                    NatConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
+            mdsalManager.removeFlow(naptFibFlowEntity);
+        } else {
+            LOG.error("Invalid vpnId retrieved for routerId {}",routerId);
+            return;
+        }
+
+        //Remove Fib entries and 36-> 44
+        Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+        if (networkId != null) {
+            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+            if (externalIps != null) {
+                externalRouterListener.clrRtsFromBgpAndDelFibTs(naptSwitch, routerId, networkId, externalIps, null);
+                LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} with networkId {} and externalIps {}",
+                        naptSwitch,routerId,networkId,externalIps);
+            } else {
+                LOG.debug("ExternalIps not found for router {} with networkId {}", routerName, networkId);
+            }
+        } else {
+            LOG.debug("network not associated to router {}", routerId);
+        }
+
+        //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+        IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+        if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+            LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be removed in" +
+                    "oldNaptSwitch {}", routerId, naptSwitch);
+            return;
+        }
+        BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+        List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+        for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
+            if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
+                LOG.debug("No {} session associated to router {},no flows need to be removed in oldNaptSwitch {}",
+                        intextIpProtocolType.getProtocol(),routerId,naptSwitch);
+                break;
+            }
+            List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+            for(IpPortMap ipPortMap : ipPortMaps) {
+                String ipPortInternal = ipPortMap.getIpPortInternal();
+                String[] ipPortParts = ipPortInternal.split(":");
+                if(ipPortParts.length != 2) {
+                    LOG.error("Unable to retrieve the Internal IP and port");
+                    continue;
+                }
+                String internalIp = ipPortParts[0];
+                String internalPort = ipPortParts[1];
+
+                //Build and remove flow in outbound NAPT table
+                String switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
+                        internalIp, Integer.valueOf(internalPort));
+                FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
+                        cookieSnatFlow, switchFlowRef);
+
+                LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
+                        NatConstants.OUTBOUND_NAPT_TABLE,naptSwitch, routerId);
+                mdsalManager.removeFlow(outboundNaptFlowEntity);
+
+                IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+                if (ipPortExternal == null) {
+                    LOG.debug("External Ipport mapping not found for internalIp {} with port {} for router", internalIp,
+                            internalPort, routerId);
+                    continue;
+                }
+                String externalIp = ipPortExternal.getIpAddress();
+                int externalPort = ipPortExternal.getPortNum();
+
+                //Build and remove flow in  inbound NAPT table
+                switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
+                        externalIp, externalPort);
+                FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+                        cookieSnatFlow, switchFlowRef);
+
+                LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
+                        NatConstants.INBOUND_NAPT_TABLE,naptSwitch, routerId);
+                mdsalManager.removeFlow(inboundNaptFlowEntity);
+            }
+        }
+
+    }
+
+    /*public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch) {
+        if (!naptSwitch.equals(dpnId)) {
+            LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
+            return false;
+        }
+        LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
+        //elect a new NaptSwitch
+        naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+        if (naptSwitch.equals(BigInteger.ZERO)) {
+            LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
+            boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
+            if(!naptUpdatedStatus) {
+                LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
+            }
+            return true;
+        }
+        //checking elected switch health status
+        if (!getSwitchStatus(naptSwitch)) {
+            LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
+            return true;
+        }
+        LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}", routerName);
+            return true;
+        }
+        //update napt model for new napt switch
+        boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
+        if (naptUpdated) {
+            //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
+            updateNaptSwitchBucketStatus(routerName, naptSwitch);
+        } else {
+            LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
+        }
+
+        installSnatFlows(routerName,routerId,naptSwitch);
+
+        boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch);
+        if (flowInstalledStatus) {
+            LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
+        } else {
+            LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
+        }
+        return true;
+    }*/
+
+    public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId) {
+        if (!naptSwitch.equals(dpnId)) {
+            LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
+            return false;
+        }
+        LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
+        //elect a new NaptSwitch
+        naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+        if (naptSwitch.equals(BigInteger.ZERO)) {
+            LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
+            boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
+            if(!naptUpdatedStatus) {
+                LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
+            }
+            return true;
+        }
+        //checking elected switch health status
+        if (!getSwitchStatus(naptSwitch)) {
+            LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
+            return true;
+        }
+        LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}", routerName);
+            return true;
+        }
+        //update napt model for new napt switch
+        boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
+        if (naptUpdated) {
+            //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
+            updateNaptSwitchBucketStatus(routerName, naptSwitch);
+        } else {
+            LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
+        }
+
+        installSnatFlows(routerName,routerId,naptSwitch,routerVpnId);
+
+        boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch,routerVpnId);
+        if (flowInstalledStatus) {
+            LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
+        } else {
+            LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
+        }
+        return true;
+    }
+
+    private String getExtNetworkVpnName(long routerId) {
+        Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+        if(networkId == null) {
+            LOG.error("networkId is null for the router ID {}", routerId);
+        } else {
+            final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+            if (vpnName != null) {
+                LOG.debug("retrieved vpn name {} associated with ext nw {} in router {}",
+                        vpnName,networkId,routerId);
+                return vpnName;
+            } else {
+                LOG.error("No VPN associated with ext nw {} belonging to routerId {}",
+                        networkId, routerId);
+            }
+        }
+        return null;
+    }
+
+    public void updateNaptSwitchBucketStatus(String routerName, BigInteger naptSwitch) {
+        LOG.debug("updateNaptSwitchBucketStatus method is called");
+
+        List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
+        //List<BigInteger> dpnList = getDpnListForRouter(routerName);
+        for (BigInteger dpn : dpnList) {
+            if (dpn.equals(naptSwitch)) {
+                LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is naptSwitch for router {}",dpn,routerName);
+                List<BucketInfo> bucketInfoList = handleGroupInPrimarySwitch();
+                modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
+            } else {
+                LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is not naptSwitch for router {}",dpn,routerName);
+                List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, naptSwitch);
+                if (bucketInfoList == null) {
+                    LOG.debug("Failed to populate bucketInfo for orinaryswitch {} whose naptSwitch {} for router {} ",
+                            dpn,naptSwitch,routerName);
+                    return;
+                }
+                modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
+            }
+        }
+    }
+
+    /*private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch) {
+
+        LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
+        IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
+        if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+            LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
+                    "newNaptSwitch {}", routerId, newNaptSwitch);
+            return true;
+        }
+        //getvpnId
+        Long vpnId = getVpnIdForRouter(routerId);
+        if (vpnId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid vpnId for routerId {}",routerId);
+            return false;
+        }
+        Long bgpVpnId = NatConstants.INVALID_ID;
+        for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
+            if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
+                LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
+                return true;
+            }
+            for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
+                String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
+                String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
+
+                //Get the external IP address and the port from the model
+                NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
+                        ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
+                IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
+                        internalIpAddress, intportnum, proto);
+                if (ipPortExternal == null) {
+                    LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
+                    continue;
+                }
+                String externalIpAddress = ipPortExternal.getIpAddress();
+                Integer extportNumber = ipPortExternal.getPortNum();
+                LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
+                        internalIpAddress,intportnum);
+
+                SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
+                SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
+
+                //checking naptSwitch status before installing flows
+                if(getSwitchStatus(newNaptSwitch)) {
+                    //Install the flow in newNaptSwitch Outbound NAPT table.
+                    try {
+                        NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
+                                vpnId,  routerId, bgpVpnId ,sourceAddress, externalAddress, proto);
+                    } catch (Exception ex) {
+                        LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
+                                "extIpport {}:{}", routerId, newNaptSwitch, internalIpAddress
+                                , intportnum, proto, externalAddress, extportNumber);
+                        return false;
+                    }
+                    LOG.debug("Succesfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
+                            "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
+                            , intportnum, proto, externalAddress, extportNumber);
+                    //Install the flow in newNaptSwitch Inbound NAPT table.
+                    try {
+                        NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+                                vpnId, routerId, bgpVpnId,externalAddress, sourceAddress, proto);
+                    } catch (Exception ex) {
+                        LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{}",
+                                routerId, newNaptSwitch, externalAddress, extportNumber,
+                                proto, internalIpAddress, intportnum);
+                        return false;
+                    }
+                    LOG.debug("Succesfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
+                            "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
+                            , intportnum, proto, externalAddress, extportNumber);
+
+                } else {
+                    LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
+                            newNaptSwitch,oldNaptSwitch);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }*/
+
+    private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch,Long routerVpnId) {
+
+        LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
+        IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
+        if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+            LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
+                    "newNaptSwitch {}", routerId, newNaptSwitch);
+            return true;
+        }
+        //getvpnId
+        Long vpnId = getVpnIdForRouter(routerId);
+        if (vpnId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid vpnId for routerId {}",routerId);
+            return false;
+        }
+        Long bgpVpnId;
+        if(routerId.equals(routerVpnId)) {
+            bgpVpnId = NatConstants.INVALID_ID;
+        } else {
+            bgpVpnId = routerVpnId;
+        }
+        LOG.debug("retrieved bgpVpnId {} for router {}",bgpVpnId,routerId);
+        for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
+            if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
+                LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
+                return true;
+            }
+            for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
+                String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
+                String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
+
+                //Get the external IP address and the port from the model
+                NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
+                        ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
+                IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
+                        internalIpAddress, intportnum, proto);
+                if (ipPortExternal == null) {
+                    LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
+                    continue;
+                }
+                String externalIpAddress = ipPortExternal.getIpAddress();
+                Integer extportNumber = ipPortExternal.getPortNum();
+                LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
+                        internalIpAddress,intportnum);
+
+                SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
+                SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
+
+                //checking naptSwitch status before installing flows
+                if(getSwitchStatus(newNaptSwitch)) {
+                    //Install the flow in newNaptSwitch Outbound NAPT table.
+                    try {
+                        NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
+                                vpnId,  routerId, bgpVpnId, sourceAddress, externalAddress, proto);
+                    } catch (Exception ex) {
+                        LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
+                                "extIpport {}:{} BgpVpnId {} - {}", routerId, newNaptSwitch, internalIpAddress
+                                , intportnum, proto, externalAddress, extportNumber,bgpVpnId,ex);
+                        return false;
+                    }
+                    LOG.debug("Successfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
+                            "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
+                            , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
+                    //Install the flow in newNaptSwitch Inbound NAPT table.
+                    try {
+                        NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+                                vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto);
+                    } catch (Exception ex) {
+                        LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} " +
+                                        "ipport {}:{} BgpVpnId {}", routerId, newNaptSwitch, externalAddress, extportNumber, proto,
+                                internalIpAddress, intportnum,bgpVpnId);
+                        return false;
+                    }
+                    LOG.debug("Successfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
+                            "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
+                            , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
+
+                } else {
+                    LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
+                            newNaptSwitch,oldNaptSwitch);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private Long getVpnIdForRouter(Long routerId) {
+        try {
+            //getvpnId
+            Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+            if (networkId == null) {
+                LOG.debug("network is not associated to router {}", routerId);
+            } else {
+                Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+                if (vpnUuid == null) {
+                    LOG.debug("vpn is not associated for network {} in router {}", networkId, routerId);
+                } else {
+                    Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                    if (vpnId > 0) {
+                        LOG.debug("retrieved vpnId {} for router {}",vpnId,routerId);
+                        return vpnId;
+                    } else {
+                        LOG.debug("retrieved invalid vpn Id");
+                    }
+                }
+            }
+        } catch (Exception ex){
+            LOG.debug("Exception while retrieving vpnId for router {} - {}", routerId, ex);
+        }
+        return NatConstants.INVALID_ID;
+    }
+
+/*
+    private List<BigInteger> getDpnListForRouter(String routerName) {
+        long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
+        if (bgpVpnId != NatConstants.INVALID_ID) {
+            return NatUtil.getDpnsForRouter(dataBroker, routerName);
+        }
+        List<BigInteger> dpnList = new ArrayList<BigInteger>();
+        List<VpnToDpnList> vpnDpnList = NatUtil.getVpnToDpnList(dataBroker, routerName);
+        if (vpnDpnList == null || vpnDpnList.isEmpty()) {
+            LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
+            dpnList = NatUtil.getDpnsForRouter(dataBroker, routerName);
+            if(dpnList == null || dpnList.isEmpty()){
+                LOG.debug("NAT Service : No switches are part of router {}", routerName);
+                LOG.error("NAT Service : NAPT SWITCH SELECTION STOPPED DUE TO NO DPNS SCENARIO FOR ROUTER {}", routerName);
+            }
+        } else {
+            for (VpnToDpnList vpnToDpn : vpnDpnList) {
+                dpnList.add(vpnToDpn.getDpnId());
+            }
+        }
+        return dpnList;
+    }
+*/
+
+    public boolean getSwitchStatus(BigInteger switchId){
+        NodeId nodeId = new NodeId("openflow:" + switchId);
+        LOG.debug("Querying switch with dpnId {} is up/down", nodeId);
+        InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, new NodeKey(nodeId)).build();
+        Optional<Node> nodeOptional = NatUtil.read(dataBroker,LogicalDatastoreType.OPERATIONAL,nodeInstanceId);
+        if (nodeOptional.isPresent()) {
+            LOG.debug("Switch {} is up", nodeId);
+            return true;
+        }
+        LOG.debug("Switch {} is down", nodeId);
+        return false;
+    }
+
+    public List<BucketInfo> handleGroupInPrimarySwitch() {
+        List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+        List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
+        listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit,
+                new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
+        BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+        listBucketInfo.add(bucketPrimary);
+        return listBucketInfo;
+    }
+
+    public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, BigInteger naptSwitch) {
+        List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+        String ifNamePrimary;
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}",routerName);
+            return listBucketInfo;
+        }
+        ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
+        if (ifNamePrimary != null) {
+            LOG.debug("TunnelInterface {} between ordinary switch {} and naptSwitch {}",ifNamePrimary,dpnId,naptSwitch);
+            List<ActionInfo> listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
+            BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+            listBucketInfo.add(bucketPrimary);
+        } else {
+            LOG.debug("No TunnelInterface between ordinary switch {} and naptSwitch {}",dpnId,naptSwitch);
+        }
+        return listBucketInfo;
+    }
+
+    protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+        GroupEntity groupEntity = null;
+        try {
+            long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+            LOG.debug("install SnatMissEntry for groupId {} for dpnId {} for router {}", groupId, dpnId,routerName);
+            groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+                    GroupTypes.GroupAll, bucketInfo);
+            mdsalManager.installGroup(groupEntity);
+            LOG.debug("installed the SNAT to NAPT GroupEntity:{}", groupEntity);
+        } catch (Exception ex) {
+            LOG.error("Failed to install group for groupEntity {} : {}",groupEntity,ex);
+        }
+    }
+
+    private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+        installSnatGroupEntry(dpnId,bucketInfo,routerName);
+        LOG.debug("modified SnatMissEntry for dpnId {} of router {}",dpnId,routerName);
+    }
+
+    protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+        RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
+
+        try {
+            Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
+                    new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId).
+//                            .setTunnelType(tunType).
+                              build());
+            rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                tunType = TunnelTypeGre.class;
+                result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+                        .setSourceDpid(srcDpId)
+                        .setDestinationDpid(dstDpId)
+//                        .setTunnelType(tunType)
+                        .build());
+                rpcResult = result.get();
+                if(!rpcResult.isSuccessful()) {
+                    LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+                } else {
+                    return rpcResult.getResult().getInterfaceName();
+                }
+                LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+            } else {
+                return rpcResult.getResult().getInterfaceName();
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {} : {}",
+                    srcDpId, dstDpId, e);
+        }
+
+        return null;
+    }
+
+    protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
+        LOG.debug("getEgressActionsForInterface called for interface {}", ifName);
+        List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
+        try {
+            Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
+                    interfaceManager.getEgressActionsForInterface(
+                            new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
+            RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}"
+                        , ifName, rpcResult.getErrors());
+            } else {
+                List<Action> actions =
+                        rpcResult.getResult().getAction();
+                for (Action action : actions) {
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
+                    if (actionClass instanceof OutputActionCase) {
+                        listActionInfo.add(new ActionInfo(ActionType.output,
+                                new String[] {((OutputActionCase)actionClass).getOutputAction()
+                                        .getOutputNodeConnector().getValue()}));
+                    } else if (actionClass instanceof PushVlanActionCase) {
+                        listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
+                    } else if (actionClass instanceof SetFieldCase) {
+                        if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
+                            int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch()
+                                    .getVlanId().getVlanId().getValue();
+                            listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
+                                    new String[] { Long.toString(vlanVid) }));
+                        }
+                    }
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception when egress actions for interface {}", ifName, e);
+        }
+        return listActionInfo;
+    }
+
+    public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
+        RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
+                .setPrimarySwitchId(naptSwitchId).build();
+        try {
+            MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
+        } catch (Exception ex) {
+            LOG.error("Failed to write naptSwitch {} for router {} in ds",
+                    naptSwitchId,routerName);
+            return false;
+        }
+        LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
+                naptSwitchId,routerName);
+        return true;
+    }
+
+    /*public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, int addordel) {
+
+        FlowEntity flowEntity;
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}",routerName);
+            return null;
+        }
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[]{ 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+
+        if (addordel == NatConstants.ADD_FLOW) {
+            List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+            List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
+
+            ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+                    BigInteger.valueOf(routerId)}) ;
+            actionsInfo.add(actionSetField);
+            LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
+            actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+            instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+
+            flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                    NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                    NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+        } else {
+            flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                    NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                    NatConstants.COOKIE_SNAT_TABLE, matches, null);
+        }
+        return flowEntity;
+    }*/
+
+    public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, long routerVpnId, int addordel) {
+
+        FlowEntity flowEntity;
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[]{ 0x0800L }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+
+        if (addordel == NatConstants.ADD_FLOW) {
+            List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+            List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
+
+            ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+                    BigInteger.valueOf(routerVpnId)}) ;
+            actionsInfo.add(actionSetField);
+            LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
+            actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+            instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+
+            flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                    NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                    NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+        } else {
+            flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+                    NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                    NatConstants.COOKIE_SNAT_TABLE, matches, null);
+        }
+        return flowEntity;
+    }
+
+    private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
+        return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+    }
+
+    /*protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch) {
+        //36 -> 46 ..Install flow forwarding packet to table46 from table36
+        LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {}", naptSwitch, routerName);
+        externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
+
+        //Install default flows punting to controller in table 46(OutBoundNapt table)
+        LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {}", naptSwitch, routerName);
+        externalRouterListener.installOutboundMissEntry(routerName, naptSwitch);
+
+        //Table 47 point to table 21 for inbound traffic
+        LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for routerId {}", naptSwitch, routerId);
+        externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
+
+        String vpnName = getExtNetworkVpnName(routerId);
+        if(vpnName != null) {
+            //Table 47 point to table 21 for outbound traffic
+            long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+            if(vpnId > 0) {
+                LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for vpnId {}", naptSwitch, vpnId);
+                externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
+            } else {
+                LOG.debug("Associated vpnId not found for router {}",routerId);
+            }
+
+            //Install Fib entries for ExternalIps & program 36 -> 44
+            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+            if (externalIps != null) {
+                for (String externalIp : externalIps) {
+                    LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
+                            naptSwitch, vpnName, externalIp);
+                    externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+                            vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
+                    LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
+                            routerId, externalIp);
+                }
+            } else {
+                LOG.debug("External Ip not found for routerId {}",routerId);
+            }
+        } else {
+            LOG.debug("Associated vpnName not found for router {}",routerId);
+        }
+    }*/
+
+    protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch,Long routerVpnId) {
+
+        if(routerId.equals(routerVpnId)) {
+            LOG.debug("Installing flows for router with internalvpnId");
+            //36 -> 46 ..Install flow forwarding packet to table46 from table36
+            LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
+                    naptSwitch, routerName,routerId);
+            externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
+
+            //Install default flows punting to controller in table 46(OutBoundNapt table)
+            LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
+                    naptSwitch, routerName, routerId);
+            externalRouterListener.createOutboundTblEntry(naptSwitch, routerId);
+
+            //Table 47 point to table 21 for inbound traffic
+            LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {}", naptSwitch, routerId);
+            externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
+        } else {
+            //36 -> 46 ..Install flow forwarding packet to table46 from table36
+            LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
+                    naptSwitch, routerName, routerVpnId);
+            externalRouterListener.installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerVpnId);
+
+            //Install default flows punting to controller in table 46(OutBoundNapt table)
+            LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
+                    naptSwitch, routerName, routerVpnId);
+            externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
+
+            //Table 47 point to table 21 for inbound traffic
+            LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {} with BgpVpnId {}",
+                    naptSwitch, routerId, routerVpnId);
+            externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
+        }
+
+        String vpnName = getExtNetworkVpnName(routerId);
+        if(vpnName != null) {
+            //Table 47 point to table 21 for outbound traffic
+            long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+            if(vpnId > 0) {
+                LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for BgpVpnId {}", naptSwitch, vpnId);
+                externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
+            } else {
+                LOG.debug("Associated BgpvpnId not found for router {}",routerId);
+            }
+
+            //Install Fib entries for ExternalIps & program 36 -> 44
+            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+            if (externalIps != null) {
+                for (String externalIp : externalIps) {
+                    LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
+                            naptSwitch, vpnName, externalIp);
+                    externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+                            vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
+                    LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
+                            routerId, externalIp);
+                }
+            } else {
+                LOG.debug("External Ip not found for routerId {}",routerId);
+            }
+        } else {
+            LOG.debug("Associated vpnName not found for router {}",routerId);
+        }
+    }
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatConstants.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatConstants.java
new file mode 100644 (file)
index 0000000..bf4a8e2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+
+
+public class NatConstants {
+    public static final short INBOUND_NAPT_TABLE = 44;
+    public static final short OUTBOUND_NAPT_TABLE = 46;
+    public static final short NAPT_PFIB_TABLE = 47;
+    public static final short TERMINATING_SERVICE_TABLE = 36;
+    public static final short DEFAULT_NAPT_FLOW_PRIORITY = 10;
+    public static final String NAPT_FLOW_NAME = "SNAT";
+    public static BigInteger COOKIE_NAPT_BASE = new BigInteger("8000000", 16);
+    public static final String NAPT_FLOWID_PREFIX = "SNAT.";
+    public static final String FLOWID_SEPARATOR = ".";
+    public static final int DEFAULT_NAPT_IDLE_TIMEOUT = 300;
+    public static int EVENT_QUEUE_LENGTH = 1000000;
+    public static final short PDNAT_TABLE = 25;
+    public static final short DNAT_TABLE = 27;
+    public static final short SNAT_TABLE = 28;
+    public static final short PSNAT_TABLE = 26;
+    public static final short L3_FIB_TABLE = 21;
+    public static final String FLOWID_PREFIX = "L3.";
+    public static final int DEFAULT_DNAT_FLOW_PRIORITY = 10;
+    public static final BigInteger COOKIE_DNAT_TABLE = new BigInteger("8000004", 16);
+    public static final long INVALID_ID = -1;
+    public static final BigInteger COOKIE_OUTBOUND_NAPT_TABLE = new BigInteger("8000008", 16);
+    public static final short DEFAULT_SNAT_FLOW_PRIORITY = 10;
+    public static final short DEFAULT_PSNAT_FLOW_PRIORITY = 5;
+    public static final String SNAT_FLOW_NAME = "SNAT";
+    public static final String SNAT_FLOWID_PREFIX = "SNAT.";
+    public static final BigInteger COOKIE_SNAT_TABLE = new BigInteger("8000006", 16);
+    public static final String SNAT_IDPOOL_NAME = "snatGroupIdPool";
+    public static final long SNAT_ID_LOW_VALUE = 200000L;
+    public static final long SNAT_ID_HIGH_VALUE = 225000L;
+    public static final int DEFAULT_TS_FLOW_PRIORITY = 10;
+    public static final BigInteger COOKIE_TS_TABLE = new BigInteger("8000002", 16);
+    public static final short DEFAULT_PREFIX = 32;
+
+    // Flow Actions
+    public static final int ADD_FLOW = 0;
+    public static final int DEL_FLOW = 1;
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatNodeEventListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatNodeEventListener.java
new file mode 100644 (file)
index 0000000..b4dcc71
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+
+public class NatNodeEventListener extends AbstractDataChangeListener<Node> implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NatNodeEventListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private NaptSwitchHA naptSwitchHA;
+
+    public NatNodeEventListener(final DataBroker db,final  NaptSwitchHA napt) {
+        super(Node.class);
+        naptSwitchHA = napt;
+        registerListener(db);
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), NatNodeEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("NatNodeEventListener: DataChange listener registration fail!", e);
+            throw new IllegalStateException("NatNodeEventListener: registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<Node> getWildCardPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Node> identifier, Node del) {
+        LOG.debug("NatNodeEventListener: Node removed received");
+        NodeId nodeId = del.getId();
+        String[] node =  nodeId.getValue().split(":");
+        if(node.length < 2) {
+            LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+            return;
+        }
+        BigInteger dpnId = new BigInteger(node[1]);
+        LOG.debug("NodeId removed is {}",dpnId);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Node> identifier, Node add) {
+        LOG.debug("NatNodeEventListener: Node added received");
+        NodeId nodeId = add.getId();
+        String[] node =  nodeId.getValue().split(":");
+        if(node.length < 2) {
+            LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+            return;
+        }
+        BigInteger dpnId = new BigInteger(node[1]);
+        LOG.debug("NodeId added is {}",dpnId);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("NatNodeEventListener Closed");
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatServiceProvider.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatServiceProvider.java
new file mode 100644 (file)
index 0000000..dadf280
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.bgpmanager.api.IBgpManager;
+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.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+public class NatServiceProvider implements BindingAwareProvider, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NatServiceProvider.class);
+    private IMdsalApiManager mdsalManager;
+    private RpcProviderRegistry rpcProviderRegistry;
+    private NotificationService notificationService;
+    private ItmRpcService itmManager;
+    private FloatingIPListener floatingIpListener;
+    private ExternalNetworkListener extNwListener;
+    private NaptManager naptManager;
+    private NaptEventHandler naptEventHandler;
+    private BlockingQueue<NAPTEntryEvent> naptEventQueue;
+    private ExternalNetworksChangeListener externalNetworksChangeListener;
+    private ExternalRoutersListener externalRouterListener;
+    private NaptPacketInHandler naptPacketInHandler;
+    private EventDispatcher eventDispatcher;
+    private IBgpManager bgpManager;
+    private NaptFlowRemovedEventHandler naptFlowRemovedEventHandler;
+    private InterfaceStateEventListener interfaceStateEventListener;
+    private NatNodeEventListener natNodeEventListener;
+    private NAPTSwitchSelector naptSwitchSelector;
+    private RouterPortsListener routerPortsListener;
+
+    public NatServiceProvider(RpcProviderRegistry rpcProviderRegistry) {
+        this.rpcProviderRegistry = rpcProviderRegistry;
+    }
+
+    public void setNotificationService(NotificationService notificationService) {
+        this.notificationService = notificationService;
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setBgpManager(IBgpManager bgpManager) {
+        LOG.debug("BGP Manager reference initialized");
+        this.bgpManager = bgpManager;
+    }
+
+    @Override
+    public void close() throws Exception {
+        floatingIpListener.close();
+        extNwListener.close();
+        externalNetworksChangeListener.close();
+        externalRouterListener.close();
+        routerPortsListener.close();
+    }
+
+    @Override
+    public void onSessionInitiated(ProviderContext session) {
+        LOG.info("NAT Manager Provider Session Initiated");
+        try {
+            //Get the DataBroker, PacketProcessingService, IdManagerService and the OdlInterfaceRpcService instances
+            final  DataBroker dataBroker = session.getSALService(DataBroker.class);
+            PacketProcessingService pktProcessingService = session.getRpcService(PacketProcessingService.class);
+            IdManagerService idManager = rpcProviderRegistry.getRpcService(IdManagerService.class);
+            OdlInterfaceRpcService interfaceService = rpcProviderRegistry.getRpcService(OdlInterfaceRpcService.class);
+            NeutronvpnService neutronvpnService = rpcProviderRegistry.getRpcService(NeutronvpnService.class);
+            itmManager = rpcProviderRegistry.getRpcService(ItmRpcService.class);
+
+            //Instantiate FloatingIPListener and set the MdsalManager and OdlInterfaceRpcService in it.
+            floatingIpListener = new FloatingIPListener(dataBroker);
+            floatingIpListener.setInterfaceManager(interfaceService);
+            floatingIpListener.setMdsalManager(mdsalManager);
+
+            //Instantiate ExternalNetworkListener and set the MdsalManager in it.
+            extNwListener = new ExternalNetworkListener(dataBroker);
+            extNwListener.setMdsalManager(mdsalManager);
+
+            //Instantiate NaptManager and set the IdManagerService in it.
+            naptManager = new NaptManager(dataBroker);
+            naptManager.setIdManager(idManager);
+
+            //Instantiate NaptEventHandler and start it as a Thread.
+            naptEventHandler = new NaptEventHandler(dataBroker);
+            naptEventHandler.setMdsalManager(mdsalManager);
+            naptEventHandler.setNaptManager(naptManager);
+            naptEventQueue = new ArrayBlockingQueue<>(NatConstants.EVENT_QUEUE_LENGTH);
+            eventDispatcher = new EventDispatcher(naptEventQueue, naptEventHandler);
+            new Thread(eventDispatcher).start();
+
+            //Instantiate NaptPacketInHandler and register it in the notification service.
+            naptPacketInHandler = new NaptPacketInHandler(eventDispatcher);
+            notificationService.registerNotificationListener(naptPacketInHandler);
+
+            //Floating ip Handler
+            VpnRpcService vpnService = rpcProviderRegistry.getRpcService(VpnRpcService.class);
+            FibRpcService fibService = rpcProviderRegistry.getRpcService(FibRpcService.class);
+            VpnFloatingIpHandler handler = new VpnFloatingIpHandler(vpnService, bgpManager, fibService);
+            handler.setBroker(dataBroker);
+            handler.setMdsalManager(mdsalManager);
+            handler.setListener(floatingIpListener);
+            floatingIpListener.setFloatingIpHandler(handler);
+
+            //Instantiate NaptSwitchSelector and set the dataBroker in it.
+            naptSwitchSelector = new NAPTSwitchSelector( dataBroker );
+
+            //Instantiate ExternalRouterListener and set the dataBroker in it.
+            externalRouterListener = new ExternalRoutersListener( dataBroker );
+            externalRouterListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker );
+            externalRouterListener.setMdsalManager(mdsalManager);
+            externalRouterListener.setItmManager(itmManager);
+            externalRouterListener.setInterfaceManager(interfaceService);
+            externalRouterListener.setIdManager(idManager);
+            externalRouterListener.setNaptManager(naptManager);
+            externalRouterListener.setBgpManager(bgpManager);
+            externalRouterListener.setFibService(fibService);
+            externalRouterListener.setVpnService(vpnService);
+            externalRouterListener.setNaptSwitchSelector(naptSwitchSelector);
+            externalRouterListener.setNaptEventHandler(naptEventHandler);
+            externalRouterListener.setNaptPacketInHandler(naptPacketInHandler);
+
+            //Instantiate ExternalNetworksChangeListener and set the dataBroker in it.
+            externalNetworksChangeListener = new ExternalNetworksChangeListener( dataBroker );
+            externalNetworksChangeListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+            externalNetworksChangeListener.setMdsalManager(mdsalManager);
+            externalNetworksChangeListener.setInterfaceManager(interfaceService);
+            externalNetworksChangeListener.setFloatingIpListener(floatingIpListener);
+            externalNetworksChangeListener.setBgpManager(bgpManager);
+            externalNetworksChangeListener.setFibService(fibService);
+            externalNetworksChangeListener.setVpnService(vpnService);
+            externalNetworksChangeListener.setExternalRoutersListener(externalRouterListener);
+            externalNetworksChangeListener.setNaptManager(naptManager);
+            externalNetworksChangeListener.setExternalRoutersListener(externalRouterListener);
+
+            //Instantiate NaptFlowRemovedHandler and register it in the notification service.
+            naptFlowRemovedEventHandler = new NaptFlowRemovedEventHandler(eventDispatcher, dataBroker, naptPacketInHandler, mdsalManager, naptManager);
+            notificationService.registerNotificationListener(naptFlowRemovedEventHandler);
+
+            //Instantiate interfaceStateEventListener and set the MdsalManager in it.
+            interfaceStateEventListener = new InterfaceStateEventListener(dataBroker);
+            interfaceStateEventListener.setMdsalManager(mdsalManager);
+            interfaceStateEventListener.setFloatingIpListener(floatingIpListener);
+            interfaceStateEventListener.setNeutronVpnService(neutronvpnService);
+            interfaceStateEventListener.setNaptManager(naptManager);
+
+            SNATDefaultRouteProgrammer defaultRouteProgrammer = new SNATDefaultRouteProgrammer(mdsalManager);
+            DpnInVpnListener dpnInVpnListener = new DpnInVpnListener(dataBroker);
+            dpnInVpnListener.setDefaultProgrammer(defaultRouteProgrammer);
+            notificationService.registerNotificationListener(dpnInVpnListener);
+
+            externalRouterListener.setDefaultProgrammer(defaultRouteProgrammer);
+
+            NaptSwitchHA naptSwitchHA = new NaptSwitchHA(dataBroker,naptSwitchSelector);
+            naptSwitchHA.setIdManager(idManager);
+            naptSwitchHA.setInterfaceManager(interfaceService);
+            naptSwitchHA.setMdsalManager(mdsalManager);
+            naptSwitchHA.setItmManager(itmManager);
+            naptSwitchHA.setBgpManager(bgpManager);
+            naptSwitchHA.setFibService(fibService);
+            naptSwitchHA.setVpnService(vpnService);
+            naptSwitchHA.setExternalRoutersListener(externalRouterListener);
+
+            natNodeEventListener = new NatNodeEventListener(dataBroker,naptSwitchHA);
+
+            dpnInVpnListener.setNaptSwitchHA(naptSwitchHA);
+            dpnInVpnListener.setMdsalManager(mdsalManager);
+            dpnInVpnListener.setIdManager(idManager);
+
+            routerPortsListener = new RouterPortsListener(dataBroker);
+
+            RouterDpnChangeListener routerDpnChangeListener = new RouterDpnChangeListener(dataBroker);
+            routerDpnChangeListener.setDefaultProgrammer(defaultRouteProgrammer);
+            routerDpnChangeListener.setIdManager(idManager);
+            routerDpnChangeListener.setMdsalManager(mdsalManager);
+            routerDpnChangeListener.setNaptSwitchHA(naptSwitchHA);
+
+            RouterToVpnListener routerToVpnListener = new RouterToVpnListener(dataBroker);
+            routerToVpnListener.setFloatingIpListener(floatingIpListener);
+            routerToVpnListener.setInterfaceManager(interfaceService);
+            routerToVpnListener.setExternalRoutersListener(externalRouterListener);
+            notificationService.registerNotificationListener(routerToVpnListener);
+        } catch (Exception e) {
+            LOG.error("Error initializing NAT Manager service", e);
+        }
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatUtil.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NatUtil.java
new file mode 100644 (file)
index 0000000..acca746
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCounters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCountersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.RouterToVpnMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.Routermapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.RoutermappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.FloatingIpInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.NeutronRouterDpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.VpnMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMapKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+
+import com.google.common.base.Optional;
+
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.NetworksKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfoKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+
+
+public class NatUtil {
+
+    private static String OF_URI_SEPARATOR = ":";
+    private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);
+
+    /*
+        getCookieSnatFlow() computes and returns a unique cookie value for the NAT flows using the router ID as the reference value.
+     */
+    public static BigInteger getCookieSnatFlow(long routerId) {
+        return NatConstants.COOKIE_NAPT_BASE.add(new BigInteger("0110000", 16)).add(
+                BigInteger.valueOf(routerId));
+    }
+
+    /*
+        getCookieNaptFlow() computes and returns a unique cookie value for the NAPT flows using the router ID as the reference value.
+    */
+    public static BigInteger getCookieNaptFlow(long routerId) {
+        return NatConstants.COOKIE_NAPT_BASE.add(new BigInteger("0111000", 16)).add(
+                BigInteger.valueOf(routerId));
+    }
+
+    /*
+        getVpnId() returns the VPN ID from the VPN name
+     */
+    public static long getVpnId(DataBroker broker, String vpnName) {
+        if(vpnName == null) {
+            return NatConstants.INVALID_ID;
+        }
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+                = getVpnInstanceToVpnIdIdentifier(vpnName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+                = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+        long vpnId = NatConstants.INVALID_ID;
+        if(vpnInstance.isPresent()) {
+            vpnId = vpnInstance.get().getVpnId();
+        }
+        return vpnId;
+    }
+
+    public static Long getVpnId(DataBroker broker, long routerId){
+        //Get the external network ID from the ExternalRouter model
+        Uuid networkId = NatUtil.getNetworkIdFromRouterId(broker, routerId);
+        if(networkId == null ){
+            LOG.error("NAT Service : networkId is null");
+            return null;
+        }
+
+        //Get the VPN ID from the ExternalNetworks model
+        Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(broker, networkId);
+        if(vpnUuid == null ){
+            LOG.error("NAT Service : vpnUuid is null");
+            return null;
+        }
+        Long vpnId = NatUtil.getVpnId(broker, vpnUuid.getValue());
+        return vpnId;
+    }
+
+    static InstanceIdentifier<RouterPorts> getRouterPortsId(String routerId) {
+        return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId)).build();
+    }
+
+    static InstanceIdentifier<Routermapping> getRouterVpnMappingId(String routerId) {
+        return InstanceIdentifier.builder(RouterToVpnMapping.class).child(Routermapping.class, new RoutermappingKey(routerId)).build();
+    }
+
+    static InstanceIdentifier<Ports> getPortsIdentifier(String routerId, String portName) {
+        return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId))
+                                                               .child(Ports.class, new PortsKey(portName)).build();
+    }
+
+    static InstanceIdentifier<IpMapping> getIpMappingIdentifier(String routerId, String portName, String internalIp) {
+        return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId))
+                                                               .child(Ports.class, new PortsKey(portName))
+                                                               .child(IpMapping.class, new IpMappingKey(internalIp)).build();
+    }
+
+    /*
+        getVpnInstanceToVpnIdIdentifier() returns the VPN instance from the below model using the VPN name as the key.
+            list vpn-instance {
+                key "vpn-instance-name"
+                leaf vpn-instance-name {
+                    type string;
+                }
+                leaf vpn-id {
+                    type uint32;
+                }
+                leaf vrf-id {
+                    type string;
+                }
+            }
+    */
+
+    static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
+    getVpnInstanceToVpnIdIdentifier(String vpnName) {
+        return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
+    }
+
+     /*
+        getFlowRef() returns a string identfier for the SNAT flows using the router ID as the reference.
+     */
+    public static String getFlowRef(BigInteger dpnId, short tableId, long routerID, String ip) {
+        return new StringBuffer().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID)
+                .append(NatConstants.FLOWID_SEPARATOR).append(ip).toString();
+    }
+
+    public static String getNaptFlowRef(BigInteger dpnId, short tableId, String routerID, String ip, int port) {
+        return new StringBuffer().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).append(NatConstants.FLOWID_SEPARATOR).append(ip).
+                append(NatConstants.FLOWID_SEPARATOR).append(port).toString();
+    }
+
+    /*
+        getNetworkIdFromRouterId() returns the network-id from the below model using the router-id as the key
+               container ext-routers {
+                   list routers {
+                       key router-name;
+                       leaf router-name { type string; }
+                       leaf network-id { type yang:uuid; }
+                       leaf enable-snat { type boolean; }
+                       leaf-list external-ips {
+                            type string; //format - ipaddress\prefixlength
+                       }
+                       leaf-list subnet-ids { type yang:uuid; }
+                   }
+               }
+
+    */
+    static Uuid getNetworkIdFromRouterId(DataBroker broker, long routerId) {
+        String routerName = getRouterName(broker, routerId);
+        InstanceIdentifier id = buildRouterIdentifier(routerName);
+        Optional<Routers> routerData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (routerData.isPresent()) {
+            return routerData.get().getNetworkId();
+        }
+        return null;
+    }
+
+    static InstanceIdentifier<Routers> buildRouterIdentifier(String routerId) {
+        InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class).child
+                (Routers.class, new RoutersKey(routerId)).build();
+        return routerInstanceIndentifier;
+    }
+
+    /*
+     * getEnableSnatFromRouterId() returns IsSnatEnabled true is routerID is present in external n/w otherwise returns false
+     */
+    static boolean isSnatEnabledForRouterId(DataBroker broker, String routerId){
+        InstanceIdentifier id = buildRouterIdentifier(routerId);
+        Optional<Routers> routerData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (routerData.isPresent()) {
+            return routerData.get().isEnableSnat();
+        }
+        return false;
+    }
+    /*
+        getVpnIdfromNetworkId() returns the vpnid from the below model using the network ID as the key.
+            container external-networks {
+                list networks  {
+                    key id;
+                    leaf id {
+                        type yang:uuid;
+                    }
+                    leaf vpnid { type yang:uuid; }
+                    leaf-list router-ids { type yang:uuid; }
+                    leaf-list subnet-ids{ type yang:uuid; }
+                }
+            }
+    */
+    public static Uuid getVpnIdfromNetworkId(DataBroker broker, Uuid networkId) {
+        InstanceIdentifier id = buildNetworkIdentifier(networkId);
+        Optional<Networks> networkData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (networkData.isPresent()) {
+            return networkData.get().getVpnid();
+        }
+        return null;
+    }
+
+    static String getAssociatedExternalNetwork(DataBroker dataBroker, String routerId) {
+        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        if (routerData.isPresent()) {
+            Uuid networkId = routerData.get().getNetworkId();
+            if(networkId != null) {
+                return networkId.getValue();
+            }
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<Networks> buildNetworkIdentifier(Uuid networkId) {
+        InstanceIdentifier<Networks> network = InstanceIdentifier.builder(ExternalNetworks.class).child
+                (Networks.class, new NetworksKey(networkId)).build();
+        return network;
+    }
+
+
+
+
+    /*
+        getNaptSwitchesDpnIdsfromRouterId() returns the primary-switch-id and the secondary-switch-id in a array using the router-id; as the key.
+            container napt-switches {
+                list router-to-napt-switch {
+                    key router-id;
+                    leaf router-id { type uint32; }
+                    leaf primary-switch-id { type uint64; }
+                    leaf secondary-switch-id { type uint64; }
+                }
+            }
+    */
+    public static BigInteger getPrimaryNaptfromRouterId(DataBroker broker, Long routerId) {
+        // convert routerId to Name
+        String routerName = getRouterName(broker, routerId);
+        InstanceIdentifier id = buildNaptSwitchIdentifier(routerName);
+        Optional<RouterToNaptSwitch> routerToNaptSwitchData = read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (routerToNaptSwitchData.isPresent()) {
+            RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
+            return routerToNaptSwitchInstance.getPrimarySwitchId();
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<RouterToNaptSwitch> buildNaptSwitchIdentifier(String routerId) {
+        InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class).child
+                (RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerId)).build();
+        return rtrNaptSw;
+    }
+
+    public static String getRouterName(DataBroker broker, Long routerId) {
+        InstanceIdentifier id = buildRouterIdentifier(routerId);
+        Optional<RouterIds> routerIdsData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (routerIdsData.isPresent()) {
+            RouterIds routerIdsInstance = routerIdsData.get();
+            return routerIdsInstance.getRouterName();
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<RouterIds> buildRouterIdentifier(Long routerId) {
+        InstanceIdentifier<RouterIds> routerIds = InstanceIdentifier.builder(RouterIdName.class).child
+                (RouterIds.class, new RouterIdsKey(routerId)).build();
+        return routerIds;
+    }
+
+    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+                                                   InstanceIdentifier<T> path) {
+
+        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+        Optional<T> result = Optional.absent();
+        try {
+            result = tx.read(datastoreType, path).get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return result;
+    }
+
+    static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String vrfId) {
+        return InstanceIdentifier.builder(VpnInstanceOpData.class)
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vrfId)).build();
+    }
+
+    public static long readVpnId(DataBroker broker, String vpnName) {
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+                = getVpnInstanceToVpnIdIdentifier(vpnName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+                = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+        long vpnId = NatConstants.INVALID_ID;
+        if(vpnInstance.isPresent()) {
+            vpnId = vpnInstance.get().getVpnId();
+        }
+        return vpnId;
+    }
+
+    public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, BigInteger cookie) {
+        FlowEntity flowEntity = new FlowEntity(dpnId);
+        flowEntity.setTableId(tableId);
+        flowEntity.setCookie(cookie);
+        return flowEntity;
+    }
+
+    public static long getIpAddress(byte[] rawIpAddress) {
+        return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
+                + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
+    }
+
+    public static String getFlowRef(BigInteger dpnId, short tableId, InetAddress destPrefix) {
+        return new StringBuilder(64).append(NatConstants.FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(destPrefix.getHostAddress()).toString();
+    }
+
+    public static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger dpnId) {
+        String nextHopIp = null;
+        InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
+            InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
+        Optional<DPNTEPsInfo> tunnelInfo = read(broker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
+        if (tunnelInfo.isPresent()) {
+          List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
+          if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
+            nextHopIp = nexthopIpList.get(0).getIpAddress().getIpv4Address().getValue();
+          }
+        }
+        return nextHopIp;
+      }
+
+    /*
+        getVpnRd returns the rd (route distinguisher) which is the VRF ID from the below model using the vpnName
+            list vpn-instance {
+                key "vpn-instance-name"
+                leaf vpn-instance-name {
+                    type string;
+                }
+                leaf vpn-id {
+                    type uint32;
+                }
+                leaf vrf-id {
+                    type string;
+                }
+            }
+    */
+    public static String getVpnRd(DataBroker broker, String vpnName) {
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+                = getVpnInstanceToVpnIdIdentifier(vpnName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+                = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+        String rd = null;
+        if(vpnInstance.isPresent()) {
+            rd = vpnInstance.get().getVrfId();
+        }
+        return rd;
+    }
+
+    /*  getExternalIPPortMap() returns the internal IP and the port for the querried router ID, external IP and the port.
+        container intext-ip-port-map {
+        config true;
+        list ip-port-mapping {
+            key router-id;
+            leaf router-id { type uint32; }
+            list intext-ip-protocol-type {
+                key protocol;
+                leaf protocol { type protocol-types; }
+                list ip-port-map {
+                    key ip-port-internal;
+                    description "internal to external ip-port mapping";
+                    leaf ip-port-internal { type string; }
+                    container ip-port-external {
+                       uses ip-port-entity;
+                    }
+                }
+            }
+         }
+       }
+    */
+    public static IpPortExternal getExternalIpPortMap(DataBroker broker, Long routerId, String internalIpAddress, String internalPort, NAPTEntryEvent.Protocol protocol) {
+        ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+        InstanceIdentifier ipPortMapId = buildIpToPortMapIdentifier(routerId, internalIpAddress, internalPort, protocolType);
+        Optional<IpPortMap> ipPortMapData = read(broker, LogicalDatastoreType.CONFIGURATION, ipPortMapId);
+        if (ipPortMapData.isPresent()) {
+            IpPortMap ipPortMapInstance = ipPortMapData.get();
+            return ipPortMapInstance.getIpPortExternal();
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<IpPortMap> buildIpToPortMapIdentifier(Long routerId, String internalIpAddress, String internalPort , ProtocolTypes protocolType) {
+        InstanceIdentifier<IpPortMap> ipPortMapId = InstanceIdentifier.builder(IntextIpPortMap.class).child
+                (IpPortMapping.class, new IpPortMappingKey(routerId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
+                .child(IpPortMap.class, new IpPortMapKey(internalIpAddress + ":" + internalPort)).build();
+        return ipPortMapId;
+    }
+
+    public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, String flowId, int priority, String flowName,
+                                             BigInteger cookie, List<MatchInfo> listMatchInfo) {
+
+        FlowEntity flowEntity = new FlowEntity(dpnId);
+        flowEntity.setTableId(tableId);
+        flowEntity.setFlowId(flowId);
+        flowEntity.setPriority(priority);
+        flowEntity.setFlowName(flowName);
+        flowEntity.setCookie(cookie);
+        flowEntity.setMatchInfoList(listMatchInfo);
+        return flowEntity;
+    }
+
+    static boolean isVpnInterfaceConfigured(DataBroker broker, String interfaceName)
+    {
+        InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
+        Optional<VpnInterface> configuredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId);
+
+        if (configuredVpnInterface.isPresent()) {
+            return true;
+        }
+        return false;
+    }
+
+    static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
+        return InstanceIdentifier.builder(VpnInterfaces.class)
+                .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
+    }
+
+    static VpnInterface getConfiguredVpnInterface(DataBroker broker, String interfaceName) {
+        InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
+        Optional<VpnInterface> configuredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId);
+
+        if (configuredVpnInterface.isPresent()) {
+            return configuredVpnInterface.get();
+        }
+        return null;
+    }
+
+    public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
+        /*
+         * NodeConnectorId is of form 'openflow:dpnid:portnum'
+         */
+        String[] split = portId.getValue().split(OF_URI_SEPARATOR);
+        return split[1];
+    }
+
+    public static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
+        String lowerLayerIf = ifState.getLowerLayerIf().get(0);
+        NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
+        return new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
+    }
+
+
+    /*
+    container vpnMaps {
+        list vpnMap {
+            key vpn-id;
+            leaf vpn-id {
+                type    yang:uuid;
+                description "vpn-id";
+            }
+            leaf name {
+                type  string;
+                description "vpn name";
+            }
+            leaf tenant-id {
+                type    yang:uuid;
+                description "The UUID of the tenant that will own the subnet.";
+            }
+
+            leaf router-id {
+              type    yang:uuid;
+              description "UUID of router ";
+            }
+            leaf-list network_ids {
+              type    yang:uuid;
+              description "UUID representing the network ";
+            }
+        }
+    }
+    Method returns router Id associated to a VPN
+     */
+
+    public static String getRouterIdfromVpnId(DataBroker broker,String vpnName){
+        InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
+                .child(VpnMap.class, new VpnMapKey(new Uuid(vpnName))).build();
+        Optional<VpnMap> optionalVpnMap = read(broker, LogicalDatastoreType.CONFIGURATION,
+                vpnMapIdentifier);
+        if (optionalVpnMap.isPresent()) {
+            return optionalVpnMap.get().getRouterId().getValue();
+        }
+        return null;
+    }
+
+    static Uuid getVpnForRouter(DataBroker broker, String routerId) {
+        InstanceIdentifier<VpnMaps> vpnMapsIdentifier = InstanceIdentifier.builder(VpnMaps.class).build();
+        Optional<VpnMaps> optionalVpnMaps = read(broker, LogicalDatastoreType.CONFIGURATION,
+                vpnMapsIdentifier);
+        if (optionalVpnMaps.isPresent() && optionalVpnMaps.get().getVpnMap() != null) {
+            List<VpnMap> allMaps = optionalVpnMaps.get().getVpnMap();
+            if (routerId != null) {
+                for (VpnMap vpnMap : allMaps) {
+                    if (vpnMap.getRouterId() != null && 
+                        routerId.equals(vpnMap.getRouterId().getValue()) && 
+                        !routerId.equals(vpnMap.getVpnId().getValue())) {
+                            return vpnMap.getVpnId();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    static long getAssociatedVpn(DataBroker broker, String routerName) {
+        InstanceIdentifier<Routermapping> routerMappingId = NatUtil.getRouterVpnMappingId(routerName);
+        Optional<Routermapping> optRouterMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, routerMappingId);
+        if(optRouterMapping.isPresent()) {
+            Routermapping routerMapping = optRouterMapping.get();
+            return routerMapping.getVpnId();
+        }
+        return NatConstants.INVALID_ID;
+    }
+
+
+    public static List<VpnToDpnList> getVpnToDpnList(DataBroker dataBroker, String vrfId )
+    {
+        List<VpnToDpnList> vpnDpnList = null;
+
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier
+                .builder(VpnInstanceOpData.class)
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vrfId))
+                .build();
+
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+
+        if(vpnInstanceOpData.isPresent())
+        {
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpData.get();
+            vpnDpnList = vpnInstanceOpDataEntry.getVpnToDpnList();
+        }
+
+        return vpnDpnList;
+    }
+
+    public static String getAssociatedVPN(DataBroker dataBroker, Uuid networkId, Logger log) {
+        Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+        if(vpnUuid == null ){
+            log.error("No VPN instance associated with ext network {}", networkId);
+            return null;
+        }
+        return vpnUuid.getValue();
+    }
+
+    public static void addPrefixToBGP(IBgpManager bgpManager, String rd, String prefix, String nextHopIp, long label, Logger log) {
+        try {
+            bgpManager.addPrefix(rd, prefix, nextHopIp, (int)label);
+        } catch(Exception e) {
+            log.error("Add prefix failed", e);
+        }
+    }
+
+    static InstanceIdentifier<Ports> buildPortToIpMapIdentifier(String routerId, String portName) {
+        InstanceIdentifier<Ports> ipPortMapId = InstanceIdentifier.builder(FloatingIpInfo.class).child
+                (RouterPorts.class, new RouterPortsKey(routerId)).child(Ports.class, new PortsKey(portName)).build();
+        return ipPortMapId;
+    }
+
+    static InstanceIdentifier<RouterPorts> buildRouterPortsIdentifier(String routerId) {
+        InstanceIdentifier<RouterPorts> routerInstanceIndentifier = InstanceIdentifier.builder(FloatingIpInfo.class).child
+                (RouterPorts.class, new RouterPortsKey(routerId)).build();
+        return routerInstanceIndentifier;
+    }
+
+    /* container snatint-ip-port-map {
+        list intip-port-map {
+            key router-id;
+            leaf router-id { type uint32; }
+            list ip-port {
+                key internal-ip;
+                leaf internal-ip { type string; }
+                list int-ip-proto-type {
+                    key protocol;
+                    leaf protocol { type protocol-types; }
+                    leaf-list ports { type uint16; }
+                }
+            }
+        }
+    }
+    Method returns InternalIp port List
+    */
+
+    public static List<Integer> getInternalIpPortListInfo(DataBroker dataBroker,Long routerId, String internalIpAddress, ProtocolTypes protocolType){
+        Optional<IntIpProtoType> optionalIpProtoType = read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSnatIntIpPortIdentifier(routerId, internalIpAddress, protocolType));
+        if (optionalIpProtoType.isPresent()) {
+            return optionalIpProtoType.get().getPorts();
+        }
+        return null;
+    }
+
+    public static InstanceIdentifier<IntIpProtoType> buildSnatIntIpPortIdentifier(Long routerId, String internalIpAddress, ProtocolTypes protocolType) {
+        InstanceIdentifier<IntIpProtoType> intIpProtocolTypeId = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+                (IntipPortMap.class, new IntipPortMapKey(routerId)).child(IpPort.class, new IpPortKey(internalIpAddress)).child
+                (IntIpProtoType.class, new IntIpProtoTypeKey(protocolType)).build();
+        return intIpProtocolTypeId;
+    }
+
+    public static ProtocolTypes getProtocolType(NAPTEntryEvent.Protocol protocol) {
+        ProtocolTypes protocolType = ProtocolTypes.TCP.toString().equals(protocol.toString()) ? ProtocolTypes.TCP : ProtocolTypes.UDP;
+        return protocolType;
+    }
+
+    public static NaptSwitches getNaptSwitch(DataBroker broker) {
+        Optional<NaptSwitches> switchesOptional = read(broker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
+        if(switchesOptional.isPresent()) {
+            return switchesOptional.get();
+        }
+        return null;
+    }
+
+    public static InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
+        return InstanceIdentifier.create(NaptSwitches.class);
+    }
+
+    public static InstanceIdentifier<RouterToNaptSwitch> buildNaptSwitchRouterIdentifier(String routerId) {
+        return InstanceIdentifier.create(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerId));
+    }
+
+    public static String toStringIpAddress(byte[] ipAddress, Logger log)
+    {
+      String ip = "";
+      if (ipAddress == null) {
+        return ip;
+      }
+
+      try {
+        ip = InetAddress.getByAddress(ipAddress).getHostAddress();
+      } catch(UnknownHostException e) {
+        log.error("NAT Service : Caught exception during toStringIpAddress()");
+      }
+
+      return ip;
+    }
+
+    public static String getGroupIdKey(String routerName){
+        String groupIdKey = new String("snatmiss." + routerName);
+        return groupIdKey;
+    }
+
+    public static long createGroupId(String groupIdKey,IdManagerService idManager) {
+        AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+                .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
+                .build();
+        try {
+            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+            RpcResult<AllocateIdOutput> rpcResult = result.get();
+            return rpcResult.getResult().getIdValue();
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.trace("", e);
+        }
+        return 0;
+    }
+
+    public static void removePrefixFromBGP(IBgpManager bgpManager, String rd, String prefix, Logger log) {
+        try {
+            bgpManager.deletePrefix(rd, prefix);
+        } catch(Exception e) {
+            log.error("Delete prefix failed", e);
+        }
+    }
+
+    public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, BigInteger cookie, String flowId) {
+        FlowEntity flowEntity = new FlowEntity(dpnId);
+        flowEntity.setTableId(tableId);
+        flowEntity.setCookie(cookie);
+        flowEntity.setFlowId(flowId);
+        return flowEntity;
+    }
+
+    public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, String flowId) {
+        FlowEntity flowEntity = new FlowEntity(dpnId);
+        flowEntity.setTableId(tableId);
+        flowEntity.setFlowId(flowId);
+        return flowEntity;
+    }
+
+    public static IpPortMapping getIportMapping(DataBroker broker, long routerId) {
+        Optional<IpPortMapping> getIportMappingData = read(broker, LogicalDatastoreType.CONFIGURATION, getIportMappingIdentifier(routerId));
+        if(getIportMappingData.isPresent()) {
+            return getIportMappingData.get();
+        }
+        return null;
+    }
+
+    public static InstanceIdentifier<IpPortMapping> getIportMappingIdentifier(long routerId) {
+        return InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
+    }
+
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> getIpMappingBuilder(Long routerId) {
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey(routerId)).build();
+        return idBuilder;
+    }
+
+    public static List<String> getExternalIpsForRouter(DataBroker dataBroker,Long routerId) {
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> ipMappingOptional = read(dataBroker,
+                LogicalDatastoreType.OPERATIONAL, getIpMappingBuilder(routerId));
+        List<String> externalIps = new ArrayList<>();
+        if (ipMappingOptional.isPresent()) {
+            List<IpMap> ipMaps = ipMappingOptional.get().getIpMap();
+            for (IpMap ipMap : ipMaps) {
+                externalIps.add(ipMap.getExternalIp());
+            }
+            return externalIps;
+        }
+        return null;
+    }
+
+    /*
+    container external-ips-counter {
+        config false;
+        list external-counters{
+            key segment-id;
+            leaf segment-id { type uint32; }
+            list external-ip-counter {
+                key external-ip;
+                leaf external-ip { type string; }
+                leaf counter { type uint8; }
+            }
+        }
+    }
+    */
+
+    public static String getLeastLoadedExternalIp(DataBroker dataBroker, long segmentId){
+        String leastLoadedExternalIp =  null;
+        InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId)).build();
+        Optional <ExternalCounters> externalCountersData = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        if (externalCountersData.isPresent()) {
+            ExternalCounters externalCounter = externalCountersData.get();
+            List<ExternalIpCounter> externalIpCounterList = externalCounter.getExternalIpCounter();
+            short countOfLstLoadExtIp = 32767;
+            for(ExternalIpCounter externalIpCounter : externalIpCounterList){
+                String curExternalIp = externalIpCounter.getExternalIp();
+                short countOfCurExtIp  = externalIpCounter.getCounter();
+                if( countOfCurExtIp < countOfLstLoadExtIp ){
+                    countOfLstLoadExtIp = countOfCurExtIp;
+                    leastLoadedExternalIp = curExternalIp;
+                }
+            }
+        }
+        return leastLoadedExternalIp;
+    }
+
+    public static String[] getSubnetIpAndPrefix(DataBroker dataBroker, Uuid subnetId){
+        String subnetIP = getSubnetIp(dataBroker, subnetId);
+        if(subnetId != null){
+            return getSubnetIpAndPrefix(subnetIP);
+        }
+        return null;
+    }
+
+    public static String getSubnetIp(DataBroker dataBroker, Uuid subnetId){
+        InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
+                .builder(Subnetmaps.class)
+                .child(Subnetmap.class, new SubnetmapKey(subnetId))
+                .build();
+        Optional<Subnetmap> removedSubnet = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
+        if(removedSubnet.isPresent()) {
+            Subnetmap subnetMapEntry = removedSubnet.get();
+            return subnetMapEntry.getSubnetIp();
+        }
+        return null;
+
+    }
+    public static String[] getSubnetIpAndPrefix(String subnetString){
+        String[] subnetSplit = subnetString.split("/");
+        String subnetIp = subnetSplit[0];
+        String subnetPrefix = "0";
+        if (subnetSplit.length == 2) {
+            subnetPrefix = subnetSplit[1];
+        }
+        return new String[] {subnetIp, subnetPrefix};
+    }
+
+    public static String[] getExternalIpAndPrefix(String leastLoadedExtIpAddr){
+        String[] leastLoadedExtIpAddrSplit = leastLoadedExtIpAddr.split("/");
+        String leastLoadedExtIp = leastLoadedExtIpAddrSplit[0];
+        String leastLoadedExtIpPrefix = String.valueOf(NatConstants.DEFAULT_PREFIX);
+        if (leastLoadedExtIpAddrSplit.length == 2) {
+            leastLoadedExtIpPrefix = leastLoadedExtIpAddrSplit[1];
+        }
+        return new String[] {leastLoadedExtIp, leastLoadedExtIpPrefix};
+    }
+
+    public static List<BigInteger> getDpnsForRouter(DataBroker dataBroker, String routerUuid){
+        InstanceIdentifier id = InstanceIdentifier.builder(NeutronRouterDpns.class).child(RouterDpnList.class, new RouterDpnListKey(routerUuid)).build();
+        Optional<RouterDpnList> routerDpnListData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        List<BigInteger> dpns = new ArrayList<>();
+        if (routerDpnListData.isPresent()) {
+            List<DpnVpninterfacesList> dpnVpninterfacesList = routerDpnListData.get().getDpnVpninterfacesList();
+            for (DpnVpninterfacesList dpnVpnInterface : dpnVpninterfacesList) {
+                dpns.add(dpnVpnInterface.getDpnId());
+            }
+            return dpns;
+        }
+        return null;
+    }
+
+    public static long getBgpVpnId(DataBroker dataBroker, String routerName){
+        long bgpVpnId = NatConstants.INVALID_ID;
+        Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+        if(bgpVpnUuid != null){
+            bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+        }
+        return bgpVpnId;
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterDpnChangeListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterDpnChangeListener.java
new file mode 100644 (file)
index 0000000..82e8c4b
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.List;
+
+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.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.NeutronRouterDpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class RouterDpnChangeListener extends AbstractDataChangeListener<DpnVpninterfacesList> implements AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker dataBroker;
+    private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+    private NaptSwitchHA naptSwitchHA;
+    private IMdsalApiManager mdsalManager;
+    private IdManagerService idManager;
+
+    public RouterDpnChangeListener (final DataBroker db) {
+        super(DpnVpninterfacesList.class);
+        dataBroker = db;
+        registerListener(db);
+    }
+
+    void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
+        this.defaultRouteProgrammer = defaultRouteProgrammer;
+    }
+
+    void setNaptSwitchHA(NaptSwitchHA switchHA) {
+        naptSwitchHA = switchHA;
+    }
+
+    void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("Router ports Listener Closed");
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), RouterDpnChangeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("RouterPorts DataChange listener registration fail!", e);
+            throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
+        return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class).child(DpnVpninterfacesList.class);
+    }
+
+    @Override
+    protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
+        LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
+        final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+        BigInteger dpnId = dpnInfo.getDpnId();
+        //check router is associated to external network
+        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        if (routerData.isPresent()) {
+            Uuid networkId = routerData.get().getNetworkId();
+            if(networkId != null) {
+                LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+                Uuid vpnName = NatUtil.getVpnForRouter(dataBroker,routerId);
+                Long vpnId;
+                if (vpnName == null) {
+                    LOG.debug("Internal vpn associated to router {}",routerId);
+                    vpnId = NatUtil.getVpnId(dataBroker,routerId);
+                    if (vpnId == NatConstants.INVALID_ID) {
+                        LOG.error("Invalid vpnId returned for routerName {}",routerId);
+                        return;
+                    }
+                    LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+                    //Install default entry in FIB to SNAT table
+                    LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...", dpnId,routerId,vpnId);
+                    defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
+                } else {
+                    LOG.debug("External BGP vpn associated to router {}",routerId);
+                    vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+                    if (vpnId == NatConstants.INVALID_ID) {
+                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                        return;
+                    }
+                    Long routId = NatUtil.getVpnId(dataBroker, routerId);
+                    if (routId == NatConstants.INVALID_ID) {
+                        LOG.error("Invalid routId returned for routerName {}",routerId);
+                        return;
+                    }
+                    LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+                    //Install default entry in FIB to SNAT table
+                    LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...", dpnId,routerId,vpnId);
+                    defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
+                }
+
+                if (routerData.get().isEnableSnat()) {
+                    LOG.info("SNAT enabled for router {}", routerId);
+                    handleSNATForDPN(dpnId, routerId ,vpnId);
+                } else {
+                    LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
+                }
+            }
+        } else {
+            LOG.debug("Router {} is not associated with External network", routerId);
+        }
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
+        LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
+        final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+        BigInteger dpnId = dpnInfo.getDpnId();
+        //check router is associated to external network
+        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        if (routerData.isPresent()) {
+            Uuid networkId = routerData.get().getNetworkId();
+            if (networkId != null) {
+                LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+                Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
+                Long vpnId;
+                if (vpnName == null) {
+                    LOG.debug("Internal vpn associated to router {}", routerId);
+                    vpnId = NatUtil.getVpnId(dataBroker, routerId);
+                    if (vpnId == NatConstants.INVALID_ID) {
+                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                        return;
+                    }
+                    LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+                    //Remove default entry in FIB
+                    LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+                    defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
+                } else {
+                    LOG.debug("External vpn associated to router {}", routerId);
+                    vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+                    if (vpnId == NatConstants.INVALID_ID) {
+                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                        return;
+                    }
+                    Long routId = NatUtil.getVpnId(dataBroker, routerId);
+                    if (routId == NatConstants.INVALID_ID) {
+                        LOG.error("Invalid routId returned for routerName {}",routerId);
+                        return;
+                    }
+                    LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+                    //Remove default entry in FIB
+                    LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+                    defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId,vpnId,routId);
+                }
+
+                if (routerData.get().isEnableSnat()) {
+                    LOG.info("SNAT enabled for router {}", routerId);
+                    removeSNATFromDPN(dpnId, routerId, vpnId);
+                } else {
+                    LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original, DpnVpninterfacesList update) {
+        LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
+    }
+    void handleSNATForDPN(BigInteger dpnId, String routerName,Long routerVpnId) {
+        //Check if primary and secondary switch are selected, If not select the role
+        //Install select group to NAPT switch
+        //Install default miss entry to NAPT switch
+        BigInteger naptSwitch;
+        try {
+            Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+            if (routerId == NatConstants.INVALID_ID) {
+                LOG.error("Invalid routerId returned for routerName {}", routerName);
+                return;
+            }
+            BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+            if (naptId == null || naptId.equals(BigInteger.ZERO)) {
+                LOG.debug("No NaptSwitch is selected for router {}", routerName);
+
+                naptSwitch = dpnId;
+                boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
+                if (!naptstatus) {
+                    LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
+                    return;
+                }
+                LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
+
+                //installing group
+                List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInPrimarySwitch();
+                naptSwitchHA.installSnatGroupEntry(naptSwitch, bucketInfo, routerName);
+
+                naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
+
+            } else {
+                LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
+                naptSwitch = naptId;
+
+                //installing group
+                List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
+                if (bucketInfo == null) {
+                    LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}", dpnId, routerName,
+                            naptSwitch);
+                    return;
+                }
+                naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
+            }
+            // Install miss entry (table 26) pointing to group
+            long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+            FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
+            if (flowEntity == null) {
+                LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}", routerName, dpnId, groupId);
+                return;
+            }
+            LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
+            mdsalManager.installFlow(flowEntity);
+        } catch (Exception ex) {
+            LOG.error("Exception in handleSNATForDPN method : {}", ex);
+        }
+    }
+
+    void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
+        //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
+        //remove miss entry to NAPT switch
+        //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
+
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("Invalid routerId returned for routerName {}",routerName);
+            return;
+        }
+        BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+        if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+            LOG.debug("No naptSwitch is selected for router {}", routerName);
+            return;
+        }
+        try {
+            boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId);
+            if (!naptStatus) {
+                LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+                        dpnId, routerName);
+            } else {
+                naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch);
+            }
+        } catch (Exception ex) {
+            LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);
+        }
+
+        long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+        FlowEntity flowEntity = null;
+        try {
+            flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
+            if (flowEntity == null) {
+                LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
+                return;
+            }
+            LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
+            mdsalManager.removeFlow(flowEntity);
+
+        } catch (Exception ex) {
+            LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
+            return;
+        }
+        LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
+
+        //remove group
+        GroupEntity groupEntity = null;
+        try {
+            groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+                    GroupTypes.GroupAll, null);
+            LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
+            mdsalManager.removeGroup(groupEntity);
+        } catch (Exception ex) {
+            LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
+            return;
+        }
+        LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterPortsListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterPortsListener.java
new file mode 100644 (file)
index 0000000..e58f861
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+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.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.vpnservice.natservice.rev160111.FloatingIpInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.Routermapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.RoutermappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.RoutermappingKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class RouterPortsListener extends AbstractDataChangeListener<RouterPorts> implements AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(RouterPortsListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker broker;
+
+
+    public RouterPortsListener (final DataBroker db) {
+        super(RouterPorts.class);
+        broker = db;
+        registerListener(db);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("Router ports Listener Closed");
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), RouterPortsListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("RouterPorts DataChange listener registration fail!", e);
+            throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
+        }
+    }
+
+    private InstanceIdentifier<RouterPorts> getWildCardPath() {
+        return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class);
+    }
+
+
+    @Override
+    protected void add(final InstanceIdentifier<RouterPorts> identifier, final RouterPorts routerPorts) {
+        LOG.trace("Add router ports method - key: " + identifier + ", value=" + routerPorts );
+        Optional<RouterPorts> optRouterPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+        if(optRouterPorts.isPresent()) {
+            RouterPorts ports = optRouterPorts.get();
+            String routerName = ports.getRouterId();
+            MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, 
+                new RouterPortsBuilder().setKey(new RouterPortsKey(routerName)).setRouterId(routerName)
+                    .setExternalNetworkId(routerPorts.getExternalNetworkId()).build());
+        } else {
+            String routerName = routerPorts.getRouterId();
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, identifier, 
+                new RouterPortsBuilder().setKey(new RouterPortsKey(routerName)).setRouterId(routerName)
+                        .setExternalNetworkId(routerPorts.getExternalNetworkId()).build());
+        }
+        //Check if the router is associated with any BGP VPN and update the association
+        String routerName = routerPorts.getRouterId();
+        Uuid vpnName = NatUtil.getVpnForRouter(broker, routerName);
+        if(vpnName != null) {
+            InstanceIdentifier<Routermapping> routerMappingId = NatUtil.getRouterVpnMappingId(routerName);
+            Optional<Routermapping> optRouterMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, routerMappingId);
+            if(!optRouterMapping.isPresent()){
+                Long vpnId = NatUtil.getVpnId(broker, vpnName.getValue());
+                LOG.debug("Updating router {} to VPN {} association with Id {}", routerName, vpnName, vpnId);
+                Routermapping routerMapping = new RoutermappingBuilder().setKey(new RoutermappingKey(routerName))
+                                                 .setRouterName(routerName).setVpnName(vpnName.getValue()).setVpnId(vpnId).build();
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerMappingId, routerMapping);
+            }
+        }
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<RouterPorts> identifier, RouterPorts routerPorts) {
+        LOG.trace("Remove router ports method - key: " + identifier + ", value=" + routerPorts );
+        //MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+        //Remove the router to vpn association mapping entry if at all present
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, NatUtil.getRouterVpnMappingId(routerPorts.getRouterId()));
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<RouterPorts> identifier, RouterPorts original, RouterPorts update) {
+        LOG.trace("Update router ports method - key: " + identifier + ", original=" + original + ", update=" + update );
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterToVpnListener.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/RouterToVpnListener.java
new file mode 100644 (file)
index 0000000..b127c41
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterAssociatedToVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterDisassociatedFromVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetAddedToVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetDeletedFromVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortAddedToSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortRemovedFromSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetUpdatedInVpn;
+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.base.Optional;
+
+public class RouterToVpnListener implements NeutronvpnListener {
+    private static final Logger LOG = LoggerFactory.getLogger(RouterToVpnListener.class);
+    private DataBroker dataBroker;
+    private FloatingIPListener floatingIpListener;
+    private OdlInterfaceRpcService interfaceManager;
+
+
+    private ExternalRoutersListener externalRoutersListener;
+
+    public RouterToVpnListener(DataBroker db) {
+        dataBroker = db;
+    }
+
+    void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+        this.interfaceManager = interfaceManager;
+    }
+
+    void setFloatingIpListener(FloatingIPListener floatingIpListener) {
+        this.floatingIpListener = floatingIpListener;
+    }
+
+    void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
+        this.externalRoutersListener = externalRoutersListener;
+    }
+
+    /**
+     * router association to vpn
+     *
+     */
+    @Override
+    public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
+        String routerName = notification.getRouterId().getValue();
+        String vpnName = notification.getVpnId().getValue();
+        //check router is associated to external network
+        String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName);
+        if(extNetwork != null) {
+            LOG.debug("Router {} is associated with ext nw {}", routerName, extNetwork);
+            handleDNATConfigurationForRouterAssociation(routerName, vpnName, extNetwork);
+            externalRoutersListener.changeLocalVpnIdToBgpVpnId(routerName, vpnName);
+        } else {
+            LOG.debug("Ignoring the Router {} association with VPN {} since it is not external router", routerName);
+        }
+
+    }
+
+    /**
+     * router disassociation from vpn
+     *
+     */
+    @Override
+    public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
+        String routerName = notification.getRouterId().getValue();
+        String vpnName = notification.getVpnId().getValue();
+        //check router is associated to external network
+        String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName);
+        if(extNetwork != null) {
+            LOG.debug("Router {} is associated with ext nw {}", routerName, extNetwork);
+            handleDNATConfigurationForRouterDisassociation(routerName, vpnName, extNetwork);
+            externalRoutersListener.changeBgpVpnIdToLocalVpnId(routerName, vpnName);
+        } else {
+            LOG.debug("Ignoring the Router {} association with VPN {} since it is not external router", routerName);
+        }
+    }
+
+    void handleDNATConfigurationForRouterAssociation(String routerName, String vpnName, String externalNetwork) {
+        InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
+        Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);
+        if(!optRouterPorts.isPresent()) {
+            LOG.debug("Could not read Router Ports data object with id: {} to handle associate vpn {}", routerName, vpnName);
+            return;
+        }
+        Uuid networkId = Uuid.getDefaultInstance(externalNetwork);
+        RouterPorts routerPorts = optRouterPorts.get();
+        List<Ports> interfaces = routerPorts.getPorts();
+        Map<String, BigInteger> portToDpnMap = new HashMap<>();
+        for(Ports port : interfaces) {
+            String portName = port.getPortName();
+            BigInteger dpnId = getDpnForInterface(interfaceManager, portName);
+            if(dpnId.equals(BigInteger.ZERO)) {
+                LOG.debug("DPN not found for {}, skip handling of router {} association with vpn", portName, routerName, vpnName);
+                continue;
+            }
+            portToDpnMap.put(portName, dpnId);
+            List<IpMapping> ipMapping = port.getIpMapping();
+            for(IpMapping ipMap : ipMapping) {
+                String externalIp = ipMap.getExternalIp();
+                //remove all NAT related entries with routerName
+                //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, null, ipMap.getInternalIp(), externalIp);
+                //Create NAT entries with VPN Id
+                LOG.debug("Updating DNAT flows with VPN metadata {} ", vpnName);
+                floatingIpListener.createNATOnlyFlowEntries(dpnId, portName, routerName, vpnName, networkId, ipMap.getInternalIp(), externalIp);
+            }
+        }
+    }
+
+    void handleDNATConfigurationForRouterDisassociation(String routerName, String vpnName, String externalNetwork) {
+        InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
+        Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);
+        if(!optRouterPorts.isPresent()) {
+            LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate vpn {}", routerName, vpnName);
+            return;
+        }
+        Uuid networkId = Uuid.getDefaultInstance(externalNetwork);
+        RouterPorts routerPorts = optRouterPorts.get();
+        List<Ports> interfaces = routerPorts.getPorts();
+        for(Ports port : interfaces) {
+            String portName = port.getPortName();
+            BigInteger dpnId = getDpnForInterface(interfaceManager, portName);
+            if(dpnId.equals(BigInteger.ZERO)) {
+                LOG.debug("DPN not found for {}, skip handling of router {} association with vpn", portName, routerName, vpnName);
+                continue;
+            }
+            List<IpMapping> ipMapping = port.getIpMapping();
+            for(IpMapping ipMap : ipMapping) {
+                String externalIp = ipMap.getExternalIp();
+                //remove all NAT related entries with routerName
+                //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, vpnName, ipMap.getInternalIp(), externalIp);
+                //Create NAT entries with VPN Id
+                floatingIpListener.createNATOnlyFlowEntries(dpnId, portName, routerName, null, networkId, ipMap.getInternalIp(), externalIp);
+            }
+        }
+    }
+
+    private BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
+        BigInteger nodeId = BigInteger.ZERO;
+        try {
+            GetDpidFromInterfaceInput
+                    dpIdInput =
+                    new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
+            Future<RpcResult<GetDpidFromInterfaceOutput>>
+                    dpIdOutput =
+                    interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
+            RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
+            if (dpIdResult.isSuccessful()) {
+                nodeId = dpIdResult.getResult().getDpid();
+            } else {
+                LOG.error("Could not retrieve DPN Id for interface {}", ifName);
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Exception when getting dpn for interface {}", ifName,  e);
+        }
+        return nodeId;
+    }
+
+    @Override
+    public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
+        throw new RuntimeException("Unsupported notification");
+    }
+
+    @Override
+    public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
+        throw new RuntimeException("Unsupported notification");
+    }
+
+    @Override
+    public void onPortAddedToSubnet(PortAddedToSubnet notification) {
+        throw new RuntimeException("Unsupported notification");
+    }
+
+    @Override
+    public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
+        throw new RuntimeException("Unsupported notification");
+    }
+
+    @Override
+    public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
+        throw new RuntimeException("Unsupported notification");
+    }
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SNATDefaultRouteProgrammer.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SNATDefaultRouteProgrammer.java
new file mode 100644 (file)
index 0000000..50ccd84
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SNATDefaultRouteProgrammer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SNATDefaultRouteProgrammer.class);
+    private IMdsalApiManager mdsalManager;
+
+    public SNATDefaultRouteProgrammer(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
+
+        InetAddress defaultIP = null;
+
+        try {
+            defaultIP = InetAddress.getByName("0.0.0.0");
+
+        } catch (UnknownHostException e) {
+            LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed  to build FIB Table Flow for Default Route to NAT table ");
+            return null;
+        }
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        //add match for default route "0.0.0.0/0"
+//        matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
+//                NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
+
+        //add match for vrfid
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
+
+        String flowRef = getFlowRefFib(dpId, NatConstants.L3_FIB_TABLE, vpnId);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+
+
+    }
+
+    private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long bgpVpnId, long routerId) {
+
+        InetAddress defaultIP = null;
+
+        try {
+            defaultIP = InetAddress.getByName("0.0.0.0");
+
+        } catch (UnknownHostException e) {
+            LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed  to build FIB Table Flow for Default Route to NAT table ");
+            return null;
+        }
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        //add match for default route "0.0.0.0/0"
+//        matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
+//                NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
+
+        //add match for vrfid
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(bgpVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
+
+        String flowRef = getFlowRefFib(dpId, NatConstants.L3_FIB_TABLE, routerId);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
+                NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+        return flowEntity;
+
+
+    }
+
+    private String getFlowRefFib(BigInteger dpnId, short tableId, long routerID) {
+        return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+    }
+
+    void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+        FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+        if(flowEntity == null) {
+            LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+            return;
+        }
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    void installDefNATRouteInDPN(BigInteger dpnId, long bgpVpnId, long routerId) {
+        FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, bgpVpnId, routerId);
+        if(flowEntity == null) {
+            LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+            return;
+        }
+        mdsalManager.installFlow(flowEntity);
+    }
+
+    void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+        FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+        if(flowEntity == null) {
+            LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+            return;
+        }
+        mdsalManager.removeFlow(flowEntity);
+    }
+
+    void removeDefNATRouteInDPN(BigInteger dpnId, long bgpVpnId, long routerId) {
+        FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, bgpVpnId, routerId);
+        if(flowEntity == null) {
+            LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+            return;
+        }
+        mdsalManager.removeFlow(flowEntity);
+    }
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SessionAddress.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/SessionAddress.java
new file mode 100644 (file)
index 0000000..eee5d4d
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+public class SessionAddress {
+
+    private String ipAddress;
+    private int portNumber;
+
+    public SessionAddress(String ipAddress, int portNumber) {
+        this.ipAddress = ipAddress;
+        this.portNumber = portNumber;
+    }
+    public String getIpAddress() {
+        return ipAddress;
+    }
+    public int getPortNumber() {
+        return portNumber;
+    }
+
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/VpnFloatingIpHandler.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/VpnFloatingIpHandler.java
new file mode 100644 (file)
index 0000000..46f65b4
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.vpnservice.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.concurrent.Future;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+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.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.AsyncFunction;
+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;
+
+public class VpnFloatingIpHandler implements FloatingIPHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
+    private VpnRpcService vpnService;
+    private FibRpcService fibService;
+    private IBgpManager bgpManager;
+    private DataBroker dataBroker;
+    private IMdsalApiManager mdsalManager;
+    private FloatingIPListener listener;
+
+    static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+    static final String FLOWID_PREFIX = "NAT.";
+    static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
+
+    public VpnFloatingIpHandler(VpnRpcService vpnService, IBgpManager bgpManager, FibRpcService fibService) {
+        this.vpnService = vpnService;
+        this.fibService = fibService;
+        this.bgpManager = bgpManager;
+    }
+
+    void setListener(FloatingIPListener listener) {
+        this.listener = listener;
+    }
+
+    void setBroker(DataBroker broker) {
+        dataBroker = broker;
+    }
+
+    void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    @Override
+    public void onAddFloatingIp(final BigInteger dpnId, final String routerId,
+                                Uuid networkId, final String interfaceName, final String externalIp, final String internalIp) {
+        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+        if(vpnName == null) {
+            LOG.info("No VPN associated with ext nw {} to handle add floating ip configuration {} in router {}",
+                    networkId, externalIp, routerId);
+            return;
+        }
+
+        GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+        Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
+
+        ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture), new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
+
+            @Override
+            public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
+                if(result.isSuccessful()) {
+                    GenerateVpnLabelOutput output = result.getResult();
+                    long label = output.getLabel();
+                    LOG.debug("Generated label {} for prefix {}", label, externalIp);
+                    listener.updateOperationalDS(routerId, interfaceName, (int)label, internalIp, externalIp);
+
+                    //Inform BGP
+                    String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+                    String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
+                    LOG.debug("Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
+                    NatUtil.addPrefixToBGP(bgpManager, rd, externalIp + "/32", nextHopIp, label, LOG);
+
+                    List<Instruction> instructions = new ArrayList<Instruction>();
+                    List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+                    actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.PDNAT_TABLE) }));
+                    instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0));
+                    makeTunnelTableEntry(dpnId, label, instructions);
+
+                    //Install custom FIB routes
+                    List<Instruction> customInstructions = new ArrayList<>();
+                    customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PDNAT_TABLE }).buildInstruction(0));
+                    makeLFibTableEntry(dpnId, label, NatConstants.PDNAT_TABLE);
+                    CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setInstruction(customInstructions)
+                            .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
+                    //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
+                    Future<RpcResult<Void>> future = fibService.createFibEntry(input);
+                    return JdkFutureAdapters.listenInPoolThread(future);
+                } else {
+                    String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
+                    LOG.error(errMsg);
+                    return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                }
+            }
+        });
+
+        Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("Error in generate label or fib install process", error);
+            }
+
+            @Override
+            public void onSuccess(RpcResult<Void> result) {
+                if(result.isSuccessful()) {
+                    LOG.info("Successfully installed custom FIB routes for prefix {}", externalIp);
+                } else {
+                    LOG.error("Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onRemoveFloatingIp(final BigInteger dpnId, String routerId, Uuid networkId, final String externalIp,
+                                   String internalIp, final long label) {
+        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+        if(vpnName == null) {
+            LOG.info("No VPN associated with ext nw {} to handle remove floating ip configuration {} in router {}",
+                    networkId, externalIp, routerId);
+            return;
+        }
+        //Remove Prefix from BGP
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        removePrefixFromBGP(rd, externalIp + "/32");
+
+        //Remove custom FIB routes
+        //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
+        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
+        Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
+
+        ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
+
+            @Override
+            public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+                //Release label
+                if(result.isSuccessful()) {
+                    removeTunnelTableEntry(dpnId, label);
+                    removeLFibTableEntry(dpnId, label);
+                    RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+                    Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
+                    return JdkFutureAdapters.listenInPoolThread(labelFuture);
+                } else {
+                    String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+                    LOG.error(errMsg);
+                    return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                }
+            }
+        });
+
+        Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("Error in removing the label or custom fib entries", error);
+            }
+
+            @Override
+            public void onSuccess(RpcResult<Void> result) {
+                if(result.isSuccessful()) {
+                    LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
+                } else {
+                    LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+                }
+            }
+        });
+    }
+
+    private void removePrefixFromBGP(String rd, String prefix) {
+        try {
+            bgpManager.deletePrefix(rd, prefix);
+        } catch(Exception e) {
+            LOG.error("Delete prefix failed", e);
+        }
+    }
+
+    void cleanupFibEntries(final BigInteger dpnId, final String vpnName, final String externalIp, final long label ) {
+        //Remove Prefix from BGP
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        removePrefixFromBGP(rd, externalIp + "/32");
+
+        //Remove custom FIB routes
+
+        //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
+        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
+        Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
+
+        ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), 
+            new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
+
+            @Override
+            public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+                //Release label
+                if(result.isSuccessful()) {
+                    removeTunnelTableEntry(dpnId, label);
+                    removeLFibTableEntry(dpnId, label);
+                    RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+                    Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
+                    return JdkFutureAdapters.listenInPoolThread(labelFuture);
+                } else {
+                    String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+                    LOG.error(errMsg);
+                    return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                }
+            }
+        });
+
+        Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("Error in removing the label or custom fib entries", error);
+            }
+
+            @Override
+            public void onSuccess(RpcResult<Void> result) {
+                if(result.isSuccessful()) {
+                    LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
+                } else {
+                    LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+                }
+            }
+        });
+    }
+
+    private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
+        return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+    }
+
+    private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
+        LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+        // Matching metadata
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+                5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+                COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+        mdsalManager.removeFlow(dpnId, flowEntity);
+        LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+    }
+
+    private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+
+        LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
+
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+
+        Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
+                0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
+
+        mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+    }
+
+    private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x8847L }));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+        Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
+        instructions.add(writeInstruction);
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
+
+        // Install the flow entry in L3_LFIB_TABLE
+        String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+                10, flowRef, 0, 0,
+                COOKIE_VM_LFIB_TABLE, matches, instructions);
+
+        mdsalManager.installFlow(dpId, flowEntity);
+
+        LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+    }
+
+    private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                                  new long[] { 0x8847L }));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+        String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+        LOG.debug("removing LFib entry with flow ref {}", flowRef);
+
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+                                               10, flowRef, 0, 0,
+                                               COOKIE_VM_LFIB_TABLE, matches, null);
+
+        mdsalManager.removeFlow(dpnId, flowEntity);
+
+        LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+    }
+
+}
+
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModule.java b/natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModule.java
new file mode 100644 (file)
index 0000000..6d34659
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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
+ */
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111;
+
+import org.opendaylight.vpnservice.natservice.internal.NatServiceProvider;
+
+public class NATServiceModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111.AbstractNATServiceModule {
+    public NATServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NATServiceModule(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.natservice.impl.rev160111.NATServiceModule 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() {
+        NatServiceProvider provider = new NatServiceProvider(getRpcRegistryDependency());
+        provider.setNotificationService(getNotificationServiceDependency());
+        provider.setMdsalManager(getMdsalutilDependency());
+        provider.setBgpManager(getBgpmanagerDependency());
+        getBrokerDependency().registerProvider(provider);
+        return provider;
+    }
+}
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModuleFactory.java b/natservice/natservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/natservice/impl/rev160111/NATServiceModuleFactory.java
new file mode 100644 (file)
index 0000000..d2c9332
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: natmanager-impl yang module local name: natservice-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Jan 20 15:47:25 IST 2016
+*
+* 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.natservice.impl.rev160111;
+public class NATServiceModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111.AbstractNATServiceModuleFactory {
+
+}
diff --git a/natservice/natservice-impl/src/main/yang/natservice-impl.yang b/natservice/natservice-impl/src/main/yang/natservice-impl.yang
new file mode 100644 (file)
index 0000000..4c71f98
--- /dev/null
@@ -0,0 +1,70 @@
+module natservice-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:natservice:impl";
+    prefix "natservice-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-sal-binding-broker-impl { prefix md-sal-binding-impl; revision-date 2013-10-28; }
+    import odl-mdsalutil { prefix odl-mdsal; revision-date 2015-04-10;}
+    import bgpmanager-api { prefix bgpmgr-api; revision-date 2015-04-20;}
+
+    description
+        "Service definition for NAT Service module";
+
+    revision "2016-01-11" {
+        description
+            "Initial revision";
+    }
+
+    identity natservice-impl {
+        base config:module-type;
+        config:java-name-prefix NATService;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case natservice-impl {
+            when "/config:modules/config:module/config:type = 'natservice-impl'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+            container rpc-registry {
+                 uses config:service-ref {
+                      refine type {
+                         mandatory true;
+                         config:required-identity md-sal-binding:binding-rpc-registry;
+                      }
+                 }
+            }
+            container bgpmanager {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity bgpmgr-api:bgpmanager-api;
+                    }
+                }
+            }
+            container notification-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding-impl:binding-new-notification-service;
+                    }
+                }
+            }
+            container mdsalutil {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity odl-mdsal:odl-mdsalutil;
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/ExternalNetworksChangeListenerTest.java b/natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/ExternalNetworksChangeListenerTest.java
new file mode 100644 (file)
index 0000000..a284db1
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.natservice.internal.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
+
+import java.math.BigInteger;
+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.MockitoAnnotations;
+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.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.natservice.internal.ExternalNetworksChangeListener;
+import org.opendaylight.vpnservice.natservice.internal.NatUtil;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(MDSALUtil.class)
+public class ExternalNetworksChangeListenerTest {
+
+    @Mock DataBroker dataBroker;
+    @Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
+    @Mock IMdsalApiManager mdsalManager;
+    @Mock FlowEntity flowMock;
+    @Mock GroupEntity groupMock;
+    InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks> id = null;
+    org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks networks = null;
+    private ExternalNetworksChangeListener extNetworks;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(dataBroker.registerDataChangeListener(
+                any(LogicalDatastoreType.class),
+                any(InstanceIdentifier.class),
+                any(DataChangeListener.class),
+                any(DataChangeScope.class)))
+                .thenReturn(dataChangeListenerRegistration);
+        extNetworks = new ExternalNetworksChangeListener(dataBroker);
+
+        PowerMockito.mockStatic(MDSALUtil.class);
+    }
+
+
+    @Test
+    public void testSnatFlowEntity() {
+        FlowEntity flowMock = mock(FlowEntity.class);
+        final short SNAT_TABLE = 40;
+        final int DEFAULT_SNAT_FLOW_PRIORITY = 0;
+        final String FLOWID_SEPARATOR = ".";
+        String SNAT_FLOWID_PREFIX = "SNAT.";
+
+
+        BigInteger dpnId = new BigInteger("100");
+        String routerName = new String("200");
+        long routerId = 200;
+        long groupId = 300;
+        List<BucketInfo> bucketInfo = new ArrayList<BucketInfo>();
+        List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
+        listActionInfoPrimary.add(new ActionInfo(ActionType.output,
+                new String[] {"3"}));
+        BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+        List<ActionInfo> listActionInfoSecondary = new ArrayList<ActionInfo>();
+        listActionInfoSecondary.add(new ActionInfo(ActionType.output,
+                new String[] {"4"}));
+        BucketInfo bucketSecondary = new BucketInfo(listActionInfoPrimary);
+        bucketInfo.add(0, bucketPrimary);
+        bucketInfo.add(1, bucketSecondary);
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { 0x0800L }));
+
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+
+
+        String flowRef =  new StringBuffer().append(SNAT_FLOWID_PREFIX).append(dpnId).append(FLOWID_SEPARATOR).
+                append(SNAT_TABLE).append(FLOWID_SEPARATOR).append(routerId).toString();
+
+        BigInteger cookieSnat = NatUtil.getCookieSnatFlow(routerId);
+        try {
+            PowerMockito.when(MDSALUtil.class, "buildFlowEntity", dpnId, SNAT_TABLE, flowRef,
+                    DEFAULT_SNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                    cookieSnat, matches, instructions ).thenReturn(flowMock);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        /* TODO : Fix this to mock it properly when it reads DS
+        extNetworks.buildSnatFlowEntity(dpnId, routerName, groupId);
+        PowerMockito.verifyStatic(); */
+
+    }
+
+}
diff --git a/natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/NaptManagerTest.java b/natservice/natservice-impl/src/test/java/org/opendaylight/vpnservice/natservice/internal/test/NaptManagerTest.java
new file mode 100644 (file)
index 0000000..89026e1
--- /dev/null
@@ -0,0 +1,195 @@
+package org.opendaylight.vpnservice.natservice.internal.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.OngoingStubbing;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.eq;
+
+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.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.natservice.internal.IPAddress;
+import org.opendaylight.vpnservice.natservice.internal.NaptManager;
+import org.opendaylight.vpnservice.natservice.internal.SessionAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+import com.google.common.util.concurrent.Futures;
+
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(MDSALUtil.class)
+public class NaptManagerTest {
+
+    @Mock IdManagerService idMgr;
+    @Mock DataBroker dataBroker;
+    @Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
+    InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap> ipmapId = null;
+    org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap ipmap = null;
+
+    private NaptManager naptManager;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        when(dataBroker.registerDataChangeListener(
+                any(LogicalDatastoreType.class),
+                any(InstanceIdentifier.class),
+                any(DataChangeListener.class),
+                any(DataChangeScope.class)))
+                .thenReturn(dataChangeListenerRegistration);
+        naptManager = new NaptManager(dataBroker);
+        when(idMgr.createIdPool(any(CreateIdPoolInput.class)))
+                  .thenReturn(Futures.immediateFuture(RpcResultBuilder.<Void>success().build()));
+        naptManager.setIdManager(idMgr);
+
+        PowerMockito.mockStatic(MDSALUtil.class);
+
+    }
+
+
+    @Ignore @Test
+    public void testRegisterMappingIpIP() {
+        // TODO : This needs to be modified to make it work
+        // TODO : Issue with Mockito.any() usage, so for now run registerMapping testcases as seperate Tests. This needs to be fixed properly.
+        ipmapId = InstanceIdentifier.builder(
+                IntextIpMap.class).child(IpMapping.class, new IpMappingKey(5L)).child(IpMap.class, new IpMapKey("10.0.0.1")).build();
+        ipmap = new IpMapBuilder().setKey(new IpMapKey("10.0.0.1")).setInternalIp("10.0.0.1").setExternalIp("192.17.13.1").build();
+        try {
+            PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        IPAddress internal = new IPAddress("10.0.0.1",0);
+        IPAddress external = new IPAddress("192.17.13.1", 0);
+        naptManager.registerMapping(5, internal, external);
+        PowerMockito.verifyStatic();
+
+    }
+
+    @Ignore @Test
+    public void testRegisterMappingIpSubnet() {
+        // TODO : This needs to be modified to make it work
+        ipmapId = InstanceIdentifier.builder(
+                IntextIpMap.class).child(IpMapping.class, new IpMappingKey(5L)).child(IpMap.class, new IpMapKey("10.0.0.1")).build();
+        ipmap = new IpMapBuilder().setKey(new IpMapKey("10.0.0.1")).setInternalIp("10.0.0.1").setExternalIp("192.17.13.1/24").build();
+        try {
+            PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        IPAddress internal = new IPAddress("10.0.0.1",0);
+        IPAddress external = new IPAddress("192.17.13.1", 24);
+        naptManager.registerMapping(5, internal, external);
+        PowerMockito.verifyStatic();
+    }
+
+    @Ignore @Test
+    public void testRegisterMappingSubnetIp() {
+        // TODO : This needs to be modified to make it work
+        ipmapId = InstanceIdentifier.builder(
+                IntextIpMap.class).child(IpMapping.class, new IpMappingKey(6L)).child(IpMap.class, new IpMapKey("10.0.2.1/16")).build();
+        ipmap = new IpMapBuilder().setKey(new IpMapKey("10.0.0.1")).setInternalIp("10.0.0.1").setExternalIp("192.19.15.3").build();
+        try {
+            PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        IPAddress internal = new IPAddress("10.0.2.1",16);
+        IPAddress external = new IPAddress("192.19.15.3", 0);
+        naptManager.registerMapping(6, internal, external);
+        PowerMockito.verifyStatic();
+     }
+
+    @Ignore @Test
+    public void testRegisterMappingSubnetSubnet() {
+        // TODO : This needs to be modified to make it work
+        ipmapId = InstanceIdentifier.builder(
+                IntextIpMap.class).child(IpMapping.class, new IpMappingKey(6L)).child(IpMap.class, new IpMapKey("10.2.0.1/24")).build();
+        ipmap = new IpMapBuilder().setKey(new IpMapKey("10.2.0.1/24")).setInternalIp("10.2.0.1/24").setExternalIp("192.21.16.1/16").build();
+        try {
+            PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        IPAddress internal = new IPAddress("10.2.0.1",24);
+        IPAddress external = new IPAddress("192.21.16.1", 16);
+        naptManager.registerMapping(6, internal, external);
+        PowerMockito.verifyStatic();
+    }
+
+
+    @Test
+    public void testgetExternalAddressMapping() {
+        // TODO : This needs to be modified to make it work
+        // Testcase to test when no entry exists in ip-pot-map
+        /*SessionAddress internalIpPort = new SessionAddress("10.0.0.1", 2);
+        InstanceIdentifierBuilder<IpPortMapping> idBuilder =
+                InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(5L));
+        InstanceIdentifier<IpPortMapping> id = idBuilder.build();
+        try {
+             PowerMockito.when(MDSALUtil.class, "read", dataBroker, LogicalDatastoreType.CONFIGURATION, id).thenReturn(null);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        naptManager.getExternalAddressMapping(5, internalIpPort);
+        PowerMockito.verifyStatic(); */  
+    }
+
+    @Test
+    public void testReleaseAddressMapping() {
+        // TODO : Below needs to be modified to make it work
+      /*  InstanceIdentifierBuilder<IpMapping> idBuilder =
+                InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(5L));
+        InstanceIdentifier<IpMapping> id = idBuilder.build();
+        try {
+            PowerMockito.doNothing().when(MDSALUtil.class, "read", dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        } catch (Exception e) {
+            // Test failed anyways
+            assertEquals("true", "false");
+        }
+        IPAddress internal = new IPAddress("10.0.0.1",0);
+        IPAddress external = new IPAddress("192.17.13.1", 0);
+        naptManager.registerMapping(5, internal, external);
+        SessionAddress internalSession = new SessionAddress("10.0.0.1", 0);
+        naptManager.releaseAddressMapping(5L, internalSession);*/
+    }
+
+
+}
diff --git a/natservice/pom.xml b/natservice/pom.xml
new file mode 100644 (file)
index 0000000..adba57f
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 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>odlparent</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>natservice-aggregator</artifactId>
+  <version>0.3.0-SNAPSHOT</version>
+  <name>natservice</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>natservice-api</module>
+    <module>natservice-impl</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>
index d941dec97f63e27ac3c7c799a87635dca82d6fe0..dd16a42f41cc2eb774c2077faf66b35249f25457 100644 (file)
@@ -38,4 +38,9 @@ public class L2GatewayCacheUtils {
                 .getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
         return cachedMap.get(devicename);
     }
+
+    public static ConcurrentMap<String, L2GatewayDevice> getCache() {
+        return (ConcurrentMap<String, L2GatewayDevice>) CacheUtil
+                .getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
+    }
 }
diff --git a/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java b/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/vpnservice/neutronvpn/api/utils/NeutronUtils.java
new file mode 100644 (file)
index 0000000..5b70621
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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
+ */
+
+package org.opendaylight.vpnservice.neutronvpn.api.utils;
+
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+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.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+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;
+
+public class NeutronUtils {
+    public static final String VNIC_TYPE_NORMAL = "normal";
+
+    public static boolean isPortVnicTypeNormal(Port port) {
+        PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
+        if(portBinding == null || portBinding.getVnicType() == null) {
+            // By default, VNIC_TYPE is NORMAL
+            return true;
+        }
+        String vnicType = portBinding.getVnicType().trim().toLowerCase();
+        return vnicType.equals(VNIC_TYPE_NORMAL);
+    }
+
+    public static String getSegmentationIdFromNeutronNetwork(Network network) {
+        String segmentationId = null;
+        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        if (providerExtension != null) {
+            segmentationId = providerExtension.getSegmentationId();
+            if (segmentationId == null) {
+                List<Segments> providerSegments = providerExtension.getSegments();
+                if (providerSegments != null && providerSegments.size() > 0) {
+                    for (Segments providerSegment: providerSegments) {
+                        if (isNetworkSegmentTypeVxlan(providerSegment)) {
+                            segmentationId = providerSegment.getSegmentationId();
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return segmentationId;
+    }
+
+    static boolean isNetworkSegmentTypeVxlan(Segments providerSegment) {
+        Class<? extends NetworkTypeBase> networkType = providerSegment.getNetworkType();
+        return (networkType != null && networkType.isAssignableFrom(NetworkTypeVxlan.class));
+    }
+}
index 92c084a75deb98b6df51c1247fb4095b975db702..aead8a4bc00ba643efad225071dccfb5744e1d22 100644 (file)
@@ -151,6 +151,19 @@ module neutronvpn {
         }
     }
 
+
+    container router-interfaces-map {
+        list router-interfaces {
+            key router-id;
+            leaf router-id { type yang:uuid; }
+            list interfaces {
+                key interface-id;
+                leaf interface-id { type string; }
+            }
+        }
+    }
+
+
     /* container for DHCP Configuration */
     container dhcp-config {
         list configs {
@@ -390,4 +403,24 @@ module neutronvpn {
             }
     }
 
-}
\ No newline at end of file
+    notification router-associated-to-vpn {
+                description "router association to vpn";
+                leaf router-id{
+                    type yang:uuid;
+                }
+                leaf vpn-id{
+                    type yang:uuid;
+                }
+        }
+
+        notification router-disassociated-from-vpn {
+                description "router disassociation from vpn";
+                leaf router-id{
+                    type yang:uuid;
+                }
+                leaf vpn-id{
+                    type yang:uuid;
+                }
+        }
+
+}
index e8c777e8d28f71bff10a87397352a61bb7d483c7..2bda4dee5c27064a9395df811b18f5ebd96407e0 100644 (file)
@@ -39,14 +39,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         </type>
                         <name>mdsalutil-service</name>
                     </mdsalutil>
-                    <entity-ownership-service>
-                        <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
-                        <name>entity-ownership-service</name>
-                    </entity-ownership-service>
-                    <binding-normalized-node-serializer>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
-                        <name>runtime-mapping-singleton</name>
-                    </binding-normalized-node-serializer>
                     <notification-publish-service>
                         <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-publish-service</type>
                         <name>binding-notification-publish-adapter</name>
@@ -55,6 +47,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
                         <name>binding-notification-adapter</name>
                     </notification-service>
+                    <entity-ownership-service>
+                        <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
+                        <name>entity-ownership-service</name>
+                    </entity-ownership-service>
                 </module>
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
index d432f45cfbc7a9eee99d1bf6e5335cd02d3bc910..7488a361d9e37da003a4e5c2e852004c3062d7d5 100644 (file)
@@ -15,13 +15,14 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+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.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceKey;
-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.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -98,7 +99,7 @@ public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Net
 
     private void createElanInstance(Network input) {
         String elanInstanceName = input.getUuid().getValue();
-        String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(input);
+        String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(input);
         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName);
         if (segmentationId != null) {
             elanInstanceBuilder.setVni(Long.valueOf(segmentationId));
index 826955dff5a553b5a27daeadb7030ea2c64aa9c7..2feca2cd75ff4d4d97454d3f198c835bb36ff283 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
@@ -140,7 +141,7 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
     }
 
     private void handleNeutronPortCreated(Port port) {
-        if (!NeutronvpnUtils.isPortVnicTypeNormal(port)) {
+        if (!NeutronUtils.isPortVnicTypeNormal(port)) {
             LOG.info("Port {} is not a NORMAL VNIC Type port; OF Port interfaces are not created",
                     port.getUuid().getValue());
             return;
@@ -158,6 +159,10 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
             // create vpn-interface on this neutron port
             LOG.debug("Adding VPN Interface");
             nvpnManager.createVpnInterface(vpnId, port);
+            Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+            if(routerId != null) {
+                nvpnManager.addToNeutronRouterInterfacesMap(routerId, port.getUuid().getValue());
+            }
         }
     }
 
@@ -176,6 +181,11 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
         // ELAN interface is also implicitly deleted as part of this operation
         deleteOfPortInterface(port);
 
+        Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+        if(routerId != null) {
+            nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, port.getUuid().getValue());
+        }
+
     }
 
     private void handleNeutronPortUpdated(Port portoriginal, Port portupdate) {
@@ -185,6 +195,10 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
 
         if (vpnIdup != null) {
             nvpnManager.createVpnInterface(vpnIdup, portupdate);
+            Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnIdup).getRouterId();
+            if(routerId != null) {
+                nvpnManager.addToNeutronRouterInterfacesMap(routerId, portupdate.getUuid().getValue());
+            }
         }
 
         // remove port FixedIP from local Subnets DS
@@ -192,6 +206,10 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
 
         if (vpnIdor != null) {
             nvpnManager.deleteVpnInterface(portoriginal);
+            Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnIdor).getRouterId();
+            if(routerId != null) {
+                nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portoriginal.getUuid().getValue());
+            }
         }
     }
 
index 201a2f4d35e6cf95f8463e475afbf70ddb683e92..bd66c26f7735d13a06fad04ed3342db44f22f346 100644 (file)
@@ -37,6 +37,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacenciesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterInterfacesMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesKey;
+
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
 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.Router;
@@ -814,8 +822,12 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable , Eve
         InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
         Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
         long elanTag = elanInstance.get().getElanTag();
-        if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
-        else {isExternalVpn = true;}
+        Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+        if (vpnId.equals(routerId)) {
+            isExternalVpn = false;
+        } else {
+            isExternalVpn = true;
+        }
         try {
             isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
             checkAndPublishSubnetAddNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
@@ -867,6 +879,53 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable , Eve
         }
     }
 
+
+
+        // router-interfaces-map
+//    list router-interfaces {
+//        key router-id;
+//        leaf router-id { type yang:uuid; }
+//        list interfaces {
+//            key interface-id;
+//            leaf interface-id { type yang:uuid; }
+//        }
+//    }
+////}
+    InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
+        return InstanceIdentifier.builder(RouterInterfacesMap.class)
+                .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
+    }
+    void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
+        InstanceIdentifier<RouterInterfaces> routerInterfacesId =  getRouterInterfacesId(routerId);
+        Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
+        Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName)).setInterfaceId(interfaceName).build();
+        if(optRouterInterfaces.isPresent()) {
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)), routerInterface);
+        } else {
+            RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
+            List<Interfaces> interfaces = new ArrayList<>();
+            interfaces.add(routerInterface);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId, builder.setInterfaces(interfaces).build());
+        }
+    }
+    
+    void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
+        InstanceIdentifier<RouterInterfaces> routerInterfacesId =  getRouterInterfacesId(routerId);
+        Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
+        Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName)).setInterfaceId(interfaceName).build();
+        if(optRouterInterfaces.isPresent()) {
+            RouterInterfaces routerInterfaces = optRouterInterfaces.get();
+            List<Interfaces> interfaces = routerInterfaces.getInterfaces();
+            if(interfaces != null && interfaces.remove(routerInterface)) {
+                if(interfaces.isEmpty()) {
+                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
+                } else {
+                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
+                }
+            }
+        }
+    }
+
     protected List<Adjacency> addAdjacencyforExtraRoute(List<Routes> routeList, boolean rtrUp, String vpnifname) {
         List<Adjacency> adjList = new ArrayList<Adjacency>();
         for (Routes route : routeList) {
@@ -974,8 +1033,12 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable , Eve
         InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
         Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
         long elanTag = elanInstance.get().getElanTag();
-        if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
-        else {isExternalVpn = true;}
+        Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+        if (vpnId.equals(routerId)) {
+            isExternalVpn = false;
+        } else {
+            isExternalVpn = true;
+        }
         try {
             isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
             checkAndPublishSubnetDelNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
@@ -994,6 +1057,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable , Eve
                 for (Uuid port : sn.getPortList()) {
                     logger.debug("removing vpn-interface for port {}", port.getValue());
                     deleteVpnInterface(NeutronvpnUtils.getNeutronPort(broker, port));
+                    if (routerId != null) {
+                        removeFromNeutronRouterInterfacesMap(routerId, port.getValue());
+                    }
                 }
             }
             // update subnet-vpn association
index a374e1de30cb5b43f840f359ca7baf39c72924c9..f9a4dcd2909b87995581c1e307d56b98f1e180fd 100644 (file)
@@ -10,12 +10,11 @@ package org.opendaylight.vpnservice.neutronvpn;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.vpnservice.neutronvpn.l2gw.L2GatewayProvider;
@@ -44,10 +43,9 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
     private NeutronPortChangeListener portListener;
     private RpcProviderRegistry rpcProviderRegistry;
     private L2GatewayProvider l2GatewayProvider;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private NotificationPublishService notificationPublishService;
     private NotificationService notificationService;
+    private EntityOwnershipService entityOwnershipService;
 
     public NeutronvpnProvider(RpcProviderRegistry rpcRegistry,NotificationPublishService notificationPublishService,
                               NotificationService notificationService) {
@@ -76,10 +74,6 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
         this.entityOwnershipService = entityOwnershipService;
     }
 
-    public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
-    }
-
     @Override
     public void onSessionInitiated(ProviderContext session) {
         try {
@@ -94,8 +88,7 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
             portListener = new NeutronPortChangeListener(dbx, nvManager,notificationPublishService,notificationService);
             portListener.setLockManager(lockManager);
             nvManager.setLockManager(lockManager);
-            l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService,
-                    bindingNormalizedNodeSerializer);
+            l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService);
 
             LOG.info("NeutronvpnProvider Session Initiated");
         } catch (Exception e) {
index 3acc5ce43b90c8ca480945b7110a2f34266a497d..d161f97dfdde3441ca4dd97e18128a7c795ee77c 100644 (file)
@@ -188,26 +188,6 @@ public class NeutronvpnUtils {
         return null;
     }
 
-    protected static String getSegmentationIdFromNeutronNetwork(Network network) {
-        String segmentationId = null;
-        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
-        if (providerExtension != null) {
-            segmentationId = providerExtension.getSegmentationId();
-            if (segmentationId == null) {
-                List<Segments> providerSegments = providerExtension.getSegments();
-                if (providerSegments != null && providerSegments.size() > 0) {
-                    for (Segments providerSegment: providerSegments) {
-                        if (isNetworkSegmentTypeVxlan(providerSegment)) {
-                            segmentationId = providerSegment.getSegmentationId();
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        return segmentationId;
-    }
-
     protected static List<Uuid> getNeutronRouterSubnetIds(DataBroker broker, Uuid routerId) {
         logger.info("getNeutronRouterSubnetIds for {}", routerId.getValue());
 
@@ -243,16 +223,6 @@ public class NeutronvpnUtils {
         return new StringBuilder().append("tap").append(tapId).toString();
     }
 
-    protected static boolean isPortVnicTypeNormal(Port port) {
-        PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
-        if(portBinding == null || portBinding.getVnicType() == null) {
-            // By default, VNIC_TYPE is NORMAL
-            return true;
-        }
-        String vnicType = portBinding.getVnicType().trim().toLowerCase();
-        return vnicType.equals(VNIC_TYPE_NORMAL);
-    }
-
     protected static boolean lock(LockManagerService lockManager, String lockName) {
         TryLockInput input = new TryLockInputBuilder().setLockName(lockName).setTime(5L).setTimeUnit
                 (TimeUnits.Milliseconds).build();
@@ -365,9 +335,4 @@ public class NeutronvpnUtils {
 
         return result;
     }
-
-    static boolean isNetworkSegmentTypeVxlan(Segments providerSegment) {
-        Class<? extends NetworkTypeBase> networkType = providerSegment.getNetworkType();
-        return (networkType != null && networkType.isAssignableFrom(NetworkTypeVxlan.class));
-    }
 }
index f62d3f43014eb155ac1b8e657ad69dc9dc0644be..9ab162505506e0fb1dc09d194e19cf710c67ef4f 100644 (file)
@@ -13,7 +13,6 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -54,15 +53,12 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase<L2ga
     private final DataBroker broker;
     private ItmRpcService itmRpcService;
     private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
 
     public L2GatewayListener(final DataBroker db, RpcProviderRegistry rpcRegistry,
-            EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+            EntityOwnershipService entityOwnershipService) {
         super(L2gateway.class, L2GatewayListener.class);
         broker = db;
         this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         itmRpcService = rpcRegistry.getRpcService(ItmRpcService.class);
         registerListener(db);
     }
@@ -135,8 +131,8 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase<L2ga
                 final String hwvtepId = l2GwDevice.getHwvtepNodeId();
                 InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
                 ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+                        entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                        HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
                 final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
                 Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
                     @Override
@@ -184,8 +180,8 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase<L2ga
                     final String hwvtepId = l2GwDevice.getHwvtepNodeId();
                     InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
                     ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                            entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                            bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+                            entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                            HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
                     final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
                     Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
                         @Override
index 2da2a4599fa52da40f0cb660d3fd43c03dd928bd..e0d5445bcea50a1fc9a28f4045453d109cbae1d7 100644 (file)
@@ -12,7 +12,6 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -22,11 +21,9 @@ public class L2GatewayProvider {
     private L2GatewayListener l2GatewayListener;
 
     public L2GatewayProvider(DataBroker broker, RpcProviderRegistry rpcRegistry,
-            EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+            EntityOwnershipService entityOwnershipService) {
         L2GatewayCacheUtils.createL2DeviceCache();
-        l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService,
-                bindingNormalizedNodeSerializer);
+        l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService);
         LOG.info("L2GatewayProvider Initialized");
     }
 
index 90198d70a213a238f85e0e3ac0081a0fc2c8e876..35087e850649d9ac35bd11468d654ced943d7e88 100644 (file)
@@ -39,7 +39,6 @@ public class NeutronvpnImplModule extends org.opendaylight.yang.gen.v1.urn.opend
         provider.setMdsalManager(getMdsalutilDependency());
         provider.setLockManager(lockManagerService);
         provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
-        provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
         getBrokerDependency().registerProvider(provider);
         return provider;
     }
index 33a3b0368c9c02e8f4f2fcf1919e4b6423cb5c3b..b1ef1420cf9e48a57a33ce0a06c696b81bd35609 100644 (file)
@@ -51,24 +51,6 @@ module neutronvpn-impl {
                     }
                 }
             }
-            container entity-ownership-service {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity eos:entity-ownership-service;
-                    }
-                }
-            }
-
-            container binding-normalized-node-serializer {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity md-sal-binding:binding-normalized-node-serializer;
-                    }
-                }
-            }
-
             container notification-publish-service {
                 uses config:service-ref {
                     refine type {
@@ -83,6 +65,15 @@ module neutronvpn-impl {
                          mandatory true;
                          config:required-identity md-sal-binding-impl:binding-new-notification-service;
                          }
+                    }
+            }
+
+            container entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
                 }
             }
         }
diff --git a/pom.xml b/pom.xml
index e29557e99b9cce51a66757b8a4c7e0bf4d871739..b35783b224d78fa40f5205f4f9b31ee39df8b386 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -31,10 +31,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <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>
   </modules>
 
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
index 6857e98ec55b1a2c73624d70f5523b4e06cfda7c..5f0c708f5bf1fc2935cb9e4b24510b11402370ae 100644 (file)
@@ -122,6 +122,12 @@ module odl-l3vpn {
                       type string;
                   }
                }
+               list ip-addresses {
+                  key ip-address;
+                  leaf ip-address {
+                      type string;
+                  }
+               }
            }
         }
     }
@@ -234,4 +240,48 @@ module odl-l3vpn {
         }
     }
 
-}
\ No newline at end of file
+    grouping dpn-in-vpn-event {
+            leaf dpn-id { type uint64; }
+            leaf vpn-name { type string; }
+            leaf rd { type string; }
+        }
+
+        notification add-dpn-event {
+            container add-event-data {
+               uses dpn-in-vpn-event;
+            }
+        }
+
+        notification remove-dpn-event {
+            container remove-event-data {
+               uses dpn-in-vpn-event;
+            }
+        }
+
+
+      /* container to maintain mapping between neutron router and DPN(s) on which vpn-interfaces for router are present */
+    container neutron-router-dpns {
+        list router-dpn-list {
+            key router-id;
+            leaf router-id { type string;}
+            list dpn-vpninterfaces-list {
+                key dpn-id;
+                leaf dpn-id { type uint64;}
+                list router-interfaces { 
+                    key interface;
+                    leaf interface { type string; }
+                }
+            }
+        }
+    }
+
+
+    container router-interfaces {
+        list router-interface {
+            key interface-name;
+            leaf interface-name { type string; }
+            leaf router-name { type string; }
+        }
+    }
+
+}
diff --git a/vpnmanager/vpnmanager-api/src/main/yang/vpn-rpc.yang b/vpnmanager/vpnmanager-api/src/main/yang/vpn-rpc.yang
new file mode 100644 (file)
index 0000000..ec78fc1
--- /dev/null
@@ -0,0 +1,39 @@
+module vpn-rpc {\r
+    namespace "urn:opendaylight:vpnservice:vpn:rpc";\r
+    prefix "vpn-rpc";\r
+\r
+    revision "2016-02-01" {\r
+        description "VPN Service RPC Module";\r
+    }\r
+\r
+    /* RPCs */\r
+\r
+    rpc generate-vpn-label {\r
+        description "to generate label for the given ip prefix from the associated VPN";\r
+        input {\r
+            leaf vpn-name {\r
+                type string;\r
+            }\r
+            leaf ip-prefix {\r
+                type string;\r
+            }\r
+        }\r
+        output {\r
+            leaf label {\r
+                type uint32;\r
+            }\r
+        }\r
+    }\r
+\r
+    rpc remove-vpn-label {\r
+        description "to remove label for the given ip prefix from the associated VPN";\r
+        input {\r
+            leaf vpn-name {\r
+                type string;\r
+            }\r
+            leaf ip-prefix {\r
+                type string;\r
+            }\r
+        }\r
+    }\r
+}
\ No newline at end of file
index 5e6cc303cd61fefa48cfdd898175cedc1def958c..45278bb659479e076063edff200ecc22467fd44f 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.vpnservice;
 
+import com.google.common.base.Optional;
 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;
@@ -16,6 +17,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.re
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -86,6 +88,7 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
         } else {
           vpnInterfaceManager.processVpnInterfaceUp(dpnId, interfaceName, intrf.getIfIndex());
           vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(intrf);
+          handleRouterInterfacesUpEvent(interfaceName);
         }
       } catch (Exception e) {
         LOG.error("Exception caught in Interface Operational State Up event", e);
@@ -112,6 +115,7 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
           if (VpnUtil.isVpnInterfaceConfigured(broker, interfaceName)) {
             vpnInterfaceManager.processVpnInterfaceDown(dpId, interfaceName, intrf.getIfIndex(), true);
             vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(intrf);
+            handleRouterInterfacesDownEvent(interfaceName,dpId);
           }
         }
       } catch (Exception e) {
@@ -133,14 +137,38 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
         if(update.getOperStatus().equals(Interface.OperStatus.Up)) {
           //advertise all prefixes in all vpns for this dpn to bgp
           // vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.ADVERTISE_ROUTE);
-                    vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(update);
+          vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(update);
         } else if(update.getOperStatus().equals(Interface.OperStatus.Down)) {
           //withdraw all prefixes in all vpns for this dpn from bgp
           // vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.WITHDRAW_ROUTE);
-                   vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(update);
+          vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(update);
         }*/
       }
 
     }
 
+    void handleRouterInterfacesUpEvent(String interfaceName) {
+        Optional<RouterInterface> optRouterInterface = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, VpnUtil.getRouterInterfaceId(interfaceName));
+        if(optRouterInterface.isPresent()) {
+            RouterInterface routerInterface = optRouterInterface.get();
+            String routerName = routerInterface.getRouterName();
+            LOG.debug("Handling UP event for router interface {} in Router {}", interfaceName, routerName);
+            vpnInterfaceManager.addToNeutronRouterDpnsMap(routerName, interfaceName);
+        } else {
+            LOG.debug("No Router interface configured to handle UP event for {}", interfaceName);
+        }
+    }
+
+    void handleRouterInterfacesDownEvent(String interfaceName,BigInteger dpnId) {
+        Optional<RouterInterface> optRouterInterface = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, VpnUtil.getRouterInterfaceId(interfaceName));
+        if(optRouterInterface.isPresent()) {
+            RouterInterface routerInterface = optRouterInterface.get();
+            String routerName = routerInterface.getRouterName();
+            LOG.debug("Handling DOWN event for router interface {} in Router {}", interfaceName, routerName);
+            vpnInterfaceManager.removeFromNeutronRouterDpnsMap(routerName, interfaceName,dpnId);
+        } else {
+            LOG.debug("No Router interface configured to handle  DOWN event for {}", interfaceName);
+        }
+    }
+
 }
diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/RouterInterfaceListener.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/RouterInterfaceListener.java
new file mode 100644 (file)
index 0000000..d799303
--- /dev/null
@@ -0,0 +1,85 @@
+/*\r
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
+package org.opendaylight.vpnservice;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;\r
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;\r
+import org.opendaylight.vpnservice.utilities.InterfaceUtils;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterInterfacesMap;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;\r
+import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class RouterInterfaceListener extends AbstractDataChangeListener<Interfaces> {\r
+    private static final Logger LOG = LoggerFactory.getLogger(RouterInterfaceListener.class);\r
+    private ListenerRegistration<DataChangeListener> listenerRegistration;\r
+    private DataBroker broker;\r
+    private VpnInterfaceManager vpnInterfaceManager;\r
+\r
+    public RouterInterfaceListener(final DataBroker db) {\r
+        super(Interfaces.class);\r
+        broker = db;\r
+        registerListener(db);\r
+    }\r
+\r
+    void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {\r
+        this.vpnInterfaceManager = vpnInterfaceManager;\r
+    }\r
+\r
+    private void registerListener(final DataBroker db) {\r
+        try {\r
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
+                    getWildCardPath(), RouterInterfaceListener.this, DataChangeScope.SUBTREE);\r
+        } catch (final Exception e) {\r
+            LOG.error("Router interface DataChange listener registration fail !", e);\r
+        }\r
+    }\r
+\r
+    private InstanceIdentifier<?> getWildCardPath() {\r
+        return InstanceIdentifier.create(RouterInterfacesMap.class).child(RouterInterfaces.class).child(Interfaces.class);\r
+    }\r
+\r
+    @Override\r
+    protected void add(InstanceIdentifier<Interfaces> identifier, Interfaces interfaceInfo) {\r
+        LOG.trace("Add event - key: {}, value: {}", identifier, interfaceInfo);\r
+        final String routerId = identifier.firstKeyOf(RouterInterfaces.class).getRouterId().getValue();\r
+        String interfaceName = interfaceInfo.getInterfaceId();\r
+\r
+        MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, \r
+                VpnUtil.getRouterInterfaceId(interfaceName), VpnUtil.getRouterInterface(interfaceName, routerId));\r
+\r
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =\r
+                InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);\r
+        if (interfaceState != null) {\r
+            LOG.debug("Handling interface {} in router {} add scenario", interfaceName, routerId);\r
+            vpnInterfaceManager.addToNeutronRouterDpnsMap(routerId, interfaceName);\r
+        } else {\r
+            LOG.warn("Interface {} not yet operational to handle router interface add event in router {}", interfaceName, routerId);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected void remove(InstanceIdentifier<Interfaces> identifier, Interfaces interfaceInfo) {\r
+        LOG.trace("Remove event - key: {}, value: {}", identifier, interfaceInfo);\r
+        final String routerId = identifier.firstKeyOf(RouterInterfaces.class).getRouterId().getValue();\r
+        String interfaceName = interfaceInfo.getInterfaceId();\r
+        vpnInterfaceManager.removeFromNeutronRouterDpnsMap(routerId, interfaceName);\r
+    }\r
+\r
+    @Override\r
+    protected void update(InstanceIdentifier<Interfaces> identifier, Interfaces original, Interfaces update) {\r
+        LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);\r
+    }\r
+\r
+}\r
index de7a5cc412b903d8bd8118d99a41e66d8bf63da6..af81bb9e8919041e633bc71f8fc12099d3c94080 100644 (file)
@@ -52,6 +52,7 @@ import java.nio.charset.StandardCharsets;
 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
 import org.opendaylight.vpnservice.mdsalutil.ActionType;
 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 
 public class SubnetRoutePacketInHandler implements PacketProcessingListener {
 
@@ -70,17 +71,22 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
 
     public void onPacketReceived(PacketReceived notification) {
 
-        s_logger.debug("SubnetRoutePacketInHandler: PacketReceived invoked...");
+        s_logger.trace("SubnetRoutePacketInHandler: PacketReceived invoked...");
 
         short tableId = notification.getTableId().getValue();
         byte[] data = notification.getPayload();
         BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
         Ethernet res = new Ethernet();
 
-        if (notification.getPacketInReason() == SendToController.class) { /*&& tableId == VpnConstants.FIB_TABLE) {*/
+        if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
+            s_logger.trace("SubnetRoutePacketInHandler: Some packet received as {}", notification);
             try {
-                s_logger.debug("SubnetRoutePacketInHandler: Some packet received");
                 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+            } catch (Exception e) {
+                s_logger.warn("SubnetRoutePacketInHandler: Failed to decode Packet ", e);
+                return;
+            }
+            try {
                 Packet pkt = res.getPayload();
                 if (pkt instanceof IPv4) {
                     IPv4 ipv4 = (IPv4) pkt;
@@ -96,25 +102,40 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                         return;
                     }
                     long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
-                    s_logger.debug("SubnetRoutePacketInHandler: Elan Tag obtained as {}" , elanTag);
                     if (elanTag == 0) {
                         s_logger.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
                                 "Packet received with Target IP {}", dstIpStr);
                         return;
                     }
                     s_logger.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
-                            + "and Target IP {}", srcIpStr, dstIpStr);
-                    BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag,  ipv4.getDestinationAddress());
+                            + "and Target IP {} and elan Tag {}", srcIpStr, dstIpStr, elanTag);
+                    BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag, ipv4.getDestinationAddress());
                     //Handle subnet routes ip requests
                     if (dpnId != BigInteger.ZERO) {
                         long groupid = VpnUtil.getRemoteBCGroup(elanTag);
                         String key = srcIpStr + dstIpStr;
                         sendArpRequest(dpnId, groupid, srcMac, srcIp, dstIp);
-                        arpList.add(key);
                     }
                     return;
                 }
+            } catch (Exception ex) {
+                //Failed to handle packet
+                s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets ", ex);
+            }
+            return;
+        }
 
+        if (tableId == NwConstants.L3_INTERFACE_TABLE) {
+            s_logger.trace("SubnetRoutePacketInHandler: Packet from Table {} received as {}",
+                    NwConstants.L3_INTERFACE_TABLE, notification);
+            try {
+                res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+            } catch (Exception e) {
+                s_logger.warn("SubnetRoutePacketInHandler: Failed to decode Table " + NwConstants.L3_INTERFACE_TABLE + " Packet ", e);
+                return;
+            }
+            try {
+                Packet pkt = res.getPayload();
                 if (pkt instanceof ARP) {
                     s_logger.debug("SubnetRoutePacketInHandler: ARP packet received");
                     ARP arpPacket = (ARP) pkt;
@@ -126,57 +147,58 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                         byte[] respDst = arpPacket.getTargetProtocolAddress();
                         String respIp = toStringIpAddress(respSrc);
                         String check = toStringIpAddress(respDst) + respIp;
-                        if (arpList.contains(check)) {
-                            s_logger.debug("SubnetRoutePacketInHandler: ARP reply received for listening target IP " + respIp);
-                            String destination = VpnUtil.getIpPrefix(respIp);
-                            long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
-                            s_logger.debug("SubnetRoutePacketInHandler Lport Tag of arp replier " + portTag);
-                            IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
-                            String ifName = interfaceInfo.getInterfaceName();
-                            InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
-                            VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
+                        if (VpnUtil.getNeutronPortNamefromPortFixedIp(broker, respIp) != null) {
+                            s_logger.debug("SubnetRoutePacketInHandler: ARP reply Packet received with "
+                                    + "Source IP {} which is a valid Neutron port, ignoring subnet route processing", respIp);
+                            return;
+                        }
+                        String destination = VpnUtil.getIpPrefix(respIp);
+                        long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+                        s_logger.info("SubnetRoutePacketInHandler: ARP reply received for target IP {} from LPort {}" + respIp, portTag);
+                        IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
+                        String ifName = interfaceInfo.getInterfaceName();
+                        InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
+                        VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
 
-                            //Get VPN interface adjacencies
-                            if (vpnInterface != null) {
-                                InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
-                                Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
-                                String nextHopIpAddr = null;
-                                String nextHopMacAddress = null;
-                                if (adjacencies.isPresent()) {
-                                    List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
-                                    for (Adjacency adjacs : adjacencyList) {
-                                        if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
-                                            nextHopIpAddr = adjacs.getIpAddress();
-                                            nextHopMacAddress = adjacs.getMacAddress();
-                                            break;
-                                        }
-                                    }
-                                    if (nextHopMacAddress != null && destination != null) {
-                                        String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
-                                        long label =
-                                                VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
-                                                        VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
-                                        String nextHopIp = nextHopIpAddr.split("/")[0];
-                                        Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
-                                                (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
-                                        adjacencyList.add(newAdj);
-                                        Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
-                                        VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
-                                                setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
-                                                addAugmentation(Adjacencies.class, aug).build();
-                                        VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
-                                        s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
+                        //Get VPN interface adjacencies
+                        if (vpnInterface != null) {
+                            InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
+                            Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
+                            String nextHopIpAddr = null;
+                            String nextHopMacAddress = null;
+                            if (adjacencies.isPresent()) {
+                                List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
+                                for (Adjacency adjacs : adjacencyList) {
+                                    if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
+                                        nextHopIpAddr = adjacs.getIpAddress();
+                                        nextHopMacAddress = adjacs.getMacAddress();
+                                        break;
                                     }
                                 }
+                                if (nextHopMacAddress != null && destination != null) {
+                                    String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
+                                    long label =
+                                            VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+                                                    VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
+                                    String nextHopIp = nextHopIpAddr.split("/")[0];
+                                    Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
+                                            (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
+                                    adjacencyList.add(newAdj);
+                                    Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
+                                    VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
+                                            setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
+                                            addAugmentation(Adjacencies.class, aug).build();
+                                    VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
+                                    s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
+                                }
                             }
-                            //Remove from list once response was processed
-                            arpList.remove(check);
                         }
                     }
                 }
             } catch (Exception ex) {
                 //Failed to decode packet
-                s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets {}", ex);
+                s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute Table " + NwConstants.L3_INTERFACE_TABLE +
+                        " packets ", ex);
             }
         }
     }
@@ -190,10 +212,6 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
         }
         InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
                 .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
-        s_logger.trace("SubnetRoutePacketInHandler: Obtained target ip address as " + ipAddress);
-        s_logger.trace("SubnetRoutePacketInHandler: Obtained elanTag as " + elanTag);
-        s_logger.trace("SubnetRoutePacketInHandler: Obtained elanInfo as " + elanInfo);
-        s_logger.trace("SubnetRoutePacketInHandler: Obtained network name as " + elanInfo.getName());
 
         Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
         if (optionalNetworkMap.isPresent()) {
@@ -207,9 +225,9 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                 if (!optionalSubs.isPresent()) {
                     continue;
                 }
-                s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId.getValue());
                 SubnetOpDataEntry subOpEntry = optionalSubs.get();
                 if (subOpEntry.getNhDpnId() != null) {
+                    s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId);
                     boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
                     s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
                     if (match) {
@@ -256,8 +274,8 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
     private void sendArpRequest(BigInteger dpnId, long groupId, byte[] abySenderMAC, byte[] abySenderIpAddress,
                                 byte[] abyTargetIpAddress) {
 
-        s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderMAC {}, senderIPAddress {}, targetIPAddress {}",
-                dpnId, groupId,new String(abySenderMAC, StandardCharsets.UTF_8),
+        s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderIPAddress {}, targetIPAddress {}",
+                dpnId, groupId,
                 toStringIpAddress(abySenderIpAddress),toStringIpAddress(abyTargetIpAddress));
         if (abySenderIpAddress != null) {
             byte[] arpPacket;
@@ -293,8 +311,8 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
             arp.setTargetProtocolAddress(targetIP);
             rawArpPkt = arp.serialize();
         } catch (Exception ex) {
-            s_logger.error("VPNUtil:  Serialized ARP packet with senderMacAddress {} senderIp {} targetIP {} exception {}",
-                    senderMacAddress, senderIP, targetIP, ex);
+            s_logger.error("VPNUtil:  Serialized ARP packet with senderIp {} targetIP {} exception ",
+                    senderIP, targetIP, ex);
         }
 
         return rawArpPkt;
@@ -310,7 +328,7 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
             ethernet.setRawPayload(arp);
             rawEthPkt = ethernet.serialize();
         } catch (Exception ex) {
-            s_logger.error("VPNUtil:  Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception {}",
+            s_logger.error("VPNUtil:  Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception ",
                     sourceMAC, targetMAC, ex);
         }
         return rawEthPkt;
index 62d6db72e2992a5d59c6c744d6d6a73470e1dfc2..a764d396855feffe0701c9b44afce7b4954f52ef 100644 (file)
@@ -21,7 +21,8 @@ public class VpnConstants {
     public static final BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
     public static final BigInteger COOKIE_L3_BASE = new BigInteger("8000000", 16);
     public static final String FLOWID_PREFIX = "L3.";
-    public static final long WAIT_TIME_IN_MILLISECONDS = 5000;
+    public static final long MIN_WAIT_TIME_IN_MILLISECONDS = 10000;
+    public static final long MAX_WAIT_TIME_IN_MILLISECONDS = 90000;
     public static final int ELAN_GID_MIN = 200000;
     public static final short ELAN_SMAC_TABLE = 50;
     public static final short FIB_TABLE = 21;
index 2a9a96138aa8c6a3fb5689531fa7fe1f81452fa8..469b0e33a6c6c9f84d035cc78ba647acd77c359e 100644 (file)
@@ -16,11 +16,21 @@ import com.google.common.util.concurrent.JdkFutureAdapters;
 import org.opendaylight.controller.md.sal.binding.api.*;
 import org.opendaylight.vpnservice.mdsalutil.*;
 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.l3vpn.rev130911.NeutronRouterDpns;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
@@ -352,7 +362,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
 
         // Install the flow entry in L3_INTERFACE_TABLE
         String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
@@ -499,7 +509,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 vpnIntfMap.put(interfaceName, notifyTask);
                 synchronized (notifyTask) {
                     try {
-                        notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS);
+                        notifyTask.wait(VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS);
                     } catch (InterruptedException e) {
                     }
                 }
@@ -514,15 +524,18 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
 
         String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
+        LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", intf.getName(),
+                intf.getVpnInstanceName(), rd);
         if (adjacencies.isPresent()) {
             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
 
             if (!nextHops.isEmpty()) {
                 LOG.trace("NextHops are " + nextHops);
                 for (Adjacency nextHop : nextHops) {
-                    VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+                    // Commenting the release of ID here as it will be released by FIB
+                   /* VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
                                       VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
-                    /*VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                    VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
                                    VpnUtil.getPrefixToInterfaceIdentifier(
                                        VpnUtil.getVpnId(broker, intf.getVpnInstanceName()),
                                        nextHop.getIpAddress()),
@@ -734,8 +747,9 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     while (adjIt.hasNext()) {
                         Adjacency adjElem = adjIt.next();
                         if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
-                            VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
-                                    VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));
+                            // Commenting the release of ID here as it will be released by FIB
+                           /* VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+                                    VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));*/
                             adjIt.remove();
 
                             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
@@ -801,42 +815,56 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
             final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
             String interfaceName = key.getName();
-
-            //increment the vpn interface count in Vpn Instance Op Data
-            Long ifCnt = 0L;
-            String rd = getRouteDistinguisher(del.getVpnInstanceName());
-            if(rd == null || rd.isEmpty()) rd = del.getVpnInstanceName();
-            VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
-            if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
-                ifCnt = vpnInstOp.getVpnInterfaceCount();
-            }
-
-            LOG.trace("VpnInterfaceOpListener remove: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt);
-
-            if(ifCnt != 0) {
-                VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-                        VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-                        VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
-            }
-
-            // Vpn Interface removed => No more adjacencies from it.
-            // Hence clean up interface from vpn-dpn-interface list.
-            Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
-            Optional<Prefixes> prefixToInterface = Optional.absent();
-            prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
-                         VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                                VpnUtil.getIpPrefix(adjacency.getIpAddress())));
-            if (!prefixToInterface.isPresent()) {
-                prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
-                                                 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                                         VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
-            }
-            if (prefixToInterface.isPresent()) {
-                VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
-                               VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                                 prefixToInterface.get().getIpAddress()),
-                               VpnUtil.DEFAULT_CALLBACK);
-                updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false);
+            String vpnName = del.getVpnInstanceName();
+
+            LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
+            //decrement the vpn interface count in Vpn Instance Op Data
+            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
+                    id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
+            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+                    = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+            if (vpnInstance.isPresent()) {
+                String rd = null;
+                rd = vpnInstance.get().getVrfId();
+                //String rd = getRouteDistinguisher(del.getVpnInstanceName());
+
+                VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
+                LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
+                        interfaceName, rd, vpnName, vpnInstOp);
+
+                if (vpnInstOp != null) {
+                    // Vpn Interface removed => No more adjacencies from it.
+                    // Hence clean up interface from vpn-dpn-interface list.
+                    Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
+                    Optional<Prefixes> prefixToInterface = Optional.absent();
+                    prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                            VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+                                    VpnUtil.getIpPrefix(adjacency.getIpAddress())));
+                    if (!prefixToInterface.isPresent()) {
+                        prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                                VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+                                        VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
+                    }
+                    if (prefixToInterface.isPresent()) {
+                        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                                VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+                                        prefixToInterface.get().getIpAddress()),
+                                VpnUtil.DEFAULT_CALLBACK);
+                        updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false);
+                    }
+                    Long ifCnt = 0L;
+                    ifCnt = vpnInstOp.getVpnInterfaceCount();
+                    LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} Intf count {}",
+                            interfaceName, rd, vpnName, ifCnt);
+                    if ((ifCnt != null) && (ifCnt > 0)) {
+                        VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
+                                VpnUtil.getVpnInstanceOpDataIdentifier(rd),
+                                VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
+                    }
+                }
+            } else {
+                LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
             }
             notifyTaskIfRequired(interfaceName);
         }
@@ -948,4 +976,91 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
+       InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
+        return InstanceIdentifier.builder(NeutronRouterDpns.class)
+            .child(RouterDpnList.class, new RouterDpnListKey(routerName))
+            .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
+    }
+
+    InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
+        return InstanceIdentifier.builder(NeutronRouterDpns.class)
+            .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
+    }
+
+    protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
+        BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
+        if(dpId.equals(BigInteger.ZERO)) {
+            LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
+            return;
+        }
+        InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
+
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+                .CONFIGURATION, routerDpnListIdentifier);
+        RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
+        if (optionalRouterDpnList.isPresent()) {
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier.child(
+                    RouterInterfaces.class,  new RouterInterfacesKey(vpnInterfaceName)), routerInterface);
+        } else {
+            MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
+                    getRouterId(routerName),
+                    new RouterDpnListBuilder().setRouterId(routerName).build());
+            //VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
+            DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
+            List<RouterInterfaces> routerInterfaces =  new ArrayList<>();
+            routerInterfaces.add(routerInterface);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier,
+                    dpnVpnList.setRouterInterfaces(routerInterfaces).build());
+        }
+    }
+
+    protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
+        BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
+        if(dpId.equals(BigInteger.ZERO)) {
+            LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
+            return;
+        }
+        InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+                .CONFIGURATION, routerDpnListIdentifier);
+        if (optionalRouterDpnList.isPresent()) {
+            List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
+            RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
+
+            if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
+                if (routerInterfaces.isEmpty()) {
+                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier);
+                } else {
+                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier.child(
+                            RouterInterfaces.class,
+                            new RouterInterfacesKey(vpnInterfaceName)));
+                }
+            }
+        }
+    }
+       
+       protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,BigInteger dpId) {
+        if(dpId.equals(BigInteger.ZERO)) {
+            LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
+            return;
+        }
+        InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+                .CONFIGURATION, routerDpnListIdentifier);
+        if (optionalRouterDpnList.isPresent()) {
+            List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
+            RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
+
+            if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
+                if (routerInterfaces.isEmpty()) {
+                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier);
+                } else {
+                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier.child(
+                            RouterInterfaces.class,
+                            new RouterInterfacesKey(vpnInterfaceName)));
+                }
+            }
+        }
+    }
+
 }
index 88c73c2de8b7d68a6522dd2517175a62e712b8b7..e5d7a44aa0c8c8af842e64e8a2204912adc671ff 100644 (file)
@@ -98,7 +98,7 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
                     getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
             fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
                     getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
-            opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+            opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
                     getVpnInstanceOpListenerPath(), vpnInstOpListener, DataChangeScope.SUBTREE);
 
         } catch (final Exception e) {
@@ -115,16 +115,20 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
         this.vpnInterfaceManager = vpnInterfaceManager;
     }
 
-    private void waitForOpDataRemoval(String id) {
+    private void waitForOpRemoval(String id, long timeout) {
         //wait till DCN for update on VPN Instance Op Data signals that vpn interfaces linked to this vpn instance is zero
         Runnable notifyTask = new VpnNotifyTask();
         synchronized (id.intern()) {
-            vpnOpMap.put(id, notifyTask);
-            synchronized (notifyTask) {
-                try {
-                    notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS);
-                } catch (InterruptedException e) {
+            try {
+                vpnOpMap.put(id, notifyTask);
+                synchronized (notifyTask) {
+                    try {
+                        notifyTask.wait(timeout);
+                    } catch (InterruptedException e) {
+                    }
                 }
+            } finally {
+                vpnOpMap.remove(id);
             }
         }
 
@@ -132,55 +136,96 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
 
     @Override
     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
-        LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del);
+        LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
         String vpnName = del.getVpnInstanceName();
+        String rd = del.getIpv4Family().getRouteDistinguisher();
+        long vpnId = VpnUtil.getVpnId(broker, vpnName);
 
-        //Clean up vpn Interface
-        InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
-        Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.OPERATIONAL, vpnInterfacesId);
+        //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
+        Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
+        if ((rd != null) && (!rd.isEmpty())) {
+            vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                    VpnUtil.getVpnInstanceOpDataIdentifier(rd));
+        } else {
+            vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                    VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
+        }
 
-        if(optionalVpnInterfaces.isPresent()) {
-            List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
-            for(VpnInterface vpnInterface : vpnInterfaces) {
-                if(vpnInterface.getVpnInstanceName().equals(vpnName)) {
-                    LOG.debug("VpnInterface {} will be removed from VPN {}", vpnInterface.getName(), vpnName);
-                    vpnInterfaceManager.remove(
-                            VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+        if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
+            VpnInstanceOpDataEntry vpnOpEntry = null;
+            long timeout = VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
+            Long intfCount = 0L;
+
+            vpnOpEntry = vpnOpValue.get();
+            intfCount = vpnOpEntry.getVpnInterfaceCount();
+            if (intfCount != null && intfCount > 0) {
+                // Minimum wait time of 10 seconds for one VPN Interface clearance (inclusive of full trace on)
+                timeout = intfCount * 10000;
+                // Maximum wait time of 90 seconds for all VPN Interfaces clearance (inclusive of full trace on)
+                if (timeout > VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS) {
+                    timeout = VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS;
                 }
+                LOG.trace("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
+                        intfCount, rd, vpnName);
             }
-        }
-        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
-            vpnIdentifier = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
-        delete(LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
-
-        VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
-        String rd = del.getIpv4Family().getRouteDistinguisher();
+            LOG.trace("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
+                    (timeout/1000), rd, vpnName);
 
-        if (rd !=null) {
+            if ((rd != null)  && (!rd.isEmpty())) {
+                waitForOpRemoval(rd, timeout);
+            } else {
+                waitForOpRemoval(vpnName, timeout);
+            }
 
+            LOG.trace("Returned out of waiting for  Op Data removal for rd {}, vpnname {}", rd, vpnName);
+        }
+        // Clean up VpnInstanceToVpnId from Config DS
+        VpnUtil.removeVpnInstanceToVpnId(broker, vpnName);
+        LOG.trace("Removed vpnIdentifier for  rd{} vpnname {}", rd, vpnName);
+        if (rd != null) {
             try {
                 bgpManager.deleteVrf(rd);
             } catch (Exception e) {
-                LOG.error("Exception when removing VRF from BGP", e);
+                LOG.error("Exception when removing VRF from BGP for RD {} in VPN {} exception " + e, rd, vpnName);
             }
-            waitForOpDataRemoval(rd);
-            delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd));
+
+            // Clean up VPNExtraRoutes Operational DS
+            VpnUtil.removeVpnExtraRouteForVpn(broker, rd);
+
+            // Clean up VPNInstanceOpDataEntry
+            VpnUtil.removeVpnOpInstance(broker, rd);
         } else {
-            waitForOpDataRemoval(vpnName);
-            delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
+            // Clean up FIB Entries Config DS
+            VpnUtil.removeVrfTableForVpn(broker, vpnName);
+
+            // Clean up VPNExtraRoutes Operational DS
+            VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName);
+
+            // Clean up VPNInstanceOpDataEntry
+            VpnUtil.removeVpnOpInstance(broker, vpnName);
         }
+
+        // Clean up PrefixToInterface Operational DS
+        VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId);
+
+        // Clean up L3NextHop Operational DS
+        VpnUtil.removeL3nexthopForVpnId(broker, vpnId);
+
+        // Release the ID used for this VPN back to IdManager
+
+        VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
     }
 
     @Override
     protected void update(InstanceIdentifier<VpnInstance> identifier,
             VpnInstance original, VpnInstance update) {
-        LOG.trace("Update event - Key: {}, value: {}", identifier, update);
+        LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
     }
 
     @Override
     protected void add(InstanceIdentifier<VpnInstance> identifier,
             VpnInstance value) {
-        LOG.trace("VPN Instance key: {}, value: {}", identifier, value);
+        LOG.trace("Add VPN event key: {}, value: {}", identifier, value);
         VpnAfConfig config = value.getIpv4Family();
         String rd = config.getRouteDistinguisher();
 
@@ -196,14 +241,20 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
 
 
         if(rd == null) {
+            VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder();
+            builder.setVrfId(value.getVpnInstanceName()).setVpnId(vpnId);
+            builder.setVpnInterfaceCount(0L);
             syncWrite(LogicalDatastoreType.OPERATIONAL,
                     VpnUtil.getVpnInstanceOpDataIdentifier(value.getVpnInstanceName()),
-                    VpnUtil.getVpnInstanceOpDataBuilder(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK);
+                    builder.build(), DEFAULT_CALLBACK);
 
         } else {
+            VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder();
+            builder.setVrfId(rd).setVpnId(vpnId);
+            builder.setVpnInterfaceCount(0L);
             syncWrite(LogicalDatastoreType.OPERATIONAL,
                        VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-                       VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId), DEFAULT_CALLBACK);
+                       builder.build(), DEFAULT_CALLBACK);
 
             List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
 
@@ -230,7 +281,6 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
             }
         }
         //Try to add up vpn Interfaces if already in Operational Datastore
-        LOG.trace("Trying to add the vpn interfaces  -1.");
         InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
         Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
 
@@ -428,6 +478,7 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
         private void notifyTaskIfRequired(String vpnName) {
             Runnable notifyTask = vpnOpMap.remove(vpnName);
             if (notifyTask == null) {
+                LOG.trace("VpnInstanceOpListener update: No Notify Task queued for vpnName {}", vpnName);
                 return;
             }
             executorService.execute(notifyTask);
index 9e3ba8f0d91b588c5502048b98e265bd6f08056a..89d0382eaa6984d7776c6fb461dd046968c4b35a 100644 (file)
@@ -107,7 +107,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
                 subOpBuilder.setSubnetId(subnetId);
                 subOpBuilder.setSubnetCidr(subnetIp);
-                String rd = VpnUtil.getVpnRd(broker, vpnName);
+                String rd = VpnUtil.getVpnRdFromVpnInstanceConfig(broker, vpnName);
                 if (rd == null) {
                     logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD ");
                     return;
@@ -726,5 +726,14 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
             throw e;
         }
     }
+
+    @Override
+    public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
+    }
+
+    @Override
+    public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
+
+    }
 }
 
index 76ad366faad1b3a4b98d607cd9c5ec9a17a87f8e..d45818e7419ef06bd4093bb9e81d70ca744326a4 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFaile
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
@@ -47,6 +48,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
@@ -61,6 +65,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.E
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey;
@@ -73,6 +80,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.L3nexthop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.VpnNexthops;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronPortData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortNameKey;
@@ -230,6 +240,19 @@ public class VpnUtil {
         return rd;
     }
 
+    static String getVpnRdFromVpnInstanceConfig(DataBroker broker, String vpnName) {
+        InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
+                .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
+        Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        String rd = null;
+        if(vpnInstance.isPresent()) {
+            VpnInstance instance = vpnInstance.get();
+            VpnAfConfig config = instance.getIpv4Family();
+            rd = config.getRouteDistinguisher();
+        }
+        return rd;
+    }
+
     static org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
            getVpnInstanceToVpnId(String vpnName, long vpnId, String rd) {
         return new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceBuilder()
@@ -257,6 +280,16 @@ public class VpnUtil {
         return new VpnInstanceOpDataEntryBuilder().setVpnInterfaceCount(count).setVrfId(vrfId).build();
     }
 
+       static InstanceIdentifier<RouterInterface> getRouterInterfaceId(String interfaceName) {
+        return InstanceIdentifier.builder(RouterInterfaces.class)
+                .child(RouterInterface.class, new RouterInterfaceKey(interfaceName)).build();
+    }
+
+    static RouterInterface getRouterInterface(String interfaceName, String routerName) {
+        return new RouterInterfaceBuilder().setKey(new RouterInterfaceKey(interfaceName))
+                .setInterfaceName(interfaceName).setRouterName(routerName).build();
+    }
+       
     static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(broker, LogicalDatastoreType.OPERATIONAL, id);
@@ -432,7 +465,6 @@ public class VpnUtil {
 
     public static boolean isIpInSubnet(int ipAddress, String subnetCidr) {
         String[] subSplit = subnetCidr.split("/");
-        LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet Split " + subSplit);
         if (subSplit.length < 2) {
             return false;
         }
@@ -448,13 +480,72 @@ public class VpnUtil {
         }
         int prefixLength = Integer.valueOf(subSplit[1]);
         int mask = -1 << (32 - prefixLength);
-        LOG.trace("SubnetRoutePacketInHandler: prefixLength " + prefixLength + " mask " + mask);
-        LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (subnet & mask));
-        LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (ipAddress & mask));
         if ((subnet & mask) == (ipAddress & mask)) {
             return true;
         }
         return false;
     }
 
+    public static void removePrefixToInterfaceForVpnId(DataBroker broker, long vpnId) {
+        try {
+            // Clean up PrefixToInterface Operational DS
+            delete(broker, LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.builder(PrefixToInterface.class).child(VpnIds.class, new VpnIdsKey(vpnId)).build(),
+                    DEFAULT_CALLBACK);
+        } catch (Exception e) {
+            LOG.error("Exception during cleanup of PrefixToInterface for VPN ID {}", vpnId, e);
+        }
+    }
+
+    public static void removeVpnExtraRouteForVpn(DataBroker broker, String vpnName) {
+        try {
+            // Clean up VPNExtraRoutes Operational DS
+            delete(broker, LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.builder(VpnToExtraroute.class).child(Vpn.class, new VpnKey(vpnName)).build(),
+                    DEFAULT_CALLBACK);
+        } catch (Exception e) {
+            LOG.error("Exception during cleanup of VPNToExtraRoute for VPN {}", vpnName, e);
+        }
+    }
+
+    public static void removeVpnOpInstance(DataBroker broker, String vpnName) {
+        try {
+            // Clean up VPNInstanceOpDataEntry
+            delete(broker, LogicalDatastoreType.OPERATIONAL, getVpnInstanceOpDataIdentifier(vpnName),
+                    DEFAULT_CALLBACK);
+        } catch (Exception e) {
+            LOG.error("Exception during cleanup of VPNInstanceOpDataEntry for VPN {}", vpnName, e);
+        }
+    }
+
+    public static void removeVpnInstanceToVpnId(DataBroker broker, String vpnName) {
+        try {
+            delete(broker, LogicalDatastoreType.CONFIGURATION, getVpnInstanceToVpnIdIdentifier(vpnName),
+                    DEFAULT_CALLBACK);
+        } catch (Exception e) {
+            LOG.error("Exception during clean up of VpnInstanceToVpnId for VPN {}", vpnName, e);
+        }
+    }
+
+    public static void removeVrfTableForVpn(DataBroker broker, String vpnName) {
+        // Clean up FIB Entries Config DS
+        try {
+            delete(broker, LogicalDatastoreType.CONFIGURATION,
+                    InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(vpnName)).build(),
+                    DEFAULT_CALLBACK);
+        } catch (Exception e) {
+            LOG.error("Exception during clean up of VrfTable from FIB for VPN {}", vpnName, e);
+        }
+    }
+
+    public static void removeL3nexthopForVpnId(DataBroker broker, long vpnId) {
+        try {
+            // Clean up L3NextHop Operational DS
+            delete(broker, LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).build(),
+                    DEFAULT_CALLBACK);
+        } catch (Exception e) {
+            LOG.error("Exception during cleanup of L3NextHop for VPN ID {}", vpnId, e);
+        }
+    }
 }
\ No newline at end of file
index 67eccf91ad3f6a613662c8e02026f24191510756..30ae8178ba0609fabb14c6c717353cc2af6ee546 100644 (file)
@@ -70,6 +70,9 @@ public class VpnserviceProvider implements BindingAwareProvider, IVpnManager,
             notificationService.registerNotificationListener(subnetRoutePacketInHandler);
             vpnManager.setVpnInterfaceManager(vpnInterfaceManager);
             createIdPool();
+                       
+                       RouterInterfaceListener routerListener = new RouterInterfaceListener(dataBroker);
+            routerListener.setVpnInterfaceManager(vpnInterfaceManager);
         } catch (Exception e) {
             LOG.error("Error initializing services", e);
         }
index bf933fef79df2beeca9bf1825f0aae1c81e70ab0..3d9217014e9c69f8f56ed2b0b9f90f2c4362c093 100644 (file)
@@ -26,6 +26,10 @@ import org.opendaylight.vpnservice.VpnInterfaceManager;
 import org.opendaylight.vpnservice.VpnSubnetRouteHandler;
 import org.opendaylight.vpnservice.interfacemgr.globals.IfmConstants;
 import org.opendaylight.vpnservice.utilities.InterfaceUtils;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv4Family;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance
+        .Ipv4FamilyBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 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.IpAddressBuilder;
@@ -109,6 +113,7 @@ public class VpnSubnetRouteHandlerTest {
     SubnetToDpn subnetToDpn = null;
     RdToElanOpEntry rdToElanOpEntry = null;
     String subnetIp = "10.1.1.24";
+    String routeDistinguisher = "100:1";
     String nexthopIp = null;
     String poolName = null;
     String interfaceName = "VPN";
@@ -131,9 +136,11 @@ public class VpnSubnetRouteHandlerTest {
     DPNTEPsInfo dpntePsInfo = null;
     TunnelEndPoints tunlEndPts = null;
     IpAddress ipAddress = null;
+    Ipv4Family ipv4Family = null;
     String idKey = null;
     AllocateIdOutput allocateIdOutput = null;
     AllocateIdInput allocateIdInput = null;
+    org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance vpnInstnce;
 
     InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
             .state.Interface> ifStateId = InterfaceUtils.buildStateInterfaceId(portKey);
@@ -153,6 +160,11 @@ public class VpnSubnetRouteHandlerTest {
             child(RdToElanOpEntry.class, new RdToElanOpEntryKey(interfaceName, subnetIp)).build();
     InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id
             .VpnInstance> instVpnInstance = getVpnInstanceToVpnIdIdentifier(interfaceName);
+    InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.
+            VpnInstance> vpnInstanceIdentifier = InstanceIdentifier.builder(VpnInstances.class).child(org.opendaylight
+            .yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance.class,
+            new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances
+                    .VpnInstanceKey(interfaceName)).build();
 
     @Mock DataBroker dataBroker;
     @Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
@@ -174,6 +186,8 @@ public class VpnSubnetRouteHandlerTest {
     Optional<RdToElanOpEntry> optionalRd;
     Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
             optionalVpnInstnce;
+    Optional<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance>
+            vpnInstanceOptional;
 
     @Before
     public void setUp() throws Exception {
@@ -198,6 +212,7 @@ public class VpnSubnetRouteHandlerTest {
         optionalSubnetMap = Optional.of(subnetmap);
         optionalRd = Optional.of(rdToElanOpEntry);
         optionalVpnInstnce = Optional.of(vpnInstance);
+        vpnInstanceOptional = Optional.of(vpnInstnce);
 
         doReturn(Futures.immediateCheckedFuture(optionalRd)).when(mockReadTx).read(LogicalDatastoreType.OPERATIONAL,
                 rdIdentifier);
@@ -219,13 +234,15 @@ public class VpnSubnetRouteHandlerTest {
                 .CONFIGURATION, subMapid);
         doReturn(Futures.immediateCheckedFuture(optionalVpnInstnce)).when(mockReadTx).read(LogicalDatastoreType
                 .CONFIGURATION, instVpnInstance);
+        doReturn(Futures.immediateCheckedFuture(vpnInstanceOptional)).when(mockReadTx).read(LogicalDatastoreType
+                .CONFIGURATION,vpnInstanceIdentifier);
         doReturn(idOutputOptional).when(idManager).allocateId(allocateIdInput);
     }
 
     private void setupMocks() {
 
         nexthopIp = "10.1.1.25";
-        idKey = "VPN.10.1.1.24";
+        idKey = "100:1.10.1.1.24";
         poolName = "vpnservices";
         elanTag = Long.valueOf(2);
         longId = Long.valueOf("100");
@@ -271,7 +288,7 @@ public class VpnSubnetRouteHandlerTest {
                 .setSubnetIp(subnetIp).setVpnName(interfaceName).setElanTag(elanTag).build();
         subnetOp = new SubnetOpDataEntryBuilder().setElanTag(elanTag).setNhDpnId(dpId).setSubnetCidr(subnetIp)
                 .setSubnetId(subnetId).setKey(new SubnetOpDataEntryKey(subnetId)).setVpnName(interfaceName)
-                .setVrfId(interfaceName).setSubnetToDpn(subToDpn).setRouteAdvState(TaskState.Done).build();
+                .setVrfId(routeDistinguisher).setSubnetToDpn(subToDpn).setRouteAdvState(TaskState.Done).build();
         vpnInstance = new VpnInstanceBuilder().setVpnId(elanTag).setVpnInstanceName(interfaceName).setVrfId
                 (interfaceName).setKey(new VpnInstanceKey(interfaceName)).build();
         subnetmap = new SubnetmapBuilder().setSubnetIp(subnetIp).setId(subnetId).setNetworkId(portId).setKey(new
@@ -286,6 +303,11 @@ public class VpnSubnetRouteHandlerTest {
         rdToElanOpEntry = new RdToElanOpEntryBuilder().setElanTag(elanTag).setRd(interfaceName).setVpnName
                 (interfaceName).setNextHopIp(nexthopIp)
                 .setKey(new RdToElanOpEntryKey(interfaceName, subnetIp)).setSubnetIp(subnetIp).build();
+        ipv4Family = new Ipv4FamilyBuilder().setRouteDistinguisher(routeDistinguisher).build();
+        vpnInstnce = new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances
+                .VpnInstanceBuilder().setKey(new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
+                .rev140815.vpn.instances.VpnInstanceKey(interfaceName)).setVpnInstanceName(interfaceName)
+                .setIpv4Family(ipv4Family).build();
         doReturn(mockReadTx).when(dataBroker).newReadOnlyTransaction();
         doReturn(mockWriteTx).when(dataBroker).newWriteOnlyTransaction();
         doReturn(Futures.immediateCheckedFuture(null)).when(mockWriteTx).submit();