This updates ONOS src tree to commit id 13/3013/1
authorAshlee Young <ashlee@wildernessvoice.com>
Tue, 3 Nov 2015 22:08:10 +0000 (14:08 -0800)
committerAshlee Young <ashlee@wildernessvoice.com>
Tue, 3 Nov 2015 22:08:10 +0000 (14:08 -0800)
03fa5e571cabbd001ddb1598847e1150b11c7333

Change-Id: I13b554026d6f902933e35887d29bd5fdb669c0bd
Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
373 files changed:
framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java
framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java
framework/src/onos/apps/dhcp/api/pom.xml [new file with mode: 0644]
framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java with 100% similarity]
framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java with 100% similarity]
framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java with 100% similarity]
framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/package-info.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java with 100% similarity]
framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java [moved from framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java with 100% similarity]
framework/src/onos/apps/dhcp/app/app.xml [new file with mode: 0644]
framework/src/onos/apps/dhcp/app/features.xml [new file with mode: 0644]
framework/src/onos/apps/dhcp/app/pom.xml [new file with mode: 0644]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/package-info.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/package-info.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/package-info.java [moved from framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml [moved from framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css [moved from framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html [moved from framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js [moved from framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html [moved from framework/src/onos/apps/dhcp/src/main/resources/gui/css.html with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html [moved from framework/src/onos/apps/dhcp/src/main/resources/gui/js.html with 100% similarity]
framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml [moved from framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml with 100% similarity]
framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java [moved from framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java with 100% similarity]
framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json [moved from framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json with 100% similarity]
framework/src/onos/apps/dhcp/pom.xml
framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/package-info.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java with 86% similarity]
framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java [new file with mode: 0644]
framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/pom.xml [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java [new file with mode: 0644]
framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml [new file with mode: 0644]
framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
framework/src/onos/apps/pom.xml
framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java [new file with mode: 0644]
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java [new file with mode: 0644]
framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java
framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java
framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java
framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java [new file with mode: 0644]
framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java
framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java
framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
framework/src/onos/apps/vtn/pom.xml
framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java [new file with mode: 0644]
framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java [new file with mode: 0644]
framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java [new file with mode: 0644]
framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java [deleted file]
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java
framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllocationPoolsCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java with 97% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllowedAddressPairCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java with 97% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FixedIpCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java with 97% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/HostRoutesCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java with 97% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java [new file with mode: 0644]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SecurityGroupCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java with 97% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SubnetCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java with 98% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/TenantNetworkCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java with 98% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/VirtualPortCodec.java [moved from framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java with 98% similarity]
framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java [new file with mode: 0644]
framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java [new file with mode: 0755]
framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java
framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java [new file with mode: 0644]
framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java [new file with mode: 0755]
framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java
framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java
framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java
framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java [deleted file]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java
framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java [deleted file]
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java
framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java
framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java [new file with mode: 0644]
framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java
framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java
framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java
framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java
framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java
framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java [new file with mode: 0644]
framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java [new file with mode: 0644]
framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java [new file with mode: 0644]
framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java
framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json
framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java
framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java [new file with mode: 0644]
framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java
framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java
framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java [new file with mode: 0644]
framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java
framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
framework/src/onos/core/store/dist/pom.xml
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java [deleted file]
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java [deleted file]
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java [deleted file]
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java [new file with mode: 0644]
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java [deleted file]
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java [deleted file]
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java
framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java
framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java
framework/src/onos/core/store/persistence/pom.xml [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java [new file with mode: 0644]
framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java [new file with mode: 0644]
framework/src/onos/core/store/pom.xml
framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java [new file with mode: 0644]
framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
framework/src/onos/docs/internal-bgpls [new file with mode: 0644]
framework/src/onos/docs/internal-stores
framework/src/onos/docs/internal.xml
framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java [new file with mode: 0644]
framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java [new file with mode: 0644]
framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java [new file with mode: 0644]
framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java
framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java
framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java [moved from framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java with 97% similarity]
framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java [moved from framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java with 55% similarity]
framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
framework/src/onos/drivers/src/main/resources/onos-drivers.xml
framework/src/onos/features/features.xml
framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java [new file with mode: 0644]
framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java [new file with mode: 0644]
framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java [new file with mode: 0644]
framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java [new file with mode: 0644]
framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java [new file with mode: 0644]
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java
framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java
framework/src/onos/pom.xml
framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java
framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java
framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java
framework/src/onos/tools/build/conf/pom.xml
framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml
framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml
framework/src/onos/tools/dev/bin/onos-build-selective
framework/src/onos/tools/dev/bin/onos-build-selective.exclude
framework/src/onos/tools/dev/bin/onos-setup-karaf
framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java
framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java
framework/src/onos/tools/test/bin/onos-config
framework/src/onos/tools/test/bin/onos-execute-expect [new file with mode: 0755]
framework/src/onos/tools/test/bin/onos-gen-partitions
framework/src/onos/tools/test/bin/onos-secure-ssh
framework/src/onos/tools/test/bin/stc
framework/src/onos/tools/test/scenarios/dist-test-seq.xml [new file with mode: 0644]
framework/src/onos/tools/test/scenarios/dist-test.xml [new file with mode: 0644]
framework/src/onos/tools/test/topos/opticalUtils.py
framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java
framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java [new file with mode: 0644]
framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java
framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java
framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java
framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java
framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java
framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java
framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css
framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js
framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js
framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css
framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css
framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html
framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js [new file with mode: 0644]
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
framework/src/onos/web/gui/src/main/webapp/index.html
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json [new file with mode: 0644]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json [moved from framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json with 100% similarity]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json [new file with mode: 0644]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json [new file with mode: 0644]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json [new file with mode: 0644]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json [deleted file]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json [new file with mode: 0644]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json [moved from framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json with 100% similarity]
framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json [moved from framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json with 100% similarity]
framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json

index 72a5b12..567944a 100644 (file)
@@ -419,6 +419,7 @@ public class AAA {
          * Handles RADIUS packets.
          *
          * @param radiusPacket RADIUS packet coming from the RADIUS server.
+         * @throws StateMachineException if an illegal state transition is triggered
          */
         protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
             StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
index 4b28a14..e15bc76 100644 (file)
@@ -23,17 +23,27 @@ import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.ItemNotFoundException;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
+import org.onosproject.net.behaviour.BridgeConfig;
+import org.onosproject.net.behaviour.BridgeName;
 import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.behaviour.DefaultTunnelDescription;
+import org.onosproject.net.behaviour.TunnelConfig;
+import org.onosproject.net.behaviour.TunnelDescription;
+import org.onosproject.net.behaviour.TunnelName;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostService;
@@ -58,6 +68,7 @@ import java.util.concurrent.Executors;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.Device.Type.SWITCH;
+import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -79,7 +90,6 @@ public class CordVtn implements CordVtnService {
     private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
         {
             put("key", "flow");
-            put("local_ip", "flow");
             put("remote_ip", "flow");
         }
     };
@@ -98,6 +108,9 @@ public class CordVtn implements CordVtnService {
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DriverService driverService;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OvsdbController controller;
 
@@ -213,8 +226,8 @@ public class CordVtn implements CordVtnService {
         if (deviceService.getDevice(ovsdb.intBrId()) == null ||
                 !deviceService.isAvailable(ovsdb.intBrId())) {
             createIntegrationBridge(ovsdb);
-        } else if (!checkVxlanPort(ovsdb)) {
-            createVxlanPort(ovsdb);
+        } else if (!checkVxlanInterface(ovsdb)) {
+            createVxlanInterface(ovsdb);
         }
     }
 
@@ -272,26 +285,41 @@ public class CordVtn implements CordVtnService {
                 });
         String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN);
 
-        // TODO change to use bridge config
-        OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
-        ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers);
+        try {
+            DriverHandler handler = driverService.createHandler(ovsdb.deviceId());
+            BridgeConfig bridgeConfig =  handler.behaviour(BridgeConfig.class);
+            bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), dpid, controllers);
+        } catch (ItemNotFoundException e) {
+            log.warn("Failed to create integration bridge on {}", ovsdb.deviceId());
+        }
     }
 
-    private void createVxlanPort(OvsdbNode ovsdb) {
-        // TODO change to use tunnel config and tunnel description
-        OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
-        ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, DEFAULT_TUNNEL,
-                                 DEFAULT_TUNNEL, DEFAULT_TUNNEL_OPTIONS);
+    private void createVxlanInterface(OvsdbNode ovsdb) {
+        DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
+        for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
+            optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
+        }
+        TunnelDescription description =
+                new DefaultTunnelDescription(null, null, VXLAN,
+                                             TunnelName.tunnelName(DEFAULT_TUNNEL),
+                                             optionBuilder.build());
+        try {
+            DriverHandler handler = driverService.createHandler(ovsdb.deviceId());
+            TunnelConfig tunnelConfig =  handler.behaviour(TunnelConfig.class);
+            tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), description);
+        } catch (ItemNotFoundException e) {
+            log.warn("Failed to create VXLAN interface on {}", ovsdb.deviceId());
+        }
     }
 
-    private boolean checkVxlanPort(OvsdbNode ovsdb) {
-        // TODO change to use tunnel config
-        OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
+    private boolean checkVxlanInterface(OvsdbNode ovsdb) {
         try {
-            ovsdbClient.getPorts().stream()
-                    .filter(p -> p.portName().value().equals(DEFAULT_TUNNEL))
-                    .findFirst().get();
-        } catch (NoSuchElementException e) {
+            DriverHandler handler = driverService.createHandler(ovsdb.deviceId());
+            BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
+            bridgeConfig.getPorts().stream()
+                    .filter(p -> p.annotations().value("portName").equals(DEFAULT_TUNNEL))
+                    .findAny().get();
+        } catch (ItemNotFoundException | NoSuchElementException e) {
             return false;
         }
         return true;
@@ -374,8 +402,8 @@ public class CordVtn implements CordVtnService {
                 return;
             }
 
-            if (!checkVxlanPort(ovsdb)) {
-                createVxlanPort(ovsdb);
+            if (!checkVxlanInterface(ovsdb)) {
+                createVxlanInterface(ovsdb);
             }
         }
 
index 287f2a3..274ca9b 100644 (file)
@@ -72,8 +72,6 @@ public class CordVtnConfigManager {
 
         configService.addListener(configListener);
         configRegistry.registerConfigFactory(configFactory);
-
-        readConfiguration();
     }
 
     @Deactivate
@@ -101,7 +99,22 @@ public class CordVtnConfigManager {
 
         @Override
         public void event(NetworkConfigEvent event) {
-            // TODO handle update event
+            if (!event.configClass().equals(CordVtnConfig.class)) {
+                return;
+            }
+
+            switch (event.type()) {
+                case CONFIG_ADDED:
+                    log.info("Network configuration added");
+                    readConfiguration();
+                    break;
+                case CONFIG_UPDATED:
+                    log.info("Network configuration updated");
+                    readConfiguration();
+                    break;
+                default:
+                    break;
+            }
         }
     }
 }
index eba5210..46f6e29 100644 (file)
@@ -61,7 +61,7 @@ public class DefaultOvsdbNode implements OvsdbNode {
 
     @Override
     public DeviceId deviceId() {
-        return DeviceId.deviceId("ovsdb:" + this.ip.toString() + ":" + this.port.toString());
+        return DeviceId.deviceId("ovsdb:" + this.ip.toString());
     }
 
     @Override
diff --git a/framework/src/onos/apps/dhcp/api/pom.xml b/framework/src/onos/apps/dhcp/api/pom.xml
new file mode 100644 (file)
index 0000000..fb5246f
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2014 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-dhcp</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.4.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-dhcp-api</artifactId>
+    <packaging>bundle</packaging>
+
+    <url>http://onosproject.org</url>
+
+    <description>DHCP Server application API</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+
+</project>
diff --git a/framework/src/onos/apps/dhcp/app/app.xml b/framework/src/onos/apps/dhcp/app/app.xml
new file mode 100644 (file)
index 0000000..bf324b1
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<app name="org.onosproject.dhcp" origin="ON.Lab" version="${project.version}"
+     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
+     features="${project.artifactId}">
+    <description>${project.description}</description>
+    <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
+    <artifact>mvn:${project.groupId}/onos-app-dhcp-api/${project.version}</artifact>
+</app>
diff --git a/framework/src/onos/apps/dhcp/app/features.xml b/framework/src/onos/apps/dhcp/app/features.xml
new file mode 100644 (file)
index 0000000..0b277de
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <repository>mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features</repository>
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <feature>onos-api</feature>
+        <bundle>mvn:${project.groupId}/onos-app-dhcp-api/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-app-dhcp/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/framework/src/onos/apps/dhcp/app/pom.xml b/framework/src/onos/apps/dhcp/app/pom.xml
new file mode 100644 (file)
index 0000000..6589402
--- /dev/null
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2014 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  --><project xmlns="http://maven.apache.org/POM/4.0.0"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-dhcp</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.4.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-dhcp</artifactId>
+    <packaging>bundle</packaging>
+
+    <url>http://onosproject.org</url>
+
+    <description>DHCP Server application</description>
+
+    <properties>
+        <onos.app.name>org.onosproject.dhcp</onos.app.name>
+        <web.context>/onos/dhcp</web.context>
+        <api.version>1.0.0</api.version>
+        <api.title>DHCP Server REST API</api.title>
+        <api.description>
+            APIs for interacting with the DHCP Server application.
+        </api.description>
+        <api.package>org.onosproject.dhcp.rest</api.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-dhcp-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Include-Resource>
+                            WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
+                            {maven-resources}
+                        </Include-Resource>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            org.slf4j,
+                            org.osgi.framework,
+                            javax.ws.rs,
+                            javax.ws.rs.core,
+                            com.sun.jersey.api.core,
+                            com.sun.jersey.spi.container.servlet,
+                            com.sun.jersey.server.impl.container.servlet,
+                            com.fasterxml.jackson.databind,
+                            com.fasterxml.jackson.databind.node,
+                            com.fasterxml.jackson.core,
+                            org.apache.karaf.shell.commands,
+                            org.apache.karaf.shell.console,
+                            com.google.common.*,
+                            org.onlab.packet.*,
+                            org.onlab.rest.*,
+                            org.onosproject.*,
+                            org.onlab.util.*,
+                            org.jboss.netty.util.*
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
index 0daa4f7..7a10776 100644 (file)
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
-  --><project xmlns="http://maven.apache.org/POM/4.0.0"
-              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
-        <artifactId>onos-apps</artifactId>
         <groupId>org.onosproject</groupId>
+        <artifactId>onos-apps</artifactId>
         <version>1.4.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
-    <artifactId>onos-app-dhcp</artifactId>
-    <packaging>bundle</packaging>
-
-    <url>http://onosproject.org</url>
+    <artifactId>onos-dhcp</artifactId>
+    <packaging>pom</packaging>
 
-    <description>DHCP Server application</description>
+    <description>ONOS sample applications</description>
 
-    <properties>
-        <onos.app.name>org.onosproject.dhcp</onos.app.name>
-        <web.context>/onos/dhcp</web.context>
-        <api.version>1.0.0</api.version>
-        <api.title>DHCP Server REST API</api.title>
-        <api.description>
-            APIs for interacting with the DHCP Server application.
-        </api.description>
-        <api.package>org.onosproject.dhcp.rest</api.package>
-    </properties>
+    <modules>
+        <module>api</module>
+        <module>app</module>
+    </modules>
 
     <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-cli</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.console</artifactId>
-            <scope>compile</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onlab-junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-core-serializers</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-incubator-api</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-api</artifactId>
-            <version>${project.version}</version>
-            <classifier>tests</classifier>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-rest</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onlab-rest</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>javax.ws.rs</groupId>
-            <artifactId>jsr311-api</artifactId>
-            <version>1.1.1</version>
-        </dependency>
-        <dependency>
-            <groupId>com.sun.jersey</groupId>
-            <artifactId>jersey-servlet</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-annotations</artifactId>
-        </dependency>
     </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <configuration>
-                    <instructions>
-                        <_wab>src/main/webapp/</_wab>
-                        <Include-Resource>
-                            WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
-                            {maven-resources}
-                        </Include-Resource>
-                        <Bundle-SymbolicName>
-                            ${project.groupId}.${project.artifactId}
-                        </Bundle-SymbolicName>
-                        <Import-Package>
-                            org.slf4j,
-                            org.osgi.framework,
-                            javax.ws.rs,
-                            javax.ws.rs.core,
-                            com.sun.jersey.api.core,
-                            com.sun.jersey.spi.container.servlet,
-                            com.sun.jersey.server.impl.container.servlet,
-                            com.fasterxml.jackson.databind,
-                            com.fasterxml.jackson.databind.node,
-                            com.fasterxml.jackson.core,
-                            org.apache.karaf.shell.commands,
-                            org.apache.karaf.shell.console,
-                            com.google.common.*,
-                            org.onlab.packet.*,
-                            org.onlab.rest.*,
-                            org.onosproject.*,
-                            org.onlab.util.*,
-                            org.jboss.netty.util.*
-                        </Import-Package>
-                        <Web-ContextPath>${web.context}</Web-ContextPath>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
 </project>
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java
new file mode 100644 (file)
index 0000000..b42586f
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * REST API for multicase forwarding.
+ */
+package org.onosproject.mfwd.rest;
diff --git a/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java b/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java
new file mode 100644 (file)
index 0000000..a7d8375
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Mastership load balancer.
+ */
+package org.onosproject.mlb;
diff --git a/framework/src/onos/apps/openstackswitching/pom.xml b/framework/src/onos/apps/openstackswitching/pom.xml
new file mode 100644 (file)
index 0000000..245b9e8
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-apps</artifactId>
+        <version>1.4.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-openstackswitching</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>SONA Openstack Switching  applications</description>
+    <properties>
+        <onos.version>1.4.0-SNAPSHOT</onos.version>
+        <onos.app.name>org.onosproject.openstackswitching</onos.app.name>
+        <web.context>/onos/openstackswitching</web.context>
+        <api.version>1.0.0</api.version>
+        <api.title>ONOS OpenStack Switching REST API</api.title>
+        <api.description>
+            APIs for receiving Neutron information.
+        </api.description>
+        <api.package>org.onosproject.openstackswitching.web</api.package>
+        <onos.app.origin>SKT, Inc.</onos.app.origin>
+    </properties>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            org.slf4j,
+                            org.osgi.framework,
+                            javax.ws.rs,
+                            javax.ws.rs.core,
+                            com.sun.jersey.api.core,
+                            com.sun.jersey.spi.container.servlet,
+                            com.sun.jersey.server.impl.container.servlet,
+                            com.fasterxml.jackson.databind,
+                            com.fasterxml.jackson.databind.node,
+                            com.fasterxml.jackson.core,
+                            org.apache.karaf.shell.commands,
+                            com.google.common.*,
+                            org.onlab.packet.*,
+                            org.onosproject.*
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java
new file mode 100644 (file)
index 0000000..afaf7a2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+* Copyright 2015 Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.onosproject.openstackswitching;
+
+import org.onosproject.net.packet.InboundPacket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+
+/**
+ * It handles ARP packet from VMs.
+ */
+public class OpenstackArpHandler {
+
+    private static Logger log = LoggerFactory
+            .getLogger(OpenstackArpHandler.class);
+
+    HashMap<String, OpenstackPort> openstackPortHashMap;
+
+    /**
+     * Constructs an OpenstackArpHandler.
+     *
+     * @param openstackPortMap port map
+     */
+    public OpenstackArpHandler(HashMap<String, OpenstackPort> openstackPortMap) {
+        this.openstackPortHashMap = openstackPortMap;
+    }
+
+    /**
+     * Processes ARP packets.
+     *
+     * @param pkt ARP request packet
+     */
+    public void processPacketIn(InboundPacket pkt) {
+        log.warn("Received an ARP packet");
+    }
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java
new file mode 100644 (file)
index 0000000..9c3641c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+* Copyright 2015 Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.onosproject.openstackswitching;
+
+import org.onosproject.net.packet.InboundPacket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * It handles DHCP request packets.
+ */
+public class OpenstackDhcpHandler {
+
+    private static Logger log = LoggerFactory
+            .getLogger(OpenstackDhcpHandler.class);
+
+    /**
+     * Returns OpenstackDhcpHandler reference.
+     */
+    public OpenstackDhcpHandler() {
+
+    }
+
+    /**
+     * Processes DHCP request packets.
+     *
+     * @param pkt DHCP request packet
+     */
+    public void processPacketIn(InboundPacket pkt) {
+        log.warn("Received a DHCP packet");
+    }
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java
new file mode 100644 (file)
index 0000000..dc7c026
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * Represents the network information given by Neutron.
+ */
+public final class OpenstackNetwork {
+
+    private String name;
+    private String tenantId;
+    private String segmentId;
+    private String networkType;
+    private String id;
+
+    /**
+     * Returns the builder object of the OpenstackNetwork class.
+     *
+     * @return OpenstackNetwork builder object
+     */
+    public static OpenstackNetwork.Builder builder() {
+        return new Builder();
+    }
+
+    private OpenstackNetwork(String name, String tenantId, String id, String sid,
+                             String type) {
+        this.name = checkNotNull(name);
+        this.tenantId = checkNotNull(tenantId);
+        this.segmentId = checkNotNull(sid);
+        this.id = checkNotNull(id);
+        this.networkType = checkNotNull(type);
+    }
+
+    public String name() {
+        return this.name;
+    }
+
+    public String tenantId() {
+        return this.tenantId;
+    }
+
+    public String id() {
+        return this.id;
+    }
+
+    public String segmentId() {
+        return this.segmentId;
+    }
+
+    public String networkType() {
+        return this.networkType;
+    }
+
+    public static final class Builder {
+        private String name;
+        private String tenantId;
+        private String id;
+        private String sid;
+        private String networkType;
+
+        public Builder name(String name) {
+            this.name = name;
+
+            return this;
+        }
+
+        public Builder tenantId(String tenantId) {
+            this.tenantId = tenantId;
+
+            return this;
+        }
+
+        public Builder id(String id) {
+            this.id = id;
+
+            return this;
+        }
+
+        public Builder segmentId(String sid) {
+            this.sid = sid;
+
+            return this;
+        }
+
+        public Builder networkType(String type) {
+            this.networkType = type;
+
+            return this;
+        }
+
+        public OpenstackNetwork build() {
+            return new OpenstackNetwork(name, tenantId, id, sid, networkType);
+        }
+
+    }
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java
new file mode 100644 (file)
index 0000000..4326b4f
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching;
+
+import com.google.common.collect.Lists;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+
+import java.util.HashMap;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * It represents the Openstack Port information.
+ */
+public final class OpenstackPort {
+
+    public enum PortStatus {
+        UP,
+        DOWN
+    }
+
+    private PortStatus status;
+    private String name;
+    // FIX_ME
+    private String allowedAddressPairs;
+    private boolean adminStateUp;
+    private String networkId;
+    private String tenantId;
+    private String deviceOwner;
+    private MacAddress macAddress;
+    // <subnet id, ip address>
+    private HashMap<String, Ip4Address> fixedIps;
+    private String id;
+    private List<String> securityGroups;
+    private String deviceId;
+
+    private OpenstackPort(PortStatus status, String name, boolean adminStateUp,
+                          String networkId, String tenantId, String deviceOwner,
+                          MacAddress macAddress, HashMap fixedIps, String id,
+                          List<String> securityGroups, String deviceId) {
+
+        this.status = status;
+        this.name = name;
+        this.adminStateUp = adminStateUp;
+        this.networkId = checkNotNull(networkId);
+        this.tenantId = checkNotNull(tenantId);
+        this.deviceOwner = deviceOwner;
+        this.macAddress = checkNotNull(macAddress);
+        this.fixedIps = checkNotNull(fixedIps);
+        this.id = checkNotNull(id);
+        this.securityGroups = securityGroups;
+        this.deviceId = deviceId;
+    }
+
+
+
+    /**
+     * Returns OpenstackPort builder object.
+     *
+     * @return OpenstackPort builder
+     */
+    public static OpenstackPort.Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Returns port status.
+     *
+     * @return port status
+     */
+    public PortStatus status() {
+        return status;
+    }
+
+    /**
+     * Returns port name.
+     *
+     * @return port name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns whether admin state up or not.
+     *
+     * @return true if admin state up, false otherwise
+     */
+    public boolean isAdminStateUp() {
+        return adminStateUp;
+    }
+
+    /**
+     * Returns network ID.
+     *
+     * @return network ID
+     */
+    public String networkId() {
+        return networkId;
+    }
+
+    /**
+     * Returns device owner.
+     *
+     * @return device owner
+     */
+    public String deviceOwner() {
+        return deviceOwner;
+    }
+
+    /**
+     * Returns mac address.
+     *
+     * @return mac address
+     */
+    public MacAddress macAddress() {
+        return macAddress;
+    }
+
+    /**
+     * Returns the fixed IP information.
+     *
+     * @return fixed IP info
+     */
+    public HashMap fixedIps() {
+        return fixedIps;
+    }
+
+    /**
+     * Returns port ID.
+     *
+     * @return port ID
+     */
+    public String id() {
+        return id;
+    }
+
+    /**
+     * Returns security group information.
+     *
+     * @return security group info
+     */
+    public List<String> securityGroups() {
+        return securityGroups;
+    }
+
+    /**
+     * Returns device ID.
+     *
+     * @return device ID
+     */
+    public String deviceId() {
+        return deviceId;
+    }
+
+    // TODO : Implement the following functions when necessary
+    //@Override
+    //public void equals(Object that) {
+    //
+    //}
+    //
+    //@Override
+    //public int hashCode() {
+    //
+    //}
+
+    /**
+     * OpenstackPort Builder class.
+     */
+    public static final class Builder {
+
+        private PortStatus status;
+        private String name;
+        // FIX_ME
+        private String allowedAddressPairs;
+        private boolean adminStateUp;
+        private String networkId;
+        private String tenantId;
+        private String deviceOwner;
+        private MacAddress macAddress;
+        // list  of hash map <subnet id, ip address>
+        private HashMap<String, Ip4Address> fixedIps;
+        private String id;
+        private List<String> securityGroups;
+        private String deviceId;
+
+        Builder() {
+            fixedIps = new HashMap<>();
+            securityGroups = Lists.newArrayList();
+        }
+
+        /**
+         * Sets port status.
+         *
+         * @param status port status
+         * @return Builder object
+         */
+        public Builder portStatus(PortStatus status) {
+            this.status = status;
+
+            return this;
+        }
+
+        /**
+         * Sets port name.
+         *
+         * @param name port name
+         * @return Builder object
+         */
+        public Builder name(String name) {
+            this.name = name;
+
+            return this;
+        }
+
+        /**
+         * Sets whether admin state up or not.
+         *
+         * @param isAdminStateUp true if admin state is up, false otherwise
+         * @return Builder object
+         */
+        public Builder adminState(boolean isAdminStateUp) {
+            this.adminStateUp = isAdminStateUp;
+
+            return this;
+        }
+
+        /**
+         * Sets network ID.
+         *
+         * @param networkId network ID
+         * @return Builder object
+         */
+        public Builder netwrokId(String networkId) {
+            this.networkId = networkId;
+
+            return this;
+        }
+
+        /**
+         * Sets tenant ID.
+         *
+         * @param tenantId tenant ID
+         * @return Builder object
+         */
+        public Builder tenantId(String tenantId) {
+            this.tenantId = tenantId;
+
+            return this;
+        }
+
+        /**
+         * Sets device owner.
+         *
+         * @param owner device owner
+         * @return Builder object
+         */
+        public Builder deviceOwner(String owner) {
+            this.deviceOwner = owner;
+
+            return this;
+        }
+
+        /**
+         * Sets MAC address of the port.
+         *
+         * @param mac MAC address
+         * @return Builder object
+         */
+        public Builder macAddress(MacAddress mac) {
+            this.macAddress = mac;
+
+            return this;
+        }
+
+        /**
+         * Sets Fixed IP address information.
+         *
+         * @param fixedIpList Fixed IP info
+         * @return Builder object
+         */
+        public Builder fixedIps(HashMap<String, Ip4Address> fixedIpList) {
+            fixedIps.putAll(fixedIpList);
+
+            return this;
+        }
+
+        /**
+         * Sets ID of the port.
+         *
+         * @param id ID of the port
+         * @return Builder object
+         */
+        public Builder id(String id) {
+            this.id = id;
+
+            return this;
+        }
+
+        /**
+         * Sets security group of the port.
+         *
+         * @param securityGroup security group of the port
+         * @return Builder object
+         */
+        public Builder securityGroup(String securityGroup) {
+            securityGroups.add(securityGroup);
+
+            return this;
+        }
+
+        /**
+         * Sets device ID of the port.
+         *
+         * @param deviceId device ID
+         * @return Builder object
+         */
+        public Builder deviceId(String deviceId) {
+            this.deviceId = deviceId;
+
+            return this;
+        }
+
+        /**
+         * Builds an OpenstackPort object.
+         *
+         * @return OpenstackPort objecet
+         */
+        public OpenstackPort build() {
+            return new OpenstackPort(status, name, adminStateUp, networkId, networkId,
+                    deviceOwner, macAddress, fixedIps, id, securityGroups, deviceId);
+        }
+    }
+}
+
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java
new file mode 100644 (file)
index 0000000..baae7f8
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.UDP;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@SuppressWarnings("ALL")
+@Service
+@Component(immediate = true)
+/**
+ * It populates forwarding rules for VMs created by Openstack.
+ */
+public class OpenstackSwitchingManager implements OpenstackSwitchingService {
+
+    private static Logger log = LoggerFactory
+            .getLogger(OpenstackSwitchingManager.class);
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowObjectiveService flowObjectiveService;
+
+
+    public static final int DHCP_PORT = 67;
+
+    private ApplicationId appId;
+    private OpenstackArpHandler arpHandler;
+    private OpenstackDhcpHandler dhcpHandler = new OpenstackDhcpHandler();
+    private OpenstackSwitchingRulePopulator rulePopulator;
+    private ExecutorService deviceEventExcutorService = Executors.newFixedThreadPool(10);
+
+    private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
+    private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
+
+    // Map <port_id, OpenstackPort>
+    private HashMap<String, OpenstackPort> openstackPortMap;
+    // Map <network_id, OpenstackNetwork>
+    private HashMap<String, OpenstackNetwork> openstackNetworkMap;
+    // Map <vni, List <Entry <portName, host ip>>
+    private HashMap<String, List<PortInfo>> vniPortMap;
+    private HashMap<Ip4Address, Port> tunnelPortMap;
+
+
+    @Activate
+    protected void activate() {
+        appId = coreService
+                .registerApplication("org.onosproject.openstackswitching");
+        rulePopulator = new OpenstackSwitchingRulePopulator(appId, flowObjectiveService);
+        packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
+        deviceService.addListener(internalDeviceListener);
+
+        openstackPortMap = Maps.newHashMap();
+        openstackNetworkMap = Maps.newHashMap();
+        vniPortMap = Maps.newHashMap();
+        tunnelPortMap = Maps.newHashMap();
+
+        arpHandler = new OpenstackArpHandler(openstackPortMap);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        packetService.removeProcessor(internalPacketProcessor);
+        deviceService.removeListener(internalDeviceListener);
+
+        deviceEventExcutorService.shutdown();
+
+        log.info("Stopped");
+    }
+
+    @Override
+    public void createPorts(OpenstackPort openstackPort) {
+        openstackPortMap.put(openstackPort.id(), openstackPort);
+    }
+
+    @Override
+    public void deletePorts() {
+
+    }
+
+    @Override
+    public void updatePorts() {
+
+    }
+
+    @Override
+    public void createNetwork(OpenstackNetwork openstackNetwork) {
+        openstackNetworkMap.put(openstackNetwork.id(), openstackNetwork);
+    }
+
+    private void processDeviceAdded(Device device) {
+        log.warn("device {} is added", device.id());
+        rulePopulator.populateDefaultRules(device.id());
+    }
+
+    private void processPortAdded(Device device, Port port) {
+        // TODO: Simplify the data structure to store the network info
+        // TODO: Make it stateless
+        // TODO: All the logics need to be processed inside of the rulePopulator class
+        synchronized (vniPortMap) {
+            log.warn("port {} is updated", port.toString());
+
+            updatePortMaps(device, port);
+            if (!port.annotations().value("portName").equals("vxlan")) {
+                populateFlowRulesForTrafficToSameCnode(device, port);
+                populateFlowRulesForTrafficToDifferentCnode(device, port);
+            }
+        }
+    }
+
+    private void processPortRemoved(Device device, Port port) {
+        log.warn("port {} is removed", port.toString());
+        // TODO: need to update the vniPortMap
+    }
+
+    /**
+     * Populates the flow rules for traffic to VMs in different Cnode using
+     * Nicira extention.
+     *
+     * @param device device to put rules
+     * @param port port information of the VM
+     */
+    private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) {
+        String portName = port.annotations().value("portName");
+        String channelId = device.annotations().value("channelId");
+        Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
+        Ip4Address fixedIp = getFixedIpAddressForPort(portName);
+        // TODO: Avoid duplicate flow rule set up for VMs in other Cnode
+        //       (possibly avoided by flowrule subsystem?)
+        if (tunnelPortMap.get(hostIpAddress) == null) {
+            log.warn("There is no tunnel port information");
+            return;
+        }
+        String vni = getVniForPort(portName);
+        MacAddress vmMac = getVmMacAddressForPort(portName);
+        if (!vniPortMap.isEmpty() && vniPortMap.get(vni) != null) {
+            for (PortInfo portInfo : vniPortMap.get(vni)) {
+                if (!portInfo.portName.equals(portName) &&
+                        !portInfo.hostIp.equals(hostIpAddress)) {
+                    MacAddress vmMacx = getVmMacAddressForPort(portInfo.portName);
+                    rulePopulator.populateForwardingRuleForOtherCnode(vni,
+                            device.id(), portInfo.hostIp, portInfo.fixedIp, vmMacx,
+                            tunnelPortMap.get(hostIpAddress).number(),
+                            portInfo.deviceId, hostIpAddress, fixedIp, vmMac,
+                            tunnelPortMap.get(portInfo.hostIp).number());
+                }
+            }
+        }
+    }
+
+    /**
+     * Populates the flow rules for traffic to VMs in the same Cnode as the sender.
+     *
+     * @param device device to put the rules
+     * @param port port info of the VM
+     */
+    private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) {
+        Ip4Prefix cidr = getCidrForPort(port.annotations().value("portName"));
+        Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
+        if (vmIp != null) {
+            rulePopulator.populateForwardingRule(vmIp, device.id(), port, cidr);
+        }
+    }
+
+    /**
+     * Updates the port maps using the port information.
+     *
+     * @param device device info
+     * @param port port of the VM
+     */
+    private void updatePortMaps(Device device, Port port) {
+        String portName = port.annotations().value("portName");
+        String channelId = device.annotations().value("channelId");
+        Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
+        if (portName.startsWith("vxlan")) {
+            tunnelPortMap.put(hostIpAddress, port);
+        } else {
+            String vni = getVniForPort(portName);
+            Ip4Address fixedIp = getFixedIpAddressForPort(portName);
+            if (vniPortMap.get(vni) == null) {
+                vniPortMap.put(vni, Lists.newArrayList());
+            }
+            vniPortMap.get(vni).add(new PortInfo(device.id(), portName, fixedIp, hostIpAddress));
+        }
+    }
+
+    /**
+     * Returns CIDR information from the subnet map for the port.
+     *
+     * @param portName port name of the port of the VM
+     * @return CIDR of the VNI of the VM
+     */
+    private Ip4Prefix getCidrForPort(String portName) {
+        String networkId = null;
+        String uuid = portName.substring(3);
+        OpenstackPort port = openstackPortMap.values().stream()
+                .filter(p -> p.id().startsWith(uuid))
+                .findFirst().get();
+        if (port == null) {
+            log.warn("No port information for port {}", portName);
+            return null;
+        }
+
+        //OpenstackSubnet subnet = openstackSubnetMap.values().stream()
+        //        .filter(s -> s.networkId().equals(port.networkId()))
+        //        .findFirst().get();
+        //if (subnet == null) {
+        //    log.warn("No subnet information for network {}", subnet.id());
+        //    return null;
+        //}
+
+        //return Ip4Prefix.valueOf(subnet.cidr());
+        return null;
+    }
+
+    /**
+     * Returns the VNI of the VM of the port.
+     *
+     * @param portName VM port
+     * @return VNI
+     */
+    private String getVniForPort(String portName) {
+        String networkId = null;
+        String uuid = portName.substring(3);
+        OpenstackPort port = openstackPortMap.values().stream()
+                .filter(p -> p.id().startsWith(uuid))
+                .findFirst().get();
+        if (port == null) {
+            log.warn("No port information for port {}", portName);
+            return null;
+        }
+        OpenstackNetwork network = openstackNetworkMap.values().stream()
+                .filter(n -> n.id().equals(port.networkId()))
+                .findFirst().get();
+        if (network == null) {
+            log.warn("No VNI information for network {}", network.id());
+            return null;
+        }
+
+        return network.segmentId();
+    }
+
+    /**
+     * Returns the Fixed IP address of the VM.
+     *
+     * @param portName VM port info
+     * @return IP address of the VM
+     */
+    private Ip4Address getFixedIpAddressForPort(String portName) {
+
+        // FIXME - For now we use the information stored from neutron Rest API call.
+        // TODO - Later, the information needs to be extracted from Neutron on-demand.
+        String uuid = portName.substring(3);
+        OpenstackPort port = openstackPortMap.values().stream()
+                        .filter(p -> p.id().startsWith(uuid))
+                        .findFirst().get();
+
+        if (port == null) {
+            log.error("There is no port information for port name {}", portName);
+            return null;
+        }
+
+        if (port.fixedIps().isEmpty()) {
+            log.error("There is no fixed IP info in the port information");
+            return null;
+        }
+
+        return (Ip4Address) port.fixedIps().values().toArray()[0];
+    }
+
+    /**
+     * Returns the MAC address of the VM of the port.
+     *
+     * @param portName VM port
+     * @return MAC address of the VM
+     */
+    private MacAddress getVmMacAddressForPort(String portName) {
+
+        String uuid = portName.substring(3);
+        OpenstackPort port = openstackPortMap.values().stream()
+                .filter(p -> p.id().startsWith(uuid))
+                .findFirst().get();
+
+        if (port == null) {
+            log.error("There is no mac information for port name {}", portName);
+            return null;
+        }
+
+        return port.macAddress();
+    }
+
+    private class InternalPacketProcessor implements PacketProcessor {
+
+        @Override
+        public void process(PacketContext context) {
+
+            if (context.isHandled()) {
+                return;
+            }
+
+            InboundPacket pkt = context.inPacket();
+            Ethernet ethernet = pkt.parsed();
+
+            if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+                arpHandler.processPacketIn(pkt);
+            } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
+                IPv4 ipPacket = (IPv4) ethernet.getPayload();
+
+                if (ipPacket.getProtocol() == IPv4.PROTOCOL_UDP) {
+                    UDP udpPacket = (UDP) ipPacket.getPayload();
+                    if (udpPacket.getDestinationPort() == DHCP_PORT) {
+                        dhcpHandler.processPacketIn(pkt);
+                    }
+                }
+            }
+        }
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            deviceEventExcutorService.execute(new InternalEventHandler(event));
+        }
+    }
+
+    private class InternalEventHandler implements Runnable {
+
+        volatile DeviceEvent deviceEvent;
+
+        InternalEventHandler(DeviceEvent deviceEvent) {
+            this.deviceEvent = deviceEvent;
+        }
+
+        @Override
+        public void run() {
+            switch (deviceEvent.type()) {
+                case DEVICE_ADDED:
+                    processDeviceAdded((Device) deviceEvent.subject());
+                    break;
+                case DEVICE_UPDATED:
+                    Port port = (Port) deviceEvent.subject();
+                    if (port.isEnabled()) {
+                        processPortAdded((Device) deviceEvent.subject(), deviceEvent.port());
+                    }
+                    break;
+                case DEVICE_AVAILABILITY_CHANGED:
+                    Device device = (Device) deviceEvent.subject();
+                    if (deviceService.isAvailable(device.id())) {
+                        processDeviceAdded(device);
+                    }
+                    break;
+                case PORT_ADDED:
+                    processPortAdded((Device) deviceEvent.subject(), deviceEvent.port());
+                    break;
+                case PORT_UPDATED:
+                    processPortAdded((Device) deviceEvent.subject(), deviceEvent.port());
+                    break;
+                case PORT_REMOVED:
+                    processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    private final class PortInfo {
+        DeviceId deviceId;
+        String portName;
+        Ip4Address fixedIp;
+        Ip4Address hostIp;
+
+        private PortInfo(DeviceId deviceId, String portName, Ip4Address fixedIp,
+                         Ip4Address hostIp) {
+            this.deviceId = deviceId;
+            this.portName = portName;
+            this.fixedIp = fixedIp;
+            this.hostIp = hostIp;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java
new file mode 100644 (file)
index 0000000..9ead05f
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+* Copyright 2015 Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.onosproject.openstackswitching;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * It populates switching flow rules.
+ *
+ */
+public class OpenstackSwitchingRulePopulator {
+
+    private static Logger log = LoggerFactory
+            .getLogger(OpenstackSwitchingRulePopulator.class);
+
+    private FlowObjectiveService flowObjectiveService;
+    private ApplicationId appId;
+
+    /**
+     * Creates OpenstackSwitchingRulPopulator.
+     *
+     * @param appId application id
+     * @param flowObjectiveService FlowObjectiveService reference
+     */
+    public OpenstackSwitchingRulePopulator(ApplicationId appId,
+                                           FlowObjectiveService flowObjectiveService) {
+        this.flowObjectiveService = flowObjectiveService;
+        this.appId = appId;
+    }
+
+    /**
+     * Populates flows rules for forwarding packets to and from VMs.
+     *
+     * @param ip v4 IP Address
+     * @param  id device ID
+     * @param port port
+     * @param cidr v4 IP prefix
+     * @return true if it succeeds to populate rules, false otherwise.
+     */
+    public boolean populateForwardingRule(Ip4Address ip, DeviceId id, Port port, Ip4Prefix cidr) {
+
+
+        setFlowRuleForVMsInSameCnode(ip, id, port, cidr);
+
+        return true;
+    }
+
+    /**
+     * Populates the common flows rules for all VMs.
+     *
+     * - Send ARP packets to the controller
+     * - Send DHCP packets to the controller
+     *
+     * @param id Device ID to populates rules to
+     */
+    public void populateDefaultRules(DeviceId id) {
+
+        //setFlowRuleForDHCP(id);
+        setFlowRuleForArp(id);
+
+        log.warn("Default rule has been set");
+    }
+
+    /**
+     * Populates the forwarding rules for VMs with the same VNI but in other Code.
+     *
+     * @param vni VNI for the networks
+     * @param id device ID to populates the flow rules
+     * @param hostIp host IP address of the VM
+     * @param vmIp fixed IP address for the VM
+     * @param vmMac MAC address for the VM
+     * @param tunnelPort tunnel port number for the VM
+     * @param idx device ID for OVS of the other VM
+     * @param hostIpx host IP address of the other VM
+     * @param vmIpx fixed IP address of the other VM
+     * @param vmMacx MAC address for the other VM
+     * @param tunnelPortx x tunnel port number for other VM
+     */
+    public void populateForwardingRuleForOtherCnode(String vni, DeviceId id, Ip4Address hostIp,
+                                                    Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort,
+                                                    DeviceId idx, Ip4Address hostIpx,
+                                                    Ip4Address vmIpx, MacAddress vmMacx, PortNumber tunnelPortx) {
+        setVxLanFlowRule(vni, id, hostIp, vmIp, vmMac, tunnelPort);
+        setVxLanFlowRule(vni, idx, hostIpx, vmIpx, vmMacx, tunnelPortx);
+    }
+
+    /**
+     * Populates the flow rules for DHCP packets from VMs.
+     *
+     * @param id device ID to set the rules
+     */
+    private void setFlowRuleForDHCP(DeviceId id) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPProtocol(IPv4.PROTOCOL_UDP)
+                .matchUdpDst(TpPort.tpPort(OpenstackSwitchingManager.DHCP_PORT));
+        tBuilder.setOutput(PortNumber.CONTROLLER);
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(5000)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(id, fo);
+    }
+
+    /**
+     * Populates the flow rules for ARP packets from VMs.
+     *
+     * @param id device ID to put rules.
+     */
+    private void setFlowRuleForArp(DeviceId id) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_ARP);
+        tBuilder.setOutput(PortNumber.CONTROLLER);
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(5000)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(id, fo);
+    }
+
+    /**
+     * Sets the flow rules for traffic between VMs in the same Cnode.
+     *
+     * @param ip4Address VM IP address
+     * @param id device ID to put rules
+     * @param port VM port
+     * @param cidr subnet info of the VMs
+     */
+    private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id,
+                                              Port port, Ip4Prefix cidr) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(ip4Address.toIpPrefix())
+                .matchIPSrc(cidr);
+        tBuilder.setOutput(port.number());
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(5000)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(id, fo);
+    }
+
+    /**
+     * Sets the flow rules between traffic from VMs in different Cnode.
+     *
+     * @param vni  VNI
+     * @param id device ID
+     * @param hostIp host IP of the VM
+     * @param vmIp fixed IP of the VM
+     * @param vmMac MAC address of the VM
+     * @param tunnelPort tunnel port to forward traffic to
+     */
+    private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp,
+                                  Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(vmIp.toIpPrefix());
+        tBuilder.setTunnelId(Long.parseLong(vni))
+                //.setTunnelDst() <- for Nicira ext
+                //.setEthDst(vmMac)
+                .setOutput(tunnelPort);
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(5000)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(id, fo);
+    }
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java
new file mode 100644 (file)
index 0000000..d97b39c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching;
+
+/**
+ * It handles port management REST API from Openstack for VMs.
+ */
+public interface OpenstackSwitchingService {
+
+    /**
+     * Store the port information created by Openstack.
+     *
+     * @param openstackPort port information
+     */
+    void createPorts(OpenstackPort openstackPort);
+
+    /**
+     * Removes flow rules corresponding to the port removed by Openstack.
+     *
+     */
+    void deletePorts();
+
+    /**
+     * Updates flow rules corresponding to the port information updated by Openstack.
+     *
+     */
+    void updatePorts();
+
+    /**
+     * Store the network information created by openstack.
+     *
+     * @param openstackNetwork network information
+     */
+    void createNetwork(OpenstackNetwork openstackNetwork);
+
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java
new file mode 100644 (file)
index 0000000..cd50f91
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * OpenStack switch interface.
+ */
+package org.onosproject.openstackswitching;
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java
new file mode 100644 (file)
index 0000000..43bd158
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstackswitching.OpenstackNetwork;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the OpenstackNetwork Codec.
+ *
+ */
+public class OpenstackNetworkCodec extends JsonCodec<OpenstackNetwork> {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpenstackNetworkCodec.class);
+
+    private static final String NETWORK = "network";
+    private static final String NAME = "name";
+    private static final String TENANT_ID = "tenant_id";
+    private static final String SEGMENTATION_ID = "provider:segmentation_id";
+    private static final String NETWORK_TYPE = "provider:network_type";
+    private static final String ID = "id";
+
+    @Override
+    public OpenstackNetwork decode(ObjectNode json, CodecContext context) {
+
+        JsonNode networkInfo = json.get(NETWORK);
+
+        String name = networkInfo.path(NAME).asText();
+        String tenantId = networkInfo.path(TENANT_ID).asText();
+        String id = networkInfo.path(ID).asText();
+
+        OpenstackNetwork.Builder onb = OpenstackNetwork.builder();
+        onb.name(name)
+                .tenantId(tenantId)
+                .id(id);
+
+        if (!networkInfo.path(NETWORK_TYPE).isMissingNode()) {
+            onb.name(networkInfo.path(NETWORK_TYPE).asText());
+            onb.segmentId(networkInfo.path(SEGMENTATION_ID).asText());
+        }
+
+        return onb.build();
+    }
+
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java
new file mode 100644 (file)
index 0000000..f4c401f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.openstackswitching.OpenstackNetwork;
+import org.onosproject.openstackswitching.OpenstackSwitchingService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+@Path("networks")
+public class OpenstackNetworkWebResource extends AbstractWebResource {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpenstackNetworkWebResource.class);
+
+    private static final OpenstackNetworkCodec NETWORK_CODEC = new OpenstackNetworkCodec();
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createNetwork(InputStream input) {
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode networkNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackNetwork openstackNetwork = NETWORK_CODEC.decode(networkNode, this);
+
+            OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
+            switchingService.createNetwork(openstackNetwork);
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("Creates VirtualPort failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java
new file mode 100644 (file)
index 0000000..765b690
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstackswitching.OpenstackPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+
+/**
+ * It encodes and decodes the OpenstackPort.
+ */
+public class OpenstackPortCodec extends JsonCodec<OpenstackPort> {
+
+    private static Logger log = LoggerFactory
+            .getLogger(OpenstackPortCodec.class);
+
+    // JSON field names
+    private static final String PORT = "port";
+    private static final String STATUS = "status";
+    private static final String NAME = "name";
+    private static final String ADDRESS_PAIR = "allowed_address_pairs";
+    private static final String ADMIN_STATUS = "admin_status";
+    private static final String NETWORK_ID = "network_id";
+    private static final String TENANT_ID = "tenant_id";
+    private static final String DEVICE_OWNER = "device_owner";
+    private static final String MAC_ADDRESS = "mac_address";
+    private static final String FIXED_IPS = "fixed_ips";
+    private static final String SUBNET_ID = "subnet_id";
+    private static final String IP_ADDRESS = "ip_address";
+    private static final String ID = "id";
+    private static final String SECURITY_GROUPS = "security_groups";
+    private static final String DEVICE_ID = "device_id";
+
+    @Override
+    public OpenstackPort decode(ObjectNode json, CodecContext context) {
+
+        HashMap<String, Ip4Address> fixedIpMap = new HashMap<>();
+        JsonNode portInfo = json.get(PORT);
+
+        String status = portInfo.path(STATUS).asText();
+        String name = portInfo.path(NAME).asText();
+        boolean adminStateUp = portInfo.path(ADMIN_STATUS).asBoolean();
+        String networkId = portInfo.path(NETWORK_ID).asText();
+        String tenantId = portInfo.path(TENANT_ID).asText();
+        String deviceOwner = portInfo.path(DEVICE_OWNER).asText();
+        String macStr = portInfo.path(MAC_ADDRESS).asText();
+        ArrayNode fixedIpList = (ArrayNode) portInfo.path(FIXED_IPS);
+        for (JsonNode fixedIpInfo: fixedIpList) {
+            String subnetId = fixedIpInfo.path(SUBNET_ID).asText();
+            String ipAddressStr = fixedIpInfo.path(IP_ADDRESS).asText();
+            if (ipAddressStr != null) {
+                Ip4Address ipAddress = Ip4Address.valueOf(ipAddressStr);
+                fixedIpMap.put(subnetId, ipAddress);
+            }
+        }
+        String id = portInfo.path(ID).asText();
+        String securityGroups = portInfo.path(SECURITY_GROUPS).asText();
+        String deviceId = portInfo.path(DEVICE_ID).asText();
+
+        OpenstackPort.Builder openstackPortBuilder = OpenstackPort.builder();
+        openstackPortBuilder.portStatus(OpenstackPort.PortStatus.valueOf(status))
+                .name(name)
+                .adminState(adminStateUp)
+                .netwrokId(networkId)
+                .tenantId(tenantId)
+                .deviceOwner(deviceOwner)
+                .macAddress(MacAddress.valueOf(macStr))
+                .fixedIps(fixedIpMap)
+                .id(id)
+                .deviceId(deviceId);
+
+        // FIX ME
+        if (!securityGroups.isEmpty()) {
+            openstackPortBuilder.securityGroup(securityGroups);
+        }
+
+        OpenstackPort openstackPort = openstackPortBuilder.build();
+
+        return openstackPort;
+    }
+
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
new file mode 100644 (file)
index 0000000..67a9ceb
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.openstackswitching.OpenstackPort;
+import org.onosproject.openstackswitching.OpenstackSwitchingService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+@Path("ports")
+public class OpenstackPortWebResource extends AbstractWebResource {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpenstackPortWebResource.class);
+
+    private static final OpenstackPortCodec PORT_CODEC = new OpenstackPortCodec();
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createPorts(InputStream input) {
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode portNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this);
+
+            OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
+            switchingService.createPorts(openstackPort);
+            log.info("REST API ports is called with {}", portNode.toString());
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("Creates VirtualPort failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @DELETE
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response deletesPorts(InputStream input) {
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode portNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
+            switchingService.deletePorts();
+            log.info("REST API ports is called with {}", portNode.toString());
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("Delete VirtualPort failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @PUT
+    @Path("{id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response updatePorts(InputStream input) {
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode portNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class);
+            switchingService.updatePorts();
+            log.info("REST API ports is called with {}", portNode.toString());
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("Update VirtualPort failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+}
diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java
new file mode 100644 (file)
index 0000000..91e19c6
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * OpenStack switching REST API.
+ */
+package org.onosproject.openstackswitching.web;
diff --git a/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..53b0e2e
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>Openstack Switching REST API v1.0</display-name>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+        </init-param>
+        <init-param>
+            <param-name>com.sun.jersey.config.property.classnames</param-name>
+            <param-value>
+                org.onosproject.openstackswitching.web.OpenstackPortWebResource,
+                org.onosproject.openstackswitching.web.OpenstackNetworkWebResource
+            </param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
index 8466b95..e054502 100644 (file)
@@ -15,6 +15,7 @@
  */
 package org.onosproject.optical;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -45,16 +46,16 @@ import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.OpticalCircuitIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.newresource.ResourceAllocation;
 import org.onosproject.net.newresource.ResourceService;
 import org.onosproject.net.resource.device.IntentSetMultimap;
-import org.onosproject.net.resource.link.LinkResourceAllocations;
-import org.onosproject.net.resource.link.LinkResourceService;
 import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.net.topology.TopologyEdge;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -100,9 +101,6 @@ public class OpticalPathProvisioner {
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected IntentSetMultimap intentSetMultimap;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected LinkResourceService linkResourceService;
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceService resourceService;
 
@@ -377,17 +375,17 @@ public class OpticalPathProvisioner {
          * @param intent the intent
          */
         private void releaseResources(Intent intent) {
-            LinkResourceAllocations lra = linkResourceService.getAllocations(intent.id());
+            Collection<ResourceAllocation> allocations = resourceService.getResourceAllocations(intent.id());
             if (intent instanceof OpticalConnectivityIntent) {
                 resourceService.release(intent.id());
-                if (lra != null) {
-                    linkResourceService.releaseResources(lra);
+                if (!allocations.isEmpty()) {
+                    resourceService.release(ImmutableList.copyOf(allocations));
                 }
             } else if (intent instanceof OpticalCircuitIntent) {
                 resourceService.release(intent.id());
                 intentSetMultimap.releaseMapping(intent.id());
-                if (lra != null) {
-                    linkResourceService.releaseResources(lra);
+                if (!allocations.isEmpty()) {
+                    resourceService.release(ImmutableList.copyOf(allocations));
                 }
             }
         }
index 9821073..005052f 100644 (file)
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
-  -->
-<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/maven-v4_0_0.xsd">
+  --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
@@ -60,6 +57,7 @@
         <module>igmp</module>
         <module>pim</module>
         <module>mlb</module>
+        <module>openstackswitching</module>
   </modules>
 
     <properties>
index b2ce0f8..a27baaf 100644 (file)
@@ -15,8 +15,6 @@
  */
 package org.onosproject.sdnip;
 
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IPv6;
@@ -27,6 +25,8 @@ import org.onosproject.core.ApplicationId;
 import org.onosproject.incubator.net.intf.Interface;
 import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -43,7 +43,9 @@ import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -69,9 +71,10 @@ public class PeerConnectivityManager {
     private final ApplicationId appId;
     private final ApplicationId routerAppId;
 
-    // Just putting something random here for now. Figure out exactly what
-    // indexes we need when we start making use of them.
-    private final Multimap<BgpConfig.BgpSpeakerConfig, PointToPointIntent> peerIntents;
+    private final Map<Key, PointToPointIntent> peerIntents;
+
+    private final InternalNetworkConfigListener configListener
+            = new InternalNetworkConfigListener();
 
     /**
      * Creates a new PeerConnectivityManager.
@@ -93,13 +96,14 @@ public class PeerConnectivityManager {
         this.routerAppId = routerAppId;
         this.interfaceService = interfaceService;
 
-        peerIntents = HashMultimap.create();
+        peerIntents = new HashMap<>();
     }
 
     /**
      * Starts the peer connectivity manager.
      */
     public void start() {
+        configService.addListener(configListener);
         setUpConnectivity();
     }
 
@@ -107,6 +111,7 @@ public class PeerConnectivityManager {
      * Stops the peer connectivity manager.
      */
     public void stop() {
+        configService.removeListener(configListener);
     }
 
     /**
@@ -121,16 +126,27 @@ public class PeerConnectivityManager {
             return;
         }
 
+        Map<Key, PointToPointIntent> existingIntents = new HashMap<>(peerIntents);
+
         for (BgpConfig.BgpSpeakerConfig bgpSpeaker : config.bgpSpeakers()) {
             log.debug("Start to set up BGP paths for BGP speaker: {}",
                     bgpSpeaker);
 
             buildSpeakerIntents(bgpSpeaker).forEach(i -> {
-                peerIntents.put(bgpSpeaker, i);
-                intentSynchronizer.submit(i);
+                PointToPointIntent intent = existingIntents.remove(i.key());
+                if (intent == null || !IntentUtils.equals(i, intent)) {
+                    peerIntents.put(i.key(), i);
+                    intentSynchronizer.submit(i);
+                }
             });
-
         }
+
+        // Remove any remaining intents that we used to have that we don't need
+        // anymore
+        existingIntents.values().forEach(i -> {
+            peerIntents.remove(i.key());
+            intentSynchronizer.withdraw(i);
+        });
     }
 
     private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
@@ -356,7 +372,7 @@ public class PeerConnectivityManager {
      * @param srcIp source IP address
      * @param dstIp destination IP address
      * @param suffix suffix string
-     * @return
+     * @return intent key
      */
     private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) {
         String keyString = new StringBuilder()
@@ -370,4 +386,26 @@ public class PeerConnectivityManager {
         return Key.of(keyString, appId);
     }
 
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            switch (event.type()) {
+            case CONFIG_REGISTERED:
+                break;
+            case CONFIG_UNREGISTERED:
+                break;
+            case CONFIG_ADDED:
+            case CONFIG_UPDATED:
+            case CONFIG_REMOVED:
+                if (event.configClass() == RoutingService.CONFIG_CLASS) {
+                    setUpConnectivity();
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
 }
index c4b2daa..0dcc969 100644 (file)
@@ -34,6 +34,7 @@ import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -60,8 +61,10 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 
+import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.reset;
 import static org.easymock.EasyMock.verify;
@@ -119,6 +122,8 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
         routingConfig = createMock(RoutingConfigurationService.class);
         interfaceService = createMock(InterfaceService.class);
         networkConfigService = createMock(NetworkConfigService.class);
+        networkConfigService.addListener(anyObject(NetworkConfigListener.class));
+        expectLastCall().anyTimes();
         bgpConfig = createMock(BgpConfig.class);
 
         // These will set expectations on routingConfig and interfaceService
index f42f84b..36563f0 100644 (file)
@@ -35,7 +35,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.Set;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 public class ArpHandler {
@@ -112,7 +113,7 @@ public class ArpHandler {
 
 
     private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
-        List<Ip4Address> gatewayIpAddresses = config.getSubnetGatewayIps(deviceId);
+        Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
         if (gatewayIpAddresses != null) {
             Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
                     .getTargetProtocolAddress());
index 40ee55f..c4a91c7 100644 (file)
@@ -23,14 +23,12 @@ import org.onlab.packet.IpPrefix;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.MastershipRole;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -97,7 +95,7 @@ public class DefaultRoutingHandler {
             log.debug("populateAllRoutingRules: populationStatus is STARTED");
 
             for (Device sw : srManager.deviceService.getDevices()) {
-                if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) {
+                if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                     log.debug("populateAllRoutingRules: skipping device {}...we are not master",
                               sw.id());
                     continue;
@@ -146,8 +144,7 @@ public class DefaultRoutingHandler {
             // Take the snapshots of the links
             updatedEcmpSpgMap = new HashMap<>();
             for (Device sw : srManager.deviceService.getDevices()) {
-                if (srManager.mastershipService.
-                        getLocalRole(sw.id()) != MastershipRole.MASTER) {
+                if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                     continue;
                 }
                 ECMPShortestPathGraph ecmpSpgUpdated =
@@ -273,8 +270,7 @@ public class DefaultRoutingHandler {
         for (Device sw : srManager.deviceService.getDevices()) {
             log.debug("Computing the impacted routes for device {} due to link fail",
                       sw.id());
-            if (srManager.mastershipService.
-                    getLocalRole(sw.id()) != MastershipRole.MASTER) {
+            if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                 continue;
             }
             ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
@@ -320,8 +316,7 @@ public class DefaultRoutingHandler {
         for (Device sw : srManager.deviceService.getDevices()) {
             log.debug("Computing the impacted routes for device {}",
                       sw.id());
-            if (srManager.mastershipService.
-                    getLocalRole(sw.id()) != MastershipRole.MASTER) {
+            if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                 log.debug("No mastership for {} and skip route optimization",
                           sw.id());
                 continue;
@@ -455,7 +450,7 @@ public class DefaultRoutingHandler {
         // If both target switch and dest switch are edge routers, then set IP
         // rule for both subnet and router IP.
         if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
-            List<Ip4Prefix> subnets = config.getSubnets(destSw);
+            Set<Ip4Prefix> subnets = config.getSubnets(destSw);
             log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
                     targetSw, destSw, subnets);
             result = rulePopulator.populateIpRuleForSubnet(targetSw,
@@ -499,14 +494,13 @@ public class DefaultRoutingHandler {
     }
 
     /**
-     * Populates table miss entries for all tables, and pipeline rules for VLAN
-     * and TCAM tables. XXX rename/rethink
+     * Populates filtering rules for permitting Router DstMac and VLAN.
      *
      * @param deviceId Switch ID to set the rules
      */
-    public void populateTtpRules(DeviceId deviceId) {
-        rulePopulator.populateTableVlan(deviceId);
-        rulePopulator.populateTableTMac(deviceId);
+    public void populatePortAddressingRules(DeviceId deviceId) {
+        rulePopulator.populateRouterMacVlanFilters(deviceId);
+        rulePopulator.populateRouterIpPunts(deviceId);
     }
 
     /**
index 0bc155b..828c51c 100644 (file)
@@ -15,6 +15,7 @@
  */
 package org.onosproject.segmentrouting;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
@@ -38,20 +39,20 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Segment Routing configuration component that reads the
  * segment routing related configuration from Network Configuration Manager
  * component and organizes in more accessible formats.
- *
- * TODO: Merge multiple Segment Routing configuration wrapper classes into one.
  */
 public class DeviceConfiguration implements DeviceProperties {
 
     private static final Logger log = LoggerFactory
             .getLogger(DeviceConfiguration.class);
     private final List<Integer> allSegmentIds = new ArrayList<>();
-    private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
+    private final ConcurrentHashMap<DeviceId, SegmentRouterInfo> deviceConfigMap
+        = new ConcurrentHashMap<>();
 
     private class SegmentRouterInfo {
         int nodeSid;
@@ -126,18 +127,17 @@ public class DeviceConfiguration implements DeviceProperties {
     }
 
     /**
-     * Returns the segment id of a segment router.
+     * Returns the Node segment id of a segment router.
      *
      * @param deviceId device identifier
      * @return segment id
      */
     @Override
     public int getSegmentId(DeviceId deviceId) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            log.trace("getSegmentId for device{} is {}",
-                    deviceId,
-                    deviceConfigMap.get(deviceId).nodeSid);
-            return deviceConfigMap.get(deviceId).nodeSid;
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getSegmentId for device{} is {}", deviceId, srinfo.nodeSid);
+            return srinfo.nodeSid;
         } else {
             log.warn("getSegmentId for device {} "
                     + "throwing IllegalStateException "
@@ -147,10 +147,10 @@ public class DeviceConfiguration implements DeviceProperties {
     }
 
     /**
-     * Returns the segment id of a segment router given its mac address.
+     * Returns the Node segment id of a segment router given its Router mac address.
      *
      * @param routerMac router mac address
-     * @return segment id
+     * @return node segment id, or -1 if not found in config
      */
     public int getSegmentId(MacAddress routerMac) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
@@ -164,10 +164,10 @@ public class DeviceConfiguration implements DeviceProperties {
     }
 
     /**
-     * Returns the segment id of a segment router given its router ip address.
+     * Returns the Node segment id of a segment router given its Router ip address.
      *
      * @param routerAddress router ip address
-     * @return segment id
+     * @return node segment id, or -1 if not found in config
      */
     public int getSegmentId(Ip4Address routerAddress) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
@@ -188,11 +188,10 @@ public class DeviceConfiguration implements DeviceProperties {
      */
     @Override
     public MacAddress getDeviceMac(DeviceId deviceId) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            log.trace("getDeviceMac for device{} is {}",
-                    deviceId,
-                    deviceConfigMap.get(deviceId).mac);
-            return deviceConfigMap.get(deviceId).mac;
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
+            return srinfo.mac;
         } else {
             log.warn("getDeviceMac for device {} "
                     + "throwing IllegalStateException "
@@ -208,11 +207,10 @@ public class DeviceConfiguration implements DeviceProperties {
      * @return router ip address
      */
     public Ip4Address getRouterIp(DeviceId deviceId) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            log.trace("getDeviceIp for device{} is {}",
-                    deviceId,
-                    deviceConfigMap.get(deviceId).ip);
-            return deviceConfigMap.get(deviceId).ip;
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getDeviceIp for device{} is {}", deviceId, srinfo.ip);
+            return srinfo.ip;
         } else {
             log.warn("getRouterIp for device {} "
                     + "throwing IllegalStateException "
@@ -223,18 +221,17 @@ public class DeviceConfiguration implements DeviceProperties {
 
     /**
      * Indicates if the segment router is a edge router or
-     * a transit/back bone router.
+     * a core/backbone router.
      *
      * @param deviceId device identifier
      * @return boolean
      */
     @Override
     public boolean isEdgeDevice(DeviceId deviceId) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            log.trace("isEdgeDevice for device{} is {}",
-                    deviceId,
-                    deviceConfigMap.get(deviceId).isEdge);
-            return deviceConfigMap.get(deviceId).isEdge;
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
+            return srinfo.isEdge;
         } else {
             log.warn("isEdgeDevice for device {} "
                     + "throwing IllegalStateException "
@@ -244,15 +241,35 @@ public class DeviceConfiguration implements DeviceProperties {
     }
 
     /**
-     * Returns the segment ids of all configured segment routers.
+     * Returns the node segment ids of all configured segment routers.
      *
-     * @return list of segment ids
+     * @return list of node segment ids
      */
     @Override
     public List<Integer> getAllDeviceSegmentIds() {
         return allSegmentIds;
     }
 
+    @Override
+    public Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId) {
+        Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
+
+        // Construct subnet-port mapping from port-subnet mapping
+        Map<PortNumber, Ip4Prefix> portSubnetMap =
+                this.deviceConfigMap.get(deviceId).subnets;
+        portSubnetMap.forEach((port, subnet) -> {
+            if (subnetPortMap.containsKey(subnet)) {
+                subnetPortMap.get(subnet).add(port);
+            } else {
+                ArrayList<PortNumber> ports = new ArrayList<>();
+                ports.add(port);
+                subnetPortMap.put(subnet, ports);
+            }
+        });
+
+        return subnetPortMap;
+    }
+
     /**
      * Returns the device identifier or data plane identifier (dpid)
      * of a segment router given its segment id.
@@ -290,37 +307,68 @@ public class DeviceConfiguration implements DeviceProperties {
     }
 
     /**
-     * Returns the configured subnet gateway ip addresses for a segment router.
+     * Returns the configured port ip addresses for a segment router.
+     * These addresses serve as gateway IP addresses for the subnets configured
+     * on those ports.
      *
      * @param deviceId device identifier
-     * @return list of ip addresses
+     * @return immutable set of ip addresses configured on the ports or null if not found
      */
-    public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            log.trace("getSubnetGatewayIps for device{} is {}",
-                    deviceId,
-                    deviceConfigMap.get(deviceId).gatewayIps.values());
-            return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values());
-        } else {
-            return null;
+    public Set<Ip4Address> getPortIPs(DeviceId deviceId) {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
+                      srinfo.gatewayIps.values());
+            return ImmutableSet.copyOf(srinfo.gatewayIps.values());
+        }
+        return null;
+    }
+
+    /**
+     * Returns the configured IP addresses per port
+     * for a segment router.
+     *
+     * @param deviceId device identifier
+     * @return map of port to gateway IP addresses or null if not found
+     */
+    public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            return srinfo.gatewayIps;
         }
+        return null;
     }
 
     /**
      * Returns the configured subnet prefixes for a segment router.
      *
      * @param deviceId device identifier
-     * @return list of ip prefixes
+     * @return list of ip prefixes or null if not found
      */
-    public List<Ip4Prefix> getSubnets(DeviceId deviceId) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            log.trace("getSubnets for device{} is {}",
-                    deviceId,
-                    deviceConfigMap.get(deviceId).subnets.values());
-            return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values());
-        } else {
-            return null;
+    public Set<Ip4Prefix> getSubnets(DeviceId deviceId) {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getSubnets for device{} is {}", deviceId,
+                      srinfo.subnets.values());
+            return ImmutableSet.copyOf(srinfo.subnets.values());
         }
+        return null;
+    }
+
+    /**
+     *  Returns the configured subnet on the given port, or null if no
+     *  subnet has been configured on the port.
+     *
+     *  @param deviceId device identifier
+     *  @param pnum  port identifier
+     *  @return configured subnet on port, or null
+     */
+    public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            return srinfo.subnets.get(pnum);
+        }
+        return null;
     }
 
     /**
@@ -349,7 +397,7 @@ public class DeviceConfiguration implements DeviceProperties {
      * specified ip address as one of its subnet gateway ip address.
      *
      * @param gatewayIpAddress router gateway ip address
-     * @return router mac address
+     * @return router mac address or null if not found
      */
     public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
@@ -377,7 +425,7 @@ public class DeviceConfiguration implements DeviceProperties {
      */
     public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) {
 
-        List<Ip4Prefix> subnets = getSubnets(deviceId);
+        Set<Ip4Prefix> subnets = getSubnets(deviceId);
         if (subnets == null) {
             return false;
         }
@@ -399,8 +447,9 @@ public class DeviceConfiguration implements DeviceProperties {
      * @return list of port numbers
      */
     public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            for (AdjacencySid asid : srinfo.adjacencySids) {
                 if (asid.getAsid() == sid) {
                     return asid.getPorts();
                 }
@@ -419,12 +468,13 @@ public class DeviceConfiguration implements DeviceProperties {
      * otherwise false
      */
     public boolean isAdjacencySid(DeviceId deviceId, int sid) {
-        if (deviceConfigMap.get(deviceId) != null) {
-            if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            if (srinfo.adjacencySids.isEmpty()) {
                 return false;
             } else {
                 for (AdjacencySid asid:
-                        deviceConfigMap.get(deviceId).adjacencySids) {
+                        srinfo.adjacencySids) {
                     if (asid.getAsid() == sid) {
                         return true;
                     }
index f65f03e..b3916b0 100644 (file)
@@ -32,7 +32,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -70,7 +70,7 @@ public class IcmpHandler {
         DeviceId deviceId = connectPoint.deviceId();
         Ip4Address destinationAddress =
                 Ip4Address.valueOf(ipv4.getDestinationAddress());
-        List<Ip4Address> gatewayIpAddresses = config.getSubnetGatewayIps(deviceId);
+        Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
         Ip4Address routerIp = config.getRouterIp(deviceId);
         IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
         Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address();
index 7641571..d46028e 100644 (file)
@@ -25,6 +25,7 @@ import org.onlab.packet.VlanId;
 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
+import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -38,11 +39,13 @@ import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.flowobjective.Objective;
 import org.onosproject.net.flowobjective.ObjectiveError;
 import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
+import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
 import org.onosproject.net.flowobjective.ObjectiveContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
@@ -57,6 +60,11 @@ public class RoutingRulePopulator {
     private AtomicLong rulePopulationCounter;
     private SegmentRoutingManager srManager;
     private DeviceConfiguration config;
+
+    private static final int HIGHEST_PRIORITY = 0xffff;
+    private static final long OFPP_MAX = 0xffffff00L;
+
+
     /**
      * Creates a RoutingRulePopulator object.
      *
@@ -98,7 +106,7 @@ public class RoutingRulePopulator {
         TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
         TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
 
-        sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
+        sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
         sbuilder.matchEthType(Ethernet.TYPE_IPV4);
 
         tbuilder.deferred()
@@ -134,7 +142,7 @@ public class RoutingRulePopulator {
      * @return true if all rules are set successfully, false otherwise
      */
     public boolean populateIpRuleForSubnet(DeviceId deviceId,
-                                           List<Ip4Prefix> subnets,
+                                           Set<Ip4Prefix> subnets,
                                            DeviceId destSw,
                                            Set<DeviceId> nextHops) {
 
@@ -350,40 +358,80 @@ public class RoutingRulePopulator {
     }
 
     /**
-     * Populates VLAN flows rules. All packets are forwarded to TMAC table.
+     * Creates a filtering objective to permit all untagged packets with a
+     * dstMac corresponding to the router's MAC address. For those pipelines
+     * that need to internally assign vlans to untagged packets, this method
+     * provides per-subnet vlan-ids as metadata.
+     * <p>
+     * Note that the vlan assignment is only done by the master-instance for a switch.
+     * However we send the filtering objective from slave-instances as well, so
+     * that drivers can obtain other information (like Router MAC and IP).
      *
-     * @param deviceId switch ID to set the rules
+     * @param deviceId  the switch dpid for the router
      */
-    public void populateTableVlan(DeviceId deviceId) {
-        FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
-        fob.withKey(Criteria.matchInPort(PortNumber.ALL))
+    public void populateRouterMacVlanFilters(DeviceId deviceId) {
+        log.debug("Installing per-port filtering objective for untagged "
+                + "packets in device {}", deviceId);
+        for (Port port : srManager.deviceService.getPorts(deviceId)) {
+            if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
+                Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
+                VlanId assignedVlan = (portSubnet == null)
+                        ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
+                        : srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
+                FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
+                fob.withKey(Criteria.matchInPort(port.number()))
+                .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId)))
                 .addCondition(Criteria.matchVlanId(VlanId.NONE));
-        fob.permit().fromApp(srManager.appId);
-        log.debug("populateTableVlan: Installing filtering objective for untagged packets");
-        srManager.flowObjectiveService.
-            filter(deviceId,
-                   fob.add(new SRObjectiveContext(deviceId,
-                                                  SRObjectiveContext.ObjectiveType.FILTER)));
+                // vlan assignment is valid only if this instance is master
+                if (srManager.mastershipService.isLocalMaster(deviceId)) {
+                    TrafficTreatment tt = DefaultTrafficTreatment.builder()
+                            .pushVlan().setVlanId(assignedVlan).build();
+                    fob.setMeta(tt);
+                }
+                fob.permit().fromApp(srManager.appId);
+                srManager.flowObjectiveService.
+                filter(deviceId, fob.add(new SRObjectiveContext(deviceId,
+                                      SRObjectiveContext.ObjectiveType.FILTER)));
+            }
+        }
     }
 
     /**
-     * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
-     * packets are forwarded to MPLS table.
+     * Creates a forwarding objective to punt all IP packets, destined to the
+     * router's port IP addresses, to the controller. Note that the input
+     * port should not be matched on, as these packets can come from any input.
+     * Furthermore, these are applied only by the master instance.
      *
-     * @param deviceId switch ID to set the rules
+     * @param deviceId the switch dpid for the router
      */
-    public void populateTableTMac(DeviceId deviceId) {
-
-        FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
-        fob.withKey(Criteria.matchInPort(PortNumber.ALL))
-                .addCondition(Criteria.matchEthDst(config
-                                      .getDeviceMac(deviceId)));
-        fob.permit().fromApp(srManager.appId);
-        log.debug("populateTableTMac: Installing filtering objective for router mac");
-        srManager.flowObjectiveService.
-            filter(deviceId,
-                   fob.add(new SRObjectiveContext(deviceId,
-                                                  SRObjectiveContext.ObjectiveType.FILTER)));
+    public void populateRouterIpPunts(DeviceId deviceId) {
+        if (!srManager.mastershipService.isLocalMaster(deviceId)) {
+            log.debug("Not installing port-IP punts - not the master for dev:{} ",
+                      deviceId);
+            return;
+        }
+        ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder();
+        Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId));
+        allIps.add(config.getRouterIp(deviceId));
+        for (Ip4Address ipaddr : allIps) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            selector.matchEthType(Ethernet.TYPE_IPV4);
+            selector.matchIPDst(IpPrefix.valueOf(ipaddr,
+                                                 IpPrefix.MAX_INET_MASK_LENGTH));
+            treatment.setOutput(PortNumber.CONTROLLER);
+            puntIp.withSelector(selector.build());
+            puntIp.withTreatment(treatment.build());
+            puntIp.withFlag(Flag.VERSATILE)
+                .withPriority(HIGHEST_PRIORITY)
+                .makePermanent()
+                .fromApp(srManager.appId);
+            log.debug("Installing forwarding objective to punt port IP addresses");
+            srManager.flowObjectiveService.
+                forward(deviceId,
+                        puntIp.add(new SRObjectiveContext(deviceId,
+                                           SRObjectiveContext.ObjectiveType.FORWARDING)));
+        }
     }
 
     private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
index eb2cf56..9d60b27 100644 (file)
@@ -22,11 +22,17 @@ import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.VlanId;
 import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.event.Event;
+import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigRegistry;
@@ -45,7 +51,6 @@ import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.link.LinkEvent;
@@ -56,6 +61,7 @@ import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.topology.TopologyService;
+import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
 import org.onosproject.store.service.StorageService;
@@ -64,9 +70,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.URI;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Executors;
@@ -133,8 +141,13 @@ public class SegmentRoutingManager implements SegmentRoutingService {
     // Per device next objective ID store with (device id + neighbor set) as key
     private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
         Integer> nsNextObjStore = null;
+    private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
     private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
     private EventuallyConsistentMap<String, Policy> policyStore = null;
+    // Per device, per-subnet assigned-vlans store, with (device id + subnet
+    // IPv4 prefix) as key
+    private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
+        subnetVidStore = null;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected StorageService storageService;
@@ -163,6 +176,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
 
     private KryoNamespace.Builder kryoBuilder = null;
 
+    private static final short ASSIGNED_VLAN_START = 4093;
+    public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
+
     @Activate
     protected void activate() {
         appId = coreService
@@ -170,6 +186,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
 
         kryoBuilder = new KryoNamespace.Builder()
             .register(NeighborSetNextObjectiveStoreKey.class,
+                    SubnetNextObjectiveStoreKey.class,
+                    SubnetAssignedVidStoreKey.class,
                     NeighborSet.class,
                     DeviceId.class,
                     URI.class,
@@ -180,7 +198,12 @@ public class SegmentRoutingManager implements SegmentRoutingService {
                     DefaultTunnel.class,
                     Policy.class,
                     TunnelPolicy.class,
-                    Policy.Type.class
+                    Policy.Type.class,
+                    VlanId.class,
+                    Ip4Address.class,
+                    Ip4Prefix.class,
+                    IpAddress.Version.class,
+                    ConnectPoint.class
             );
 
         log.debug("Creating EC map nsnextobjectivestore");
@@ -194,6 +217,16 @@ public class SegmentRoutingManager implements SegmentRoutingService {
                 .build();
         log.trace("Current size {}", nsNextObjStore.size());
 
+        log.debug("Creating EC map subnetnextobjectivestore");
+        EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
+                subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+        subnetNextObjStore = subnetNextObjMapBuilder
+                .withName("subnetnextobjectivestore")
+                .withSerializer(kryoBuilder)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .build();
+
         EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
                 storageService.eventuallyConsistentMapBuilder();
 
@@ -212,6 +245,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
                 .build();
 
+        EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
+            subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+        subnetVidStore = subnetVidStoreMapBuilder
+                .withName("subnetvidstore")
+                .withSerializer(kryoBuilder)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .build();
+
         cfgService.addListener(cfgListener);
         cfgService.registerConfigFactory(cfgFactory);
 
@@ -296,23 +338,72 @@ public class SegmentRoutingManager implements SegmentRoutingService {
     }
 
     /**
-     * Returns the GroupKey object for the device and the NeighborSet given.
-     * XXX is this called
+     * Returns the vlan-id assigned to the subnet configured for a device.
+     * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
+     * if and only if this controller instance is the master for the device.
+     * <p>
+     * USAGE: The assigned vlans are meant to be applied to untagged packets on those
+     * switches/pipelines that need this functionality. These vids are meant
+     * to be used internally within a switch, and thus need to be unique only
+     * on a switch level. Note that packets never go out on the wire with these
+     * vlans. Currently, vlan ids are assigned from value 4093 down.
+     * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
+     * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
+     * per subnet.
+     * XXX This method should avoid any vlans configured on the ports, but
+     *     currently the app works only on untagged packets and as a result
+     *     ignores any vlan configuration.
      *
-     * @param ns NeightborSet object for the GroupKey
-     * @return GroupKey object for the NeighborSet
+     * @param deviceId switch dpid
+     * @param subnet IPv4 prefix for which assigned vlan is desired
+     * @return VlanId assigned for the subnet on the device, or
+     *         null if no vlan assignment was found and this instance is not
+     *         the master for the device.
      */
-    public GroupKey getGroupKey(NeighborSet ns) {
-        for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) {
-            return groupHandler.getGroupKey(ns);
+    public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
+        VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
+                                                        deviceId, subnet));
+        if (assignedVid != null) {
+            log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
+                    + "{}", subnet, deviceId, assignedVid);
+            return assignedVid;
+        }
+        //check mastership for the right to assign a vlan
+        if (!mastershipService.isLocalMaster(deviceId)) {
+            log.warn("This controller instance is not the master for device {}. "
+                    + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
+            return null;
+        }
+        // vlan assignment is expensive but done only once
+        Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
+        Set<Short> assignedVlans = new HashSet<>();
+        Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
+        for (Ip4Prefix sub : configuredSubnets) {
+            VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
+                                                                        sub));
+            if (v != null) {
+                assignedVlans.add(v.toShort());
+            } else {
+                unassignedSubnets.add(sub);
+            }
+        }
+        short nextAssignedVlan = ASSIGNED_VLAN_START;
+        if (!assignedVlans.isEmpty()) {
+            nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
+        }
+        for (Ip4Prefix unsub : unassignedSubnets) {
+            subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
+                               VlanId.vlanId(nextAssignedVlan--));
+            log.info("Assigned vlan: {} to subnet: {} on device: {}",
+                      nextAssignedVlan + 1, unsub, deviceId);
         }
 
-        return null;
+        return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
     }
 
     /**
-     * Returns the next objective ID for the NeighborSet given. If the nextObjectiveID does not exist,
-     * a new one is created and returned.
+     * Returns the next objective ID for the given NeighborSet.
+     * If the nextObjectiveID does not exist, a new one is created and returned.
      *
      * @param deviceId Device ID
      * @param ns NegighborSet
@@ -329,6 +420,25 @@ public class SegmentRoutingManager implements SegmentRoutingService {
         }
     }
 
+    /**
+     * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
+     * a new one is created and returned.
+     *
+     * @param deviceId Device ID
+     * @param prefix Subnet
+     * @return next objective ID
+     */
+    public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
+        if (groupHandlerMap.get(deviceId) != null) {
+            log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
+            return groupHandlerMap
+                    .get(deviceId).getSubnetNextObjectiveId(prefix);
+        } else {
+            log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
+            return -1;
+        }
+    }
+
     private class InternalPacketProcessor implements PacketProcessor {
         @Override
         public void process(PacketContext context) {
@@ -423,6 +533,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
                             event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
                             event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
                         if (deviceService.isAvailable(((Device) event.subject()).id())) {
+                            log.info("Processing device event {} for available device {}",
+                                     event.type(), ((Device) event.subject()).id());
                             processDeviceAdded((Device) event.subject());
                         }
                     } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
@@ -484,20 +596,31 @@ public class SegmentRoutingManager implements SegmentRoutingService {
 
     private void processDeviceAdded(Device device) {
         log.debug("A new device with ID {} was added", device.id());
-        //Irrespective whether the local is a MASTER or not for this device,
-        //create group handler instance and push default TTP flow rules.
-        //Because in a multi-instance setup, instances can initiate
-        //groups for any devices. Also the default TTP rules are needed
-        //to be pushed before inserting any IP table entries for any device
-        DefaultGroupHandler dgh = DefaultGroupHandler.
+        // Irrespective of whether the local is a MASTER or not for this device,
+        // we need to create a SR-group-handler instance. This is because in a
+        // multi-instance setup, any instance can initiate forwarding/next-objectives
+        // for any switch (even if this instance is a SLAVE or not even connected
+        // to the switch). To handle this, a default-group-handler instance is necessary
+        // per switch.
+        DefaultGroupHandler groupHandler = DefaultGroupHandler.
                 createGroupHandler(device.id(),
                                    appId,
                                    deviceConfiguration,
                                    linkService,
                                    flowObjectiveService,
-                                   nsNextObjStore);
-        groupHandlerMap.put(device.id(), dgh);
-        defaultRoutingHandler.populateTtpRules(device.id());
+                                   nsNextObjStore,
+                                   subnetNextObjStore);
+        groupHandlerMap.put(device.id(), groupHandler);
+
+        // Also, in some cases, drivers may need extra
+        // information to process rules (eg. Router IP/MAC); and so, we send
+        // port addressing rules to the driver as well irrespective of whether
+        // this instance is the master or not.
+        defaultRoutingHandler.populatePortAddressingRules(device.id());
+
+        if (mastershipService.isLocalMaster(device.id())) {
+            groupHandler.createGroupsFromSubnetConfig();
+        }
     }
 
     private void processPortRemoved(Device device, Port port) {
@@ -531,18 +654,29 @@ public class SegmentRoutingManager implements SegmentRoutingService {
                                               tunnelHandler, policyStore);
 
             for (Device device : deviceService.getDevices()) {
-                //Irrespective whether the local is a MASTER or not for this device,
-                //create group handler instance and push default TTP flow rules.
-                //Because in a multi-instance setup, instances can initiate
-                //groups for any devices. Also the default TTP rules are needed
-                //to be pushed before inserting any IP table entries for any device
+                // Irrespective of whether the local is a MASTER or not for this device,
+                // we need to create a SR-group-handler instance. This is because in a
+                // multi-instance setup, any instance can initiate forwarding/next-objectives
+                // for any switch (even if this instance is a SLAVE or not even connected
+                // to the switch). To handle this, a default-group-handler instance is necessary
+                // per switch.
                 DefaultGroupHandler groupHandler = DefaultGroupHandler
                         .createGroupHandler(device.id(), appId,
                                             deviceConfiguration, linkService,
                                             flowObjectiveService,
-                                            nsNextObjStore);
+                                            nsNextObjStore,
+                                            subnetNextObjStore);
                 groupHandlerMap.put(device.id(), groupHandler);
-                defaultRoutingHandler.populateTtpRules(device.id());
+
+                // Also, in some cases, drivers may need extra
+                // information to process rules (eg. Router IP/MAC); and so, we send
+                // port addressing rules to the driver as well, irrespective of whether
+                // this instance is the master or not.
+                defaultRoutingHandler.populatePortAddressingRules(device.id());
+
+                if (mastershipService.isLocalMaster(device.id())) {
+                    groupHandler.createGroupsFromSubnetConfig();
+                }
             }
 
             defaultRoutingHandler.startPopulationProcess();
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java
new file mode 100644 (file)
index 0000000..84b44c9
--- /dev/null
@@ -0,0 +1,66 @@
+package org.onosproject.segmentrouting;
+
+import java.util.Objects;
+
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.net.DeviceId;
+
+/**
+ * Class definition for key used to map per device subnets to assigned Vlan ids.
+ *
+ */
+public class SubnetAssignedVidStoreKey {
+    private final DeviceId deviceId;
+    private final Ip4Prefix subnet;
+
+    public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) {
+        this.deviceId = deviceId;
+        this.subnet = subnet;
+    }
+
+    /**
+     * Returns the device identification used to create this key.
+     *
+     * @return the device identifier
+     */
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    /**
+     * Returns the subnet information used to create this key.
+     *
+     * @return the subnet
+     */
+    public Ip4Prefix subnet() {
+        return subnet;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof SubnetAssignedVidStoreKey)) {
+            return false;
+        }
+        SubnetAssignedVidStoreKey that =
+                (SubnetAssignedVidStoreKey) o;
+        return (Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.subnet, that.subnet));
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + Objects.hashCode(deviceId)
+                + Objects.hashCode(subnet);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Device: " + deviceId + " Subnet: " + subnet;
+    }
+
+}
index c960adc..a5c1090 100644 (file)
@@ -52,9 +52,12 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
                                   LinkService linkService,
                                   FlowObjectiveService flowObjService,
                                   EventuallyConsistentMap<
-                                  NeighborSetNextObjectiveStoreKey,
-                                  Integer> nsNextObjStore) {
-        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+                                          NeighborSetNextObjectiveStoreKey,
+                                          Integer> nsNextObjStore,
+                                  EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                          Integer> subnetNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService,
+              nsNextObjStore, subnetNextObjStore);
     }
 
     @Override
index 9bbde2f..69a0d86 100644 (file)
@@ -25,10 +25,11 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.util.KryoNamespace;
@@ -74,7 +75,8 @@ public class DefaultGroupHandler {
     //        new HashMap<NeighborSet, Integer>();
     protected EventuallyConsistentMap<
         NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
-    protected Random rand = new Random();
+    protected EventuallyConsistentMap<
+            SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
 
     protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
             .register(URI.class).register(HashSet.class)
@@ -89,8 +91,10 @@ public class DefaultGroupHandler {
                                   LinkService linkService,
                                   FlowObjectiveService flowObjService,
                                   EventuallyConsistentMap<
-                                  NeighborSetNextObjectiveStoreKey,
-                                  Integer> nsNextObjStore) {
+                                          NeighborSetNextObjectiveStoreKey,
+                                          Integer> nsNextObjStore,
+                                  EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                          Integer> subnetNextObjStore) {
         this.deviceId = checkNotNull(deviceId);
         this.appId = checkNotNull(appId);
         this.deviceConfig = checkNotNull(config);
@@ -101,6 +105,7 @@ public class DefaultGroupHandler {
         nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
         this.flowObjectiveService = flowObjService;
         this.nsNextObjStore = nsNextObjStore;
+        this.subnetNextObjStore = subnetNextObjStore;
 
         populateNeighborMaps();
     }
@@ -115,7 +120,8 @@ public class DefaultGroupHandler {
      * @param config interface to retrieve the device properties
      * @param linkService link service object
      * @param flowObjService flow objective service object
-     * @param nsNextObjStore next objective store map
+     * @param nsNextObjStore NeighborSet next objective store map
+     * @param subnetNextObjStore subnet next objective store map
      * @return default group handler type
      */
     public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
@@ -123,18 +129,23 @@ public class DefaultGroupHandler {
                                                          DeviceProperties config,
                                                          LinkService linkService,
                                                          FlowObjectiveService flowObjService,
-                                                         EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
-                                                                 Integer> nsNextObjStore) {
+                                                         EventuallyConsistentMap<
+                                                                 NeighborSetNextObjectiveStoreKey,
+                                                                 Integer> nsNextObjStore,
+                                                         EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                                                 Integer> subnetNextObjStore) {
         if (config.isEdgeDevice(deviceId)) {
             return new DefaultEdgeGroupHandler(deviceId, appId, config,
                                                linkService,
                                                flowObjService,
-                                               nsNextObjStore);
+                                               nsNextObjStore,
+                                               subnetNextObjStore);
         } else {
             return new DefaultTransitGroupHandler(deviceId, appId, config,
                                                   linkService,
                                                   flowObjService,
-                                                  nsNextObjStore);
+                                                  nsNextObjStore,
+                                                  subnetNextObjStore);
         }
     }
 
@@ -322,6 +333,21 @@ public class DefaultGroupHandler {
         return nextId;
     }
 
+    /**
+     * Returns the next objective associated with the subnet.
+     * If there is no next objective for this subnet, this API
+     * would create a next objective and return.
+     *
+     * @param prefix subnet information
+     * @return int if found or -1
+     */
+    public int getSubnetNextObjectiveId(IpPrefix prefix) {
+        Integer nextId = subnetNextObjStore.
+                get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
+
+        return (nextId != null) ? nextId : -1;
+    }
+
     /**
      * Checks if the next objective ID (group) for the neighbor set exists or not.
      *
@@ -486,6 +512,43 @@ public class DefaultGroupHandler {
         }
     }
 
+    public void createGroupsFromSubnetConfig() {
+        Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
+                this.deviceConfig.getSubnetPortsMap(this.deviceId);
+
+        // Construct a broadcast group for each subnet
+        subnetPortMap.forEach((subnet, ports) -> {
+            SubnetNextObjectiveStoreKey key =
+                    new SubnetNextObjectiveStoreKey(deviceId, subnet);
+
+            if (subnetNextObjStore.containsKey(key)) {
+                log.debug("Broadcast group for device {} and subnet {} exists",
+                          deviceId, subnet);
+                return;
+            }
+
+            int nextId = flowObjectiveService.allocateNextId();
+
+            NextObjective.Builder nextObjBuilder = DefaultNextObjective
+                    .builder().withId(nextId)
+                    .withType(NextObjective.Type.BROADCAST).fromApp(appId);
+
+            ports.forEach(port -> {
+                TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+                tBuilder.setOutput(port);
+                nextObjBuilder.addTreatment(tBuilder.build());
+            });
+
+            NextObjective nextObj = nextObjBuilder.add();
+            flowObjectiveService.next(deviceId, nextObj);
+            log.debug("createGroupFromSubnetConfig: Submited "
+                              + "next objective {} in device {}",
+                      nextId, deviceId);
+
+            subnetNextObjStore.put(key, nextId);
+        });
+    }
+
     public GroupKey getGroupKey(Object obj) {
         return new DefaultGroupKey(kryo.build().serialize(obj));
     }
index 3cb73ab..b009e86 100644 (file)
@@ -45,9 +45,12 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
                                   LinkService linkService,
                                   FlowObjectiveService flowObjService,
                                   EventuallyConsistentMap<
-                                  NeighborSetNextObjectiveStoreKey,
-                                  Integer> nsNextObjStore) {
-        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+                                        NeighborSetNextObjectiveStoreKey,
+                                        Integer> nsNextObjStore,
+                                  EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                        Integer> subnetNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService,
+              nsNextObjStore, subnetNextObjStore);
     }
 
     @Override
index 497f525..d28d38d 100644 (file)
 package org.onosproject.segmentrouting.grouphandler;
 
 import java.util.List;
+import java.util.Map;
 
+import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
 
 /**
  * Mechanism through which group handler module retrieves
@@ -33,6 +36,7 @@ public interface DeviceProperties {
      * @return segment id of a device
      */
     int getSegmentId(DeviceId deviceId);
+
     /**
      * Returns the Mac address of a device to be used in group creation.
      *
@@ -40,6 +44,7 @@ public interface DeviceProperties {
      * @return mac address of a device
      */
     MacAddress getDeviceMac(DeviceId deviceId);
+
     /**
      * Indicates whether a device is edge device or transit/core device.
      *
@@ -47,6 +52,7 @@ public interface DeviceProperties {
      * @return boolean
      */
     boolean isEdgeDevice(DeviceId deviceId);
+
     /**
      * Returns all segment IDs to be considered in building auto
      *
@@ -54,4 +60,16 @@ public interface DeviceProperties {
      * @return list of segment IDs
      */
     List<Integer> getAllDeviceSegmentIds();
+
+    /**
+     * Returns subnet-to-ports mapping of given device.
+     *
+     * For each entry of the map
+     * Key: a subnet
+     * Value: a list of ports, which are bound to the subnet
+     *
+     * @param deviceId device identifier
+     * @return a map that contains all subnet-to-ports mapping of given device
+     */
+    Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId);
 }
index e7e8783..e47a662 100644 (file)
@@ -54,7 +54,8 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
      * @param config interface to retrieve the device properties
      * @param linkService link service object
      * @param flowObjService flow objective service object
-     * @param nsNextObjStore next objective store map
+     * @param nsNextObjStore NeighborSet next objective store map
+     * @param subnetNextObjStore subnet next objective store map
      */
     public PolicyGroupHandler(DeviceId deviceId,
                               ApplicationId appId,
@@ -62,8 +63,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
                               LinkService linkService,
                               FlowObjectiveService flowObjService,
                               EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
-                                      Integer> nsNextObjStore) {
-        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+                                      Integer> nsNextObjStore,
+                              EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                      Integer> subnetNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService,
+              nsNextObjStore, subnetNextObjStore);
     }
 
     public PolicyGroupIdentifier createPolicyGroupChain(String id,
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
new file mode 100644 (file)
index 0000000..d6b16c7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.grouphandler;
+
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Class definition of Key for Subnet to NextObjective store.
+ */
+public class SubnetNextObjectiveStoreKey {
+    private final DeviceId deviceId;
+    private final IpPrefix prefix;
+
+    public SubnetNextObjectiveStoreKey(DeviceId deviceId,
+                                       IpPrefix prefix) {
+        this.deviceId = deviceId;
+        this.prefix = prefix;
+    }
+
+    /**
+     * Gets device id in this SubnetNextObjectiveStoreKey.
+     *
+     * @return device id
+     */
+    public DeviceId deviceId() {
+        return this.deviceId;
+    }
+
+    /**
+     * Gets subnet information in this SubnetNextObjectiveStoreKey.
+     *
+     * @return subnet information
+     */
+    public IpPrefix prefix() {
+        return this.prefix;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof SubnetNextObjectiveStoreKey)) {
+            return false;
+        }
+        SubnetNextObjectiveStoreKey that =
+                (SubnetNextObjectiveStoreKey) o;
+        return (Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.prefix, that.prefix));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId, prefix);
+    }
+
+    @Override
+    public String toString() {
+        return "Device: " + deviceId + " Subnet: " + prefix;
+    }
+}
index 204471c..2d1aa0b 100644 (file)
@@ -23,7 +23,7 @@ import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
 
-import java.util.HashSet;
+import java.util.Arrays;
 import java.util.Set;
 
 /**
@@ -44,7 +44,6 @@ public class SetTestAddCommand extends AbstractShellCommand {
     String[] values = null;
 
     Set<String> set;
-    Set<String> toAdd = new HashSet<>();
 
 
     Serializer serializer = Serializer.using(
@@ -68,13 +67,10 @@ public class SetTestAddCommand extends AbstractShellCommand {
             }
         } else if (values.length >= 1) {
             // Add multiple elements to a set
-            for (String value : values) {
-                toAdd.add(value);
-            }
-            if (set.addAll(toAdd)) {
-                print("%s was added to the set %s", toAdd, setName);
+            if (set.addAll(Arrays.asList(values))) {
+                print("%s was added to the set %s", Arrays.asList(values), setName);
             } else {
-                print("%s was already in set %s", toAdd, setName);
+                print("%s was already in set %s", Arrays.asList(values), setName);
             }
         }
     }
index fb36a06..74c52c1 100644 (file)
@@ -24,7 +24,7 @@ import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
 
-import java.util.HashSet;
+import java.util.Arrays;
 import java.util.Set;
 
 /**
@@ -49,7 +49,6 @@ public class SetTestGetCommand extends AbstractShellCommand {
     String[] values = null;
 
     Set<String> set;
-    Set<String> toCheck = new HashSet<>();
     String output = "";
 
     Serializer serializer = Serializer.using(
@@ -95,13 +94,10 @@ public class SetTestGetCommand extends AbstractShellCommand {
             }
         } else if (values.length > 1) {
             //containsAll
-            for (String value : values) {
-                toCheck.add(value);
-            }
-            if (set.containsAll(toCheck)) {
-                print("Set %s contains the the subset %s", setName, toCheck);
+            if (set.containsAll(Arrays.asList(values))) {
+                print("Set %s contains the the subset %s", setName, Arrays.asList(values));
             } else {
-                print("Set %s did not contain the the subset %s", setName, toCheck);
+                print("Set %s did not contain the the subset %s", setName, Arrays.asList(values));
             }
         }
     }
index d1f81e4..1fa073f 100644 (file)
@@ -24,7 +24,7 @@ import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
 
-import java.util.HashSet;
+import java.util.Arrays;
 import java.util.Set;
 
 /**
@@ -54,7 +54,6 @@ public class SetTestRemoveCommand extends AbstractShellCommand {
     String[] values = null;
 
     Set<String> set;
-    Set<String> givenValues = new HashSet<>();
     Serializer serializer = Serializer.using(
             new KryoNamespace.Builder().register(KryoNamespaces.BASIC).build());
 
@@ -79,13 +78,10 @@ public class SetTestRemoveCommand extends AbstractShellCommand {
         }
 
         if (retain) { // Keep only the given values
-            for (String value : values) {
-                givenValues.add(value);
-            }
-            if (set.retainAll(givenValues)) {
-                print("%s was pruned to contain only elements of set %s", setName, givenValues);
+            if (set.retainAll(Arrays.asList(values))) {
+                print("%s was pruned to contain only elements of set %s", setName, Arrays.asList(values));
             } else {
-                print("%s was not changed by retaining only elements of the set %s", setName, givenValues);
+                print("%s was not changed by retaining only elements of the set %s", setName, Arrays.asList(values));
             }
         } else if (values.length == 1) {
             // Remove a single element from the set
@@ -94,15 +90,12 @@ public class SetTestRemoveCommand extends AbstractShellCommand {
             } else {
                 print("[%s] was not in set %s", values[0], setName);
             }
-        } else if (values.length >= 1) {
+        } else if (values.length > 1) {
             // Remove multiple elements from a set
-            for (String value : values) {
-                givenValues.add(value);
-            }
-            if (set.removeAll(givenValues)) {
-                print("%s was removed from the set %s", givenValues, setName);
+            if (set.removeAll(Arrays.asList(values))) {
+                print("%s was removed from the set %s", Arrays.asList(values), setName);
             } else {
-                print("No element of %s was in set %s", givenValues, setName);
+                print("No element of %s was in set %s", Arrays.asList(values), setName);
             }
         }
     }
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java
new file mode 100644 (file)
index 0000000..ff516d7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.virtualbng;
+
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Configuration for a connect point.
+ */
+public class ConnectPointConfiguration {
+
+    private ConnectPoint connectPoint;
+
+    /**
+     * Creats a new connect point from a string representation.
+     *
+     * @param string connect point string
+     */
+    public ConnectPointConfiguration(String string) {
+        connectPoint = ConnectPoint.deviceConnectPoint(string);
+    }
+
+    /**
+     * Creates a new connect point from a string representation.
+     *
+     * @param string connect point string
+     * @return new connect point configuration
+     */
+    public static ConnectPointConfiguration of(String string) {
+        return new ConnectPointConfiguration(string);
+    }
+
+    /**
+     * Gets the connect point.
+     *
+     * @return connect point
+     */
+    public ConnectPoint connectPoint() {
+        return connectPoint;
+    }
+}
index ee2cbea..1841675 100644 (file)
@@ -17,13 +17,15 @@ package org.onosproject.virtualbng;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.Collections;
-import java.util.List;
-
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * Contains the configuration data for virtual BNG that has been read from a
@@ -36,6 +38,7 @@ public final class VbngConfiguration {
     private final MacAddress publicFacingMac;
     private final IpAddress xosIpAddress;
     private final int xosRestPort;
+    private final Map<String, ConnectPointConfiguration> hosts;
 
     /**
      * Default constructor.
@@ -46,6 +49,7 @@ public final class VbngConfiguration {
         publicFacingMac = null;
         xosIpAddress = null;
         xosRestPort = 0;
+        hosts = null;
     }
 
     /**
@@ -57,6 +61,7 @@ public final class VbngConfiguration {
      *        public IP addresses
      * @param xosIpAddress the XOS server IP address
      * @param xosRestPort the port of the XOS server for REST
+     * @param hosts map of hosts
      */
     @JsonCreator
     public VbngConfiguration(@JsonProperty("localPublicIpPrefixes")
@@ -68,12 +73,15 @@ public final class VbngConfiguration {
                              @JsonProperty("xosIpAddress")
                              IpAddress xosIpAddress,
                              @JsonProperty("xosRestPort")
-                             int xosRestPort) {
+                             int xosRestPort,
+                             @JsonProperty("hosts")
+                             Map<String, ConnectPointConfiguration> hosts) {
         localPublicIpPrefixes = prefixes;
         this.nextHopIpAddress = nextHopIpAddress;
         this.publicFacingMac = publicFacingMac;
         this.xosIpAddress = xosIpAddress;
         this.xosRestPort = xosRestPort;
+        this.hosts = hosts;
     }
 
     /**
@@ -120,4 +128,13 @@ public final class VbngConfiguration {
     public int getXosRestPort() {
         return xosRestPort;
     }
+
+    public Map<String, ConnectPoint> getHosts() {
+        return hosts.entrySet()
+                .stream()
+                .collect(Collectors.toMap(
+                        e -> e.getKey(),
+                        e -> e.getValue().connectPoint()
+                ));
+    }
 }
index d27d690..eb83e06 100644 (file)
 package org.onosproject.virtualbng;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -33,9 +23,19 @@ import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onosproject.net.ConnectPoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * Implementation of ConfigurationService which reads virtual BNG
  * configuration from a file.
@@ -63,6 +63,7 @@ public class VbngConfigurationManager implements VbngConfigurationService {
     private MacAddress macOfPublicIpAddresses;
     private IpAddress xosIpAddress;
     private int xosRestPort;
+    private Map<String, ConnectPoint> nodeToPort;
 
     @Activate
     public void activate() {
@@ -104,6 +105,8 @@ public class VbngConfigurationManager implements VbngConfigurationService {
             macOfPublicIpAddresses = config.getPublicFacingMac();
             xosIpAddress = config.getXosIpAddress();
             xosRestPort = config.getXosRestPort();
+            nodeToPort = config.getHosts();
+
 
         } catch (FileNotFoundException e) {
             log.warn("Configuration file not found: {}", configFileName);
@@ -132,6 +135,11 @@ public class VbngConfigurationManager implements VbngConfigurationService {
         return xosRestPort;
     }
 
+    @Override
+    public Map<String, ConnectPoint> getNodeToPort() {
+        return nodeToPort;
+    }
+
     // TODO handle the case: the number of public IP addresses is not enough
     // for 1:1 mapping from public IP to private IP.
     @Override
index ef8698a..68c048f 100644 (file)
  */
 package org.onosproject.virtualbng;
 
-import java.util.Map;
-
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Map;
 
 /**
  * Provides information about the virtual BNG configuration.
@@ -53,6 +54,13 @@ public interface VbngConfigurationService {
      */
     int getXosRestPort();
 
+    /**
+     * Gets the host to port map.
+     *
+     * @return host to port map
+     */
+    Map<String, ConnectPoint> getNodeToPort();
+
     /**
      * Evaluates whether an IP address is an assigned public IP address.
      *
index 5e82b7e..e03b25e 100644 (file)
  */
 package org.onosproject.virtualbng;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.Maps;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -42,7 +33,6 @@ import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
-import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
@@ -56,6 +46,13 @@ import org.onosproject.net.intent.PointToPointIntent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * This is a virtual Broadband Network Gateway (BNG) application. It mainly
  * has 3 functions:
@@ -111,9 +108,8 @@ public class VbngManager implements VbngService {
         p2pIntentsToHost = new ConcurrentHashMap<>();
         privateIpAddressMap = new ConcurrentHashMap<>();
 
-        setupMap();
-
         nextHopIpAddress = vbngConfigurationService.getNextHopIpAddress();
+        nodeToPort = vbngConfigurationService.getNodeToPort();
         hostListener = new InternalHostListener();
         hostService.addListener(hostListener);
 
@@ -136,10 +132,16 @@ public class VbngManager implements VbngService {
      */
     private void statusRecovery() {
         log.info("vBNG starts to recover from XOS record......");
-        RestClient restClient =
-                new RestClient(vbngConfigurationService.getXosIpAddress(),
-                               vbngConfigurationService.getXosRestPort());
-        ObjectNode map = restClient.getRest();
+        ObjectNode map;
+        try {
+            RestClient restClient =
+                    new RestClient(vbngConfigurationService.getXosIpAddress(),
+                            vbngConfigurationService.getXosRestPort());
+            map = restClient.getRest();
+        } catch (Exception e) {
+            log.error("Could not contact XOS", e);
+            return;
+        }
         if (map == null) {
             log.info("Stop to recover vBNG status due to the vBNG map "
                     + "is null!");
@@ -167,21 +169,6 @@ public class VbngManager implements VbngService {
         }
     }
 
-    /**
-     * Sets up mapping from hostname to connect point.
-     */
-    private void setupMap() {
-        nodeToPort = Maps.newHashMap();
-
-        nodeToPort.put("cordcompute01.onlab.us",
-                       new ConnectPoint(FABRIC_DEVICE_ID,
-                                        PortNumber.portNumber(48)));
-
-        nodeToPort.put("cordcompute02.onlab.us",
-                       new ConnectPoint(FABRIC_DEVICE_ID,
-                                        PortNumber.portNumber(47)));
-    }
-
     /**
      * Creates a new vBNG.
      *
index c2cfe2b..e91b0c9 100644 (file)
         <module>vtnweb</module>
         <module>app</module>
        </modules>
+       <dependencies>
+           <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava-testlib</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java
new file mode 100644 (file)
index 0000000..a2748f5
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.sfc;
+
+import org.onosproject.vtnrsc.PortChain;
+
+/**
+ * SFC application that applies flows to the device.
+ */
+public interface SfcService {
+    /**
+     * Applies flow classification to OVS.
+     *
+     * @param portChain Port-Chain.
+     */
+    void InstallFlowClassification(PortChain portChain);
+
+
+    /**
+     * Remove flow classification from OVS.
+     *
+     * @param portChain Port-Chain.
+     */
+    void UnInstallFlowClassification(PortChain portChain);
+
+    /**
+     * Applies Service Function chain to OVS.
+     *
+     * @param portChain Port-Chain.
+     */
+    void InstallServiceFunctionChain(PortChain portChain);
+
+    /**
+     * Remove Service Function chain from OVS.
+     *
+     * @param portChain Port-Chain.
+     */
+    void UnInstallServiceFunctionChain(PortChain portChain);
+}
diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java
new file mode 100644 (file)
index 0000000..1872295
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.sfc.impl;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.vtnrsc.sfc.PortChain;
+import org.slf4j.Logger;
+
+/**
+ * Provides implementation of SFC Service.
+ */
+@Component(immediate = true)
+@Service
+public class SfcManager implements SfcService {
+
+    private final Logger log = getLogger(SfcManager.class);
+
+    @Activate
+    public void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public void InstallFlowClassification(PortChain portChain) {
+        log.debug("InstallFlowClassification");
+        //TODO: Installation of flow classification into OVS.
+    }
+
+    @Override
+    public void UnInstallFlowClassification(PortChain portChain) {
+        log.debug("UnInstallFlowClassification");
+        //TODO: Un-installation flow classification from OVS
+    }
+
+    @Override
+    public void InstallServiceFunctionChain(PortChain portChain) {
+        log.debug("InstallServiceFunctionChain");
+        //TODO: Installation of Service Function chain into OVS.
+    }
+
+    @Override
+    public void UnInstallServiceFunctionChain(PortChain portChain) {
+        log.debug("UnInstallServiceFunctionChain");
+        //TODO: Un-installation of Service Function chain from OVS.
+    }
+}
diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java
new file mode 100644 (file)
index 0000000..0dba868
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SFC Service manager for interacting with SFC.
+ */
+package org.onosproject.sfc.impl;
diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java
new file mode 100644 (file)
index 0000000..1dcb992
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Service for interacting with SFC.
+ */
+package org.onosproject.sfc;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java
new file mode 100644 (file)
index 0000000..39df2cf
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import java.util.Objects;
+import org.onlab.packet.IpPrefix;
+
+import com.google.common.base.MoreObjects;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Provides Default flow classifier.
+ */
+public final class DefaultFlowClassifier implements FlowClassifier {
+
+    private final FlowClassifierId flowClassifierId;
+    private final TenantId tenantId;
+    private final String name;
+    private final String description;
+    private final String etherType;
+    private final String protocol;
+    private final int minSrcPortRange;
+    private final int maxSrcPortRange;
+    private final int minDstPortRange;
+    private final int maxDstPortRange;
+    private final IpPrefix srcIpPrefix;
+    private final IpPrefix dstIpPrefix;
+    private final VirtualPortId srcPort;
+    private final VirtualPortId dstPort;
+    private static final int NULL_PORT = 0;
+    private static final String FLOW_CLASSIFIER_ID_NOT_NULL = "FlowClassifier id can not be null.";
+    private static final String TENANT_ID_NOT_NULL = "Tenant id can not be null.";
+
+    /**
+     * Constructor to create default flow classifier.
+     *
+     * @param flowClassifierId      flow classifier Id
+     * @param tenantId              Tenant ID
+     * @param name                  flow classifier name
+     * @param description           flow classifier description
+     * @param etherType             etherType
+     * @param protocol              IP protocol
+     * @param minSrcPortRange       Minimum Source port range
+     * @param maxSrcPortRange       Maximum Source port range
+     * @param minDstPortRange       Minimum destination port range
+     * @param maxDstPortRange       Maximum destination port range
+     * @param srcIpPrefix           Source IP prefix
+     * @param dstIpPrefix           destination IP prefix
+     * @param srcPort               Source VirtualPort
+     * @param dstPort               destination VirtualPort
+     */
+    private DefaultFlowClassifier(FlowClassifierId flowClassifierId, TenantId tenantId, String name,
+            String description, String etherType, String protocol, int minSrcPortRange, int maxSrcPortRange,
+            int minDstPortRange, int maxDstPortRange, IpPrefix srcIpPrefix, IpPrefix dstIpPrefix,
+            VirtualPortId srcPort, VirtualPortId dstPort) {
+        this.flowClassifierId = flowClassifierId;
+        this.tenantId = tenantId;
+        this.name = name;
+        this.description = description;
+        this.etherType = etherType;
+        this.protocol = protocol;
+        this.minSrcPortRange = minSrcPortRange;
+        this.maxSrcPortRange = maxSrcPortRange;
+        this.minDstPortRange = minDstPortRange;
+        this.maxDstPortRange = maxDstPortRange;
+        this.srcIpPrefix = srcIpPrefix;
+        this.dstIpPrefix = dstIpPrefix;
+        this.srcPort = srcPort;
+        this.dstPort = dstPort;
+    }
+
+    @Override
+    public FlowClassifierId flowClassifierId() {
+        return flowClassifierId;
+    }
+
+    @Override
+    public TenantId tenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public String description() {
+        return description;
+    }
+
+    @Override
+    public String etherType() {
+        return etherType;
+    }
+
+    @Override
+    public String protocol() {
+        return protocol;
+    }
+
+    @Override
+    public int minSrcPortRange() {
+        return minSrcPortRange;
+    }
+
+    @Override
+    public int maxSrcPortRange() {
+        return maxSrcPortRange;
+    }
+
+    @Override
+    public int minDstPortRange() {
+        return minDstPortRange;
+    }
+
+    @Override
+    public int maxDstPortRange() {
+        return maxDstPortRange;
+    }
+
+    @Override
+    public IpPrefix srcIpPrefix() {
+        return srcIpPrefix;
+    }
+
+    @Override
+    public IpPrefix dstIpPrefix() {
+        return dstIpPrefix;
+    }
+
+    @Override
+    public VirtualPortId srcPort() {
+        return srcPort;
+    }
+
+    @Override
+    public VirtualPortId dstPort() {
+        return dstPort;
+    }
+
+    /**
+     * Builder class for constructing Flow classifier.
+     */
+    public static class Builder implements FlowClassifier.Builder {
+
+        private FlowClassifierId flowClassifierId;
+        private TenantId tenantId;
+        private String name;
+        private boolean isFlowClassifierNameSet = false;
+        private String description;
+        private boolean isFlowClassifierDescriptionSet = false;
+        private String etherType;
+        private boolean isEtherTypeSet = false;
+        private String protocol;
+        private boolean isProtocolSet = false;
+        private int minSrcPortRange;
+        private boolean isMinSrcPortRangeSet = false;
+        private int maxSrcPortRange;
+        private boolean isMaxSrcPortRangeSet = false;
+        private int minDstPortRange;
+        private boolean isMinDstPortRangeSet = false;
+        private int maxDstPortRange;
+        private boolean isMaxDstPortRangeSet = false;
+        private IpPrefix srcIpPrefix;
+        private boolean isSrcIpPrefixSet = false;
+        private IpPrefix dstIpPrefix;
+        private boolean isDstIpPrefixSet = false;
+        private VirtualPortId srcPort;
+        private boolean isSrcPortSet = false;
+        private VirtualPortId dstPort;
+        private boolean isDstPortSet = false;
+
+        @Override
+        public FlowClassifier build() {
+
+            checkNotNull(flowClassifierId, FLOW_CLASSIFIER_ID_NOT_NULL);
+            checkNotNull(tenantId, TENANT_ID_NOT_NULL);
+            String name = null;
+            String description = null;
+            String etherType = null;
+            String protocol = null;
+            int minSrcPortRange = NULL_PORT;
+            int maxSrcPortRange = NULL_PORT;
+            int minDstPortRange = NULL_PORT;
+            int maxDstPortRange = NULL_PORT;
+            IpPrefix srcIpPrefix = null;
+            IpPrefix dstIpPrefix = null;
+            VirtualPortId srcPort = null;
+            VirtualPortId dstPort = null;
+
+            if (isFlowClassifierNameSet) {
+                name = this.name;
+            }
+            if (isFlowClassifierDescriptionSet) {
+                description = this.description;
+            }
+            if (isEtherTypeSet) {
+                etherType = this.etherType;
+            }
+            if (isProtocolSet) {
+                protocol = this.protocol;
+            }
+            if (isMinSrcPortRangeSet) {
+                minSrcPortRange = this.minSrcPortRange;
+            }
+            if (isMaxSrcPortRangeSet) {
+                maxSrcPortRange = this.maxSrcPortRange;
+            }
+            if (isMinDstPortRangeSet) {
+                minDstPortRange = this.minDstPortRange;
+            }
+            if (isMaxDstPortRangeSet) {
+                maxDstPortRange = this.maxDstPortRange;
+            }
+            if (isSrcIpPrefixSet) {
+                srcIpPrefix = this.srcIpPrefix;
+            }
+            if (isDstIpPrefixSet) {
+                dstIpPrefix = this.dstIpPrefix;
+            }
+            if (isSrcPortSet) {
+                srcPort = this.srcPort;
+            }
+            if (isDstPortSet) {
+                dstPort = this.dstPort;
+            }
+
+            return new DefaultFlowClassifier(flowClassifierId, tenantId, name, description, etherType, protocol,
+                    minSrcPortRange, maxSrcPortRange, minDstPortRange, maxDstPortRange, srcIpPrefix, dstIpPrefix,
+                    srcPort, dstPort);
+        }
+
+        @Override
+        public Builder setFlowClassifierId(FlowClassifierId flowClassifierId) {
+            this.flowClassifierId = flowClassifierId;
+            return this;
+        }
+
+        @Override
+        public Builder setTenantId(TenantId tenantId) {
+            this.tenantId = tenantId;
+            return this;
+        }
+
+        @Override
+        public Builder setName(String name) {
+            this.name = name;
+            this.isFlowClassifierNameSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setDescription(String description) {
+            this.description = description;
+            this.isFlowClassifierDescriptionSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setEtherType(String etherType) {
+            this.etherType = etherType;
+            this.isEtherTypeSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setProtocol(String protocol) {
+            this.protocol = protocol;
+            this.isProtocolSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setMinSrcPortRange(int minSrcPortRange) {
+            this.minSrcPortRange = minSrcPortRange;
+            this.isMinSrcPortRangeSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setMaxSrcPortRange(int maxSrcPortRange) {
+            this.maxSrcPortRange = maxSrcPortRange;
+            this.isMaxSrcPortRangeSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setMinDstPortRange(int minDstPortRange) {
+            this.minDstPortRange = minDstPortRange;
+            this.isMinDstPortRangeSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setMaxDstPortRange(int maxDstPortRange) {
+            this.maxDstPortRange = maxDstPortRange;
+            this.isMaxDstPortRangeSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setSrcIpPrefix(IpPrefix srcIpPrefix) {
+            this.srcIpPrefix = srcIpPrefix;
+            this.isSrcIpPrefixSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setDstIpPrefix(IpPrefix dstIpPrefix) {
+            this.dstIpPrefix = dstIpPrefix;
+            this.isDstIpPrefixSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setSrcPort(VirtualPortId srcPort) {
+            this.srcPort = srcPort;
+            this.isSrcPortSet = true;
+            return this;
+        }
+
+        @Override
+        public Builder setDstPort(VirtualPortId dstPort) {
+            this.dstPort = dstPort;
+            this.isDstPortSet = true;
+            return this;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(flowClassifierId, tenantId, name, description, etherType, protocol, minSrcPortRange,
+                maxSrcPortRange, minDstPortRange, maxDstPortRange, srcIpPrefix, dstIpPrefix, srcPort, dstPort);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultFlowClassifier) {
+            DefaultFlowClassifier other = (DefaultFlowClassifier) obj;
+            return Objects.equals(this.flowClassifierId, other.flowClassifierId)
+                    && Objects.equals(this.tenantId, other.tenantId)
+                    && Objects.equals(this.name, other.name)
+                    && Objects.equals(this.description, other.description)
+                    && Objects.equals(this.etherType, other.etherType)
+                    && Objects.equals(this.protocol, other.protocol)
+                    && Objects.equals(this.minSrcPortRange, other.minSrcPortRange)
+                    && Objects.equals(this.maxSrcPortRange, other.maxSrcPortRange)
+                    && Objects.equals(this.minDstPortRange, other.minDstPortRange)
+                    && Objects.equals(this.maxDstPortRange, other.maxDstPortRange)
+                    && Objects.equals(this.srcIpPrefix, other.srcIpPrefix)
+                    && Objects.equals(this.dstIpPrefix, other.dstIpPrefix)
+                    && Objects.equals(this.srcPort, other.srcPort)
+                    && Objects.equals(this.dstPort, other.dstPort);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean exactMatch(FlowClassifier flowClassifier) {
+        return this.equals(flowClassifier)
+                && Objects.equals(this.flowClassifierId, flowClassifier.flowClassifierId())
+                && Objects.equals(this.tenantId, flowClassifier.tenantId())
+                && Objects.equals(this.name, flowClassifier.name())
+                && Objects.equals(this.description, flowClassifier.description())
+                && Objects.equals(this.etherType, flowClassifier.etherType())
+                && Objects.equals(this.protocol, flowClassifier.protocol())
+                && Objects.equals(this.minSrcPortRange, flowClassifier.minSrcPortRange())
+                && Objects.equals(this.maxSrcPortRange, flowClassifier.maxSrcPortRange())
+                && Objects.equals(this.minDstPortRange, flowClassifier.minDstPortRange())
+                && Objects.equals(this.maxDstPortRange, flowClassifier.maxDstPortRange())
+                && Objects.equals(this.srcIpPrefix, flowClassifier.srcIpPrefix())
+                && Objects.equals(this.dstIpPrefix, flowClassifier.dstIpPrefix())
+                && Objects.equals(this.srcPort, flowClassifier.srcPort())
+                && Objects.equals(this.dstPort, flowClassifier.dstPort());
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("FlowClassifierId", flowClassifierId)
+                .add("TenantId", tenantId)
+                .add("Name", name)
+                .add("Description", description)
+                .add("String", etherType)
+                .add("Protocol", protocol)
+                .add("MinSrcPortRange", minSrcPortRange)
+                .add("MaxSrcPortRange", maxSrcPortRange)
+                .add("MinDstPortRange", minDstPortRange)
+                .add("MaxDstPortRange", maxDstPortRange)
+                .add("SrcIpPrefix", srcIpPrefix)
+                .add("DstIpPrefix", dstIpPrefix)
+                .add("SrcPort", srcPort)
+                .add("DstPort", dstPort)
+                .toString();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java
new file mode 100644 (file)
index 0000000..89b94b3
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Implementation of port chain.
+ */
+public final class DefaultPortChain implements PortChain {
+
+    private final PortChainId portChainId;
+    private final TenantId tenantId;
+    private final String name;
+    private final String description;
+    private final List<PortPairGroupId> portPairGroupList;
+    private final List<FlowClassifierId> flowClassifierList;
+
+    /**
+     * Default constructor to create port chain.
+     *
+     * @param portChainId port chain id
+     * @param tenantId tenant id
+     * @param name name of port chain
+     * @param description description of port chain
+     * @param portPairGroupList port pair group list
+     * @param flowClassifierList flow classifier list
+     */
+    private DefaultPortChain(PortChainId portChainId, TenantId tenantId,
+                             String name, String description,
+                             List<PortPairGroupId> portPairGroupList,
+                             List<FlowClassifierId> flowClassifierList) {
+
+        this.portChainId = portChainId;
+        this.tenantId = tenantId;
+        this.name = name;
+        this.description = description;
+        this.portPairGroupList = portPairGroupList;
+        this.flowClassifierList = flowClassifierList;
+    }
+
+    @Override
+    public PortChainId portChainId() {
+        return portChainId;
+    }
+
+    @Override
+    public TenantId tenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public String description() {
+        return description;
+    }
+
+    @Override
+    public List<PortPairGroupId> portPairGroups() {
+        return  ImmutableList.copyOf(portPairGroupList);
+    }
+
+    @Override
+    public List<FlowClassifierId> flowClassifiers() {
+        return ImmutableList.copyOf(flowClassifierList);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(portChainId, tenantId, name, description,
+                            portPairGroupList, flowClassifierList);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultPortChain) {
+            DefaultPortChain that = (DefaultPortChain) obj;
+            return Objects.equals(portChainId, that.portChainId) &&
+                    Objects.equals(tenantId, that.tenantId) &&
+                    Objects.equals(name, that.name) &&
+                    Objects.equals(description, that.description) &&
+                    Objects.equals(portPairGroupList, that.portPairGroupList) &&
+                    Objects.equals(flowClassifierList, that.flowClassifierList);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean exactMatch(PortChain portChain) {
+        return this.equals(portChain) &&
+                Objects.equals(this.portChainId, portChain.portChainId()) &&
+                Objects.equals(this.tenantId, portChain.tenantId());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("id", portChainId.toString())
+                .add("tenantId", tenantId.toString())
+                .add("name", name)
+                .add("description", description)
+                .add("portPairGroupList", portPairGroupList)
+                .add("flowClassifier", flowClassifierList)
+                .toString();
+    }
+
+    /**
+     * To create an instance of the builder.
+     *
+     * @return instance of builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder class for Port chain.
+     */
+    public static final class Builder implements PortChain.Builder {
+
+        private PortChainId portChainId;
+        private TenantId tenantId;
+        private String name;
+        private String description;
+        private List<PortPairGroupId> portPairGroupList;
+        private List<FlowClassifierId> flowClassifierList;
+
+        @Override
+        public Builder setId(PortChainId portChainId) {
+            this.portChainId = portChainId;
+            return this;
+        }
+
+        @Override
+        public Builder setTenantId(TenantId tenantId) {
+            this.tenantId = tenantId;
+            return this;
+        }
+
+        @Override
+        public Builder setName(String name) {
+            this.name = name;
+            return this;
+        }
+
+        @Override
+        public Builder setDescription(String description) {
+            this.description = description;
+            return this;
+        }
+
+        @Override
+        public Builder setPortPairGroups(List<PortPairGroupId> portPairGroups) {
+            this.portPairGroupList = portPairGroups;
+            return this;
+        }
+
+        @Override
+        public Builder setFlowClassifiers(List<FlowClassifierId> flowClassifiers) {
+            this.flowClassifierList = flowClassifiers;
+            return this;
+        }
+
+        @Override
+        public PortChain build() {
+
+            checkNotNull(portChainId, "Port chain id cannot be null");
+            checkNotNull(tenantId, "Tenant id cannot be null");
+            checkNotNull(portPairGroupList, "Port pair groups cannot be null");
+
+            return new DefaultPortChain(portChainId, tenantId, name, description,
+                                        portPairGroupList, flowClassifierList);
+        }
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java
new file mode 100644 (file)
index 0000000..4b3b7cf
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+/**
+ * Implementation of port pair.
+ */
+public final class DefaultPortPair implements PortPair {
+
+    private final PortPairId portPairId;
+    private final TenantId tenantId;
+    private final String name;
+    private final String description;
+    private final String ingress;
+    private final String egress;
+
+    /**
+     * Default constructor to create Port Pair.
+     *
+     * @param portPairId port pair id
+     * @param tenantId tenant id
+     * @param name name of port pair
+     * @param description description of port pair
+     * @param ingress ingress port
+     * @param egress egress port
+     */
+    private DefaultPortPair(PortPairId portPairId, TenantId tenantId,
+                            String name, String description,
+                            String ingress, String egress) {
+
+        this.portPairId = portPairId;
+        this.tenantId = tenantId;
+        this.name = name;
+        this.description = description;
+        this.ingress = ingress;
+        this.egress = egress;
+    }
+
+    @Override
+    public PortPairId portPairId() {
+        return portPairId;
+    }
+
+    @Override
+    public TenantId tenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public String description() {
+        return description;
+    }
+
+    @Override
+    public String ingress() {
+        return ingress;
+    }
+
+    @Override
+    public String egress() {
+        return egress;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(portPairId, tenantId, name, description,
+                            ingress, egress);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultPortPair) {
+            DefaultPortPair that = (DefaultPortPair) obj;
+            return Objects.equals(portPairId, that.portPairId) &&
+                    Objects.equals(tenantId, that.tenantId) &&
+                    Objects.equals(name, that.name) &&
+                    Objects.equals(description, that.description) &&
+                    Objects.equals(ingress, that.ingress) &&
+                    Objects.equals(egress, that.egress);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean exactMatch(PortPair portPair) {
+        return this.equals(portPair) &&
+                Objects.equals(this.portPairId, portPair.portPairId()) &&
+                Objects.equals(this.tenantId, portPair.tenantId());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("id", portPairId.toString())
+                .add("tenantId", tenantId.tenantId())
+                .add("name", name)
+                .add("description", description)
+                .add("ingress", ingress)
+                .add("egress", egress)
+                .toString();
+    }
+
+    /**
+     * To create an instance of the builder.
+     *
+     * @return instance of builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder class for Port pair.
+     */
+    public static final class Builder implements PortPair.Builder {
+
+        private PortPairId portPairId;
+        private TenantId tenantId;
+        private String name;
+        private String description;
+        private String ingress;
+        private String egress;
+
+        @Override
+        public Builder setId(PortPairId portPairId) {
+            this.portPairId = portPairId;
+            return this;
+        }
+
+        @Override
+        public Builder setTenantId(TenantId tenantId) {
+            this.tenantId = tenantId;
+            return this;
+        }
+
+        @Override
+        public Builder setName(String name) {
+            this.name = name;
+            return this;
+        }
+
+        @Override
+        public Builder setDescription(String description) {
+            this.description = description;
+            return this;
+        }
+
+        @Override
+        public Builder setIngress(String ingress) {
+            this.ingress = ingress;
+            return this;
+        }
+
+        @Override
+        public Builder setEgress(String egress) {
+            this.egress = egress;
+            return this;
+        }
+
+        @Override
+        public PortPair build() {
+
+            checkNotNull(portPairId, "Port pair id cannot be null");
+            checkNotNull(tenantId, "Tenant id cannot be null");
+            checkNotNull(ingress, "Ingress of a port pair cannot be null");
+            checkNotNull(egress, "Egress of a port pair cannot be null");
+
+            return new DefaultPortPair(portPairId, tenantId, name, description,
+                                       ingress, egress);
+        }
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java
new file mode 100644 (file)
index 0000000..877cc6c
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Implementation of port pair group.
+ */
+public final class DefaultPortPairGroup implements PortPairGroup {
+
+    private final PortPairGroupId portPairGroupId;
+    private final TenantId tenantId;
+    private final String name;
+    private final String description;
+    private final List<PortPairId> portPairList;
+
+    /**
+     * Default constructor to create Port Pair Group.
+     *
+     * @param portPairGroupId port pair group id
+     * @param tenantId tenant id
+     * @param name name of port pair group
+     * @param description description of port pair group
+     * @param portPairList list of port pairs
+     */
+    private DefaultPortPairGroup(PortPairGroupId portPairGroupId, TenantId tenantId,
+                                 String name, String description,
+                                 List<PortPairId> portPairList) {
+
+        this.portPairGroupId = portPairGroupId;
+        this.tenantId = tenantId;
+        this.name = name;
+        this.description = description;
+        this.portPairList = portPairList;
+    }
+
+    @Override
+    public PortPairGroupId portPairGroupId() {
+        return portPairGroupId;
+    }
+
+    @Override
+    public TenantId tenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public String description() {
+        return description;
+    }
+
+    @Override
+    public List<PortPairId> portPairs() {
+        return ImmutableList.copyOf(portPairList);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(portPairGroupId, tenantId, name, description,
+                            portPairList);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultPortPairGroup) {
+            DefaultPortPairGroup that = (DefaultPortPairGroup) obj;
+            return Objects.equals(portPairGroupId, that.portPairGroupId) &&
+                    Objects.equals(tenantId, that.tenantId) &&
+                    Objects.equals(name, that.name) &&
+                    Objects.equals(description, that.description) &&
+                    Objects.equals(portPairList, that.portPairList);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean exactMatch(PortPairGroup portPairGroup) {
+        return this.equals(portPairGroup) &&
+                Objects.equals(this.portPairGroupId, portPairGroup.portPairGroupId()) &&
+                Objects.equals(this.tenantId, portPairGroup.tenantId());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("id", portPairGroupId.toString())
+                .add("tenantId", tenantId.toString())
+                .add("name", name)
+                .add("description", description)
+                .add("portPairGroupList", portPairList)
+                .toString();
+    }
+
+    /**
+     * To create an instance of the builder.
+     *
+     * @return instance of builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder class for Port pair group.
+     */
+    public static final class Builder implements PortPairGroup.Builder {
+
+        private PortPairGroupId portPairGroupId;
+        private TenantId tenantId;
+        private String name;
+        private String description;
+        private List<PortPairId> portPairList;
+
+        @Override
+        public Builder setId(PortPairGroupId portPairGroupId) {
+            this.portPairGroupId = portPairGroupId;
+            return this;
+        }
+
+        @Override
+        public Builder setTenantId(TenantId tenantId) {
+            this.tenantId = tenantId;
+            return this;
+        }
+
+        @Override
+        public Builder setName(String name) {
+            this.name = name;
+            return this;
+        }
+
+        @Override
+        public Builder setDescription(String description) {
+            this.description = description;
+            return this;
+        }
+
+        @Override
+        public Builder setPortPairs(List<PortPairId> portPairs) {
+            this.portPairList = portPairs;
+            return this;
+        }
+
+        @Override
+        public PortPairGroup build() {
+
+            checkNotNull(portPairGroupId, "Port pair group id cannot be null");
+            checkNotNull(tenantId, "Tenant id cannot be null");
+            checkNotNull(portPairList, "Port pairs cannot be null");
+
+            return new DefaultPortPairGroup(portPairGroupId, tenantId, name, description,
+                                            portPairList);
+        }
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java
new file mode 100644 (file)
index 0000000..7b4108d
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Abstraction of an entity which provides flow classifier for service function chain.
+ * FlowClassifier classify the traffic based on the criteria defined in the request.
+ * The classification can be based on port range or source and destination IP address or
+ * other flow classifier elements.
+ */
+public interface FlowClassifier {
+
+    /**
+     * Returns flow classifier ID.
+     *
+     * @return flow classifier id
+     */
+    FlowClassifierId flowClassifierId();
+
+    /**
+     * Returns Tenant ID.
+     *
+     * @return tenant Id
+     */
+    TenantId tenantId();
+
+    /**
+     * Returns flow classifier name.
+     *
+     * @return flow classifier name
+     */
+    String name();
+
+    /**
+     * Returns flow classifier description.
+     *
+     * @return flow classifier description
+     */
+    String description();
+
+    /**
+     * Returns EtherType.
+     *
+     * @return EtherType
+     */
+    String etherType();
+
+    /**
+     * Returns IP Protocol.
+     *
+     * @return IP protocol
+     */
+    String protocol();
+
+    /**
+     * Returns minimum source port range.
+     *
+     * @return minimum source port range
+     */
+    int minSrcPortRange();
+
+    /**
+     * Returns maximum source port range.
+     *
+     * @return maximum source port range
+     */
+    int maxSrcPortRange();
+
+    /**
+     * Returns minimum destination port range.
+     *
+     * @return minimum destination port range
+     */
+    int minDstPortRange();
+
+    /**
+     * Returns maximum destination port range.
+     *
+     * @return maximum destination port range.
+     */
+    int maxDstPortRange();
+
+    /**
+     * Returns Source IP prefix.
+     *
+     * @return Source IP prefix
+     */
+    IpPrefix srcIpPrefix();
+
+    /**
+     * Returns Destination IP prefix.
+     *
+     * @return Destination IP prefix
+     */
+    IpPrefix dstIpPrefix();
+
+    /**
+     * Returns Source virtual port.
+     *
+     * @return Source virtual port
+     */
+    VirtualPortId srcPort();
+
+    /**
+     * Returns Destination virtual port.
+     *
+     * @return Destination virtual port
+     */
+    VirtualPortId dstPort();
+
+    /**
+     * Returns whether this Flow classifier is an exact match to the
+     * Flow classifier given in the argument.
+     *
+     * @param flowClassifier other flowClassifier to match against
+     * @return true if the flowClassifiers are an exact match, otherwise false
+     */
+    boolean exactMatch(FlowClassifier flowClassifier);
+
+    /**
+     * Builder for flow Classifier.
+     */
+    interface Builder {
+
+        /**
+         * Returns Flow Classifier.
+         *
+         * @return flow classifier.
+         */
+        FlowClassifier build();
+
+        /**
+         * Sets Flow Classifier ID.
+         *
+         * @param flowClassifierId flow classifier id.
+         * @return Builder object by setting flow classifier Id.
+         */
+        Builder setFlowClassifierId(FlowClassifierId flowClassifierId);
+
+        /**
+         * Sets Tenant ID.
+         *
+         * @param tenantId tenant id.
+         * @return Builder object by setting Tenant ID.
+         */
+        Builder setTenantId(TenantId tenantId);
+
+        /**
+         * Sets Flow classifier name.
+         *
+         * @param name flow classifier name
+         * @return builder object by setting flow classifier name
+         */
+        Builder setName(String name);
+
+        /**
+         * Sets flow classifier description.
+         *
+         * @param description flow classifier description
+         * @return flow classifier description
+         */
+        Builder setDescription(String description);
+
+        /**
+         * Sets EtherType.
+         *
+         * @param etherType EtherType
+         * @return EtherType
+         */
+        Builder setEtherType(String etherType);
+
+        /**
+         * Sets IP protocol.
+         *
+         * @param protocol IP protocol
+         * @return builder object by setting IP protocol
+         */
+        Builder setProtocol(String protocol);
+
+        /**
+         * Set minimum source port range.
+         *
+         * @param minRange minimum source port range
+         * @return builder object by setting minimum source port range
+         */
+        Builder setMinSrcPortRange(int minRange);
+
+        /**
+         * Sets maximum source port range.
+         *
+         * @param maxRange maximum source port range
+         * @return builder object by setting maximum source port range
+         */
+        Builder setMaxSrcPortRange(int maxRange);
+
+        /**
+         * Sets minimum destination port range.
+         *
+         * @param minRange minimum destination port range
+         * @return builder object by setting minimum destination port range
+         */
+        Builder setMinDstPortRange(int minRange);
+
+        /**
+         * Sets maximum destination port range.
+         *
+         * @param maxRange maximum destination port range.
+         * @return builder object by setting maximum destination port range.
+         */
+        Builder setMaxDstPortRange(int maxRange);
+
+        /**
+         * Sets Source IP prefix.
+         *
+         * @param srcIpPrefix Source IP prefix
+         * @return builder object by setting Source IP prefix
+         */
+        Builder setSrcIpPrefix(IpPrefix srcIpPrefix);
+
+        /**
+         * Sets Destination IP prefix.
+         *
+         * @param dstIpPrefix Destination IP prefix
+         * @return builder object by setting Destination IP prefix
+         */
+        Builder setDstIpPrefix(IpPrefix dstIpPrefix);
+
+        /**
+         * Sets Source virtual port.
+         *
+         * @param srcPort Source virtual port
+         * @return builder object by setting Source virtual port
+         */
+        Builder setSrcPort(VirtualPortId srcPort);
+
+        /**
+         * Sets Destination virtual port.
+         *
+         * @param dstPort Destination virtual port
+         * @return builder object by setting Destination virtual port
+         */
+        Builder setDstPort(VirtualPortId dstPort);
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java
new file mode 100644 (file)
index 0000000..b789abe
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.UUID;
+import java.util.Objects;
+
+/**
+ * Flow classification identifier.
+ */
+public final class FlowClassifierId {
+
+    private final UUID flowClassifierId;
+
+    /**
+     * Constructor to create flow classifier id.
+     *
+     * @param flowClassifierId flow classifier id.
+     */
+    private FlowClassifierId(final UUID flowClassifierId) {
+        this.flowClassifierId = flowClassifierId;
+    }
+
+    /**
+     * Returns new flow classifier id.
+     *
+     * @param flowClassifierId flow classifier id
+     * @return new flow classifier id
+     */
+    public static FlowClassifierId flowClassifierId(final UUID flowClassifierId) {
+        return new FlowClassifierId(flowClassifierId);
+    }
+
+    /**
+     * Returns new flow classifier id.
+     *
+     * @param flowClassifierId flow classifier id
+     * @return new flow classifier id
+     */
+    public static FlowClassifierId flowClassifierId(final String flowClassifierId) {
+        return new FlowClassifierId(UUID.fromString(flowClassifierId));
+    }
+
+    /**
+     * Returns the value of flow classifier id.
+     *
+     * @return flow classifier id.
+     */
+    public UUID value() {
+        return flowClassifierId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.flowClassifierId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof FlowClassifierId) {
+            final FlowClassifierId other = (FlowClassifierId) obj;
+            return Objects.equals(this.flowClassifierId, other.flowClassifierId);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("FlowClassifierId", flowClassifierId)
+                .toString();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java
new file mode 100644 (file)
index 0000000..d147eaa
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import java.util.List;
+
+/**
+ * Abstraction of an entity providing Port Chain information.
+ * A Port Chain (Service Function Path) consists of
+ * a set of Neutron ports, to define the sequence of service functions
+ * a set of flow classifiers, to specify the classified traffic flows to enter the chain
+ */
+public interface PortChain {
+
+    /**
+     * Returns the ID of this port chain.
+     *
+     * @return the port chain id
+     */
+    PortChainId portChainId();
+
+    /**
+     * Returns the tenant id of this port chain.
+     *
+     * @return the tenant id
+     */
+    TenantId tenantId();
+
+    /**
+     * Returns the name of this port chain.
+     *
+     * @return name of port chain
+     */
+    String name();
+
+    /**
+     * Returns the description of this port chain.
+     *
+     * @return description of port chain
+     */
+    String description();
+
+    /**
+     * Returns the list of port pair groups associated with
+     * this port chain.
+     *
+     * @return list of port pair groups
+     */
+    List<PortPairGroupId> portPairGroups();
+
+    /**
+     * Returns the list of flow classifiers associated with
+     * this port chain.
+     *
+     * @return list of flow classifiers
+     */
+    List<FlowClassifierId> flowClassifiers();
+
+    /**
+     * Returns whether this port chain is an exact match to the port chain given
+     * in the argument.
+     * <p>
+     * Exact match means the port pair groups and flow classifiers match
+     * with the given port chain. It does not consider the port chain id, name
+     * and description.
+     * </p>
+     *
+     * @param portChain other port chain to match against
+     * @return true if the port chains are an exact match, otherwise false
+     */
+    boolean exactMatch(PortChain portChain);
+
+    /**
+     * A port chain builder..
+     */
+    interface Builder {
+
+        /**
+         * Assigns the port chain id to this object.
+         *
+         * @param portChainId the port chain id
+         * @return this the builder object
+         */
+        Builder setId(PortChainId portChainId);
+
+        /**
+         * Assigns tenant id to this object.
+         *
+         * @param tenantId tenant id of the port chain
+         * @return this the builder object
+         */
+        Builder setTenantId(TenantId tenantId);
+
+        /**
+         * Assigns the name to this object.
+         *
+         * @param name name of the port chain
+         * @return this the builder object
+         */
+        Builder setName(String name);
+
+        /**
+         * Assigns the description to this object.
+         *
+         * @param description description of the port chain
+         * @return this the builder object
+         */
+        Builder setDescription(String description);
+
+        /**
+         * Assigns the port pair groups associated with the port chain
+         * to this object.
+         *
+         * @param portPairGroups list of port pair groups
+         * @return this the builder object
+         */
+        Builder setPortPairGroups(List<PortPairGroupId> portPairGroups);
+
+        /**
+         * Assigns the flow classifiers associated with the port chain
+         * to this object.
+         *
+         * @param flowClassifiers list of flow classifiers
+         * @return this the builder object
+         */
+        Builder setFlowClassifiers(List<FlowClassifierId> flowClassifiers);
+
+        /**
+         * Builds a port chain object.
+         *
+         * @return a port chain.
+         */
+        PortChain build();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java
new file mode 100644 (file)
index 0000000..66edbdc
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.UUID;
+
+import com.google.common.base.Objects;
+
+/**
+ * Representation of a Port Chain ID.
+ */
+public final class PortChainId {
+
+    private final UUID portChainId;
+
+    /**
+     * Private constructor for port chain id.
+     *
+     * @param id UUID id of port chain
+     */
+    private PortChainId(UUID id) {
+        checkNotNull(id, "Port chain id can not be null");
+        this.portChainId = id;
+    }
+
+    /**
+     * Constructor to create port chain id from UUID.
+     *
+     * @param id UUID of port chain
+     * @return object of port chain id
+     */
+    public static PortChainId portChainId(UUID id) {
+        return new PortChainId(id);
+    }
+
+    /**
+     * Constructor to create port chain id from string.
+     *
+     * @param id port chain id in string
+     * @return object of port chain id
+     */
+    public static PortChainId portChainId(String id) {
+        return new PortChainId(UUID.fromString(id));
+    }
+
+    /**
+     * Returns the value of port chain id.
+     *
+     * @return port chain id
+     */
+    public UUID value() {
+        return portChainId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj.getClass()  == this.getClass()) {
+            PortChainId that = (PortChainId) obj;
+            return Objects.equal(this.portChainId, that.portChainId);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.portChainId);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("portChainId", portChainId.toString())
+                .toString();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java
new file mode 100644 (file)
index 0000000..f6285e6
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+
+/**
+ * Abstraction of an entity providing Port Pair information.
+ * A port pair represents a service function instance.
+ */
+public interface PortPair {
+
+    /**
+     * Returns the ID of this port Pair.
+     *
+     * @return the port pair id
+     */
+    PortPairId portPairId();
+
+    /**
+     * Returns the tenant id of this port pair.
+     *
+     * @return an tenant id
+     */
+    TenantId tenantId();
+
+    /**
+     * Returns the description of this port pair.
+     *
+     * @return description of port pair
+     */
+    String name();
+
+    /**
+     * Returns the description of this port pair.
+     *
+     * @return description of port pair
+     */
+    String description();
+
+    /**
+     * Returns the ingress port of this port pair.
+     *
+     * @return ingress of port pair
+     */
+    String ingress();
+
+    /**
+     * Returns the egress port of this port pair.
+     *
+     * @return egress of port pair
+     */
+    String egress();
+
+    /**
+     * Returns whether this port pair is an exact match to the port pair given
+     * in the argument.
+     * <p>
+     * Exact match means the Port port pairs match with the given port pair.
+     * It does not consider the port pair id, name and description.
+     * </p>
+     * @param portPair other port pair to match against
+     * @return true if the port pairs are an exact match, otherwise false
+     */
+    boolean exactMatch(PortPair portPair);
+
+    /**
+     * A port pair builder..
+     */
+    interface Builder {
+
+        /**
+         * Assigns the port pair id to this object.
+         *
+         * @param portPairId the port pair id
+         * @return this the builder object
+         */
+        Builder setId(PortPairId portPairId);
+
+        /**
+         * Assigns tenant id to this object.
+         *
+         * @param tenantId tenant id of the port pair
+         * @return this the builder object
+         */
+        Builder setTenantId(TenantId tenantId);
+
+        /**
+         * Assigns the name to this object.
+         *
+         * @param name name of the port pair
+         * @return this the builder object
+         */
+        Builder setName(String name);
+
+        /**
+         * Assigns the description to this object.
+         *
+         * @param description description of the port pair
+         * @return this the builder object
+         */
+        Builder setDescription(String description);
+
+        /**
+         * Assigns the ingress port to this object.
+         *
+         * @param port ingress port of the port pair
+         * @return this the builder object
+         */
+        Builder setIngress(String port);
+
+        /**
+         * Assigns the egress port to this object.
+         *
+         * @param port egress port of the port pair
+         * @return this the builder object
+         */
+        Builder setEgress(String port);
+
+        /**
+         * Builds a port pair object.
+         *
+         * @return a port pair.
+         */
+        PortPair build();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java
new file mode 100644 (file)
index 0000000..f647b57
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import java.util.List;
+
+/**
+ * Abstraction of an entity providing Port Pair Group information.
+ * A port pair group consists of one or more port pairs.
+ */
+public interface PortPairGroup {
+
+    /**
+     * Returns the ID of this port pair group.
+     *
+     * @return the port pair group id
+     */
+    PortPairGroupId portPairGroupId();
+
+    /**
+     * Returns the tenant id of this port pair group.
+     *
+     * @return the tenant id
+     */
+    TenantId tenantId();
+
+    /**
+     * Returns the name of this port pair group.
+     *
+     * @return name of port pair group
+     */
+    String name();
+
+    /**
+     * Returns the description of this port pair group.
+     *
+     * @return description of port pair group
+     */
+    String description();
+
+    /**
+     * Returns the list of port pairs associated with this port pair group.
+     *
+     * @return list of port pairs
+     */
+    List<PortPairId> portPairs();
+
+    /**
+     * Returns whether this port pair group is an exact match to the
+     * port pair group given in the argument.
+     * <p>
+     * Exact match means the Port pairs match with the given port pair group.
+     * It does not consider the port pair group id, name and description.
+     * </p>
+     * @param portPairGroup other port pair group to match against
+     * @return true if the port pairs are an exact match, otherwise false
+     */
+    boolean exactMatch(PortPairGroup portPairGroup);
+
+    /**
+     * A port pair group builder..
+     */
+    interface Builder {
+
+        /**
+         * Assigns the port pair group id to this object.
+         *
+         * @param portPairGroupId the port pair group id
+         * @return this the builder object
+         */
+        Builder setId(PortPairGroupId portPairGroupId);
+
+        /**
+         * Assigns tenant id to this object.
+         *
+         * @param tenantId tenant id of port pair group
+         * @return this the builder object
+         */
+        Builder setTenantId(TenantId tenantId);
+
+        /**
+         * Assigns the name to this object.
+         *
+         * @param name name of the port pair group
+         * @return this the builder object
+         */
+        Builder setName(String name);
+
+        /**
+         * Assigns the description to this object.
+         *
+         * @param description description of the port pair group
+         * @return this the builder object
+         */
+        Builder setDescription(String description);
+
+        /**
+         * Assigns the port pairs associated with the port pair group
+         * to this object.
+         *
+         * @param portPairs list of port pairs
+         * @return this the builder object
+         */
+        Builder setPortPairs(List<PortPairId> portPairs);
+
+        /**
+         * Builds a port pair group object.
+         *
+         * @return a port pair group object.
+         */
+        PortPairGroup build();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java
new file mode 100644 (file)
index 0000000..0474901
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.UUID;
+
+import com.google.common.base.Objects;
+
+/**
+ * Representation of a Port Pair Group ID.
+ */
+public final class PortPairGroupId {
+
+    private final UUID portPairGroupId;
+
+    /**
+     * Private constructor for port pair group id.
+     *
+     * @param id UUID id of port pair group
+     */
+    private PortPairGroupId(UUID id) {
+        checkNotNull(id, "Port pair group id can not be null");
+        this.portPairGroupId = id;
+    }
+
+    /**
+     * Constructor to create port pair group id from UUID.
+     *
+     * @param id UUID of port pair group id
+     * @return object of port pair group id
+     */
+    public static PortPairGroupId portPairGroupId(UUID id) {
+        return new PortPairGroupId(id);
+    }
+
+    /**
+     * Constructor to create port pair group id from string.
+     *
+     * @param id port pair group id in string
+     * @return object of port pair group id
+     */
+    public static PortPairGroupId portPairGroupId(String id) {
+        return new PortPairGroupId(UUID.fromString(id));
+    }
+
+    /**
+     * Returns the value of port pair group id.
+     *
+     * @return port pair group id
+     */
+    public UUID value() {
+        return portPairGroupId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj.getClass()  == this.getClass()) {
+            PortPairGroupId that = (PortPairGroupId) obj;
+            return Objects.equal(this.portPairGroupId, that.portPairGroupId);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.portPairGroupId);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("portPairGroupId", portPairGroupId.toString())
+                .toString();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java
new file mode 100644 (file)
index 0000000..05c31aa
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.UUID;
+
+import com.google.common.base.Objects;
+
+/**
+ * Representation of a Port Pair ID.
+ */
+public final class PortPairId {
+
+    private final UUID portPairId;
+
+    /**
+     * Private constructor for port pair id.
+     *
+     * @param id UUID id of port pair
+     */
+    private PortPairId(UUID id) {
+        checkNotNull(id, "Port chain id can not be null");
+        this.portPairId = id;
+    }
+
+    /**
+     * Constructor to create port pair id from UUID.
+     *
+     * @param id UUID of port pair id
+     * @return object of port pair id
+     */
+    public static PortPairId portPairId(UUID id) {
+        return new PortPairId(id);
+    }
+
+    /**
+     * Constructor to create port pair id from string.
+     *
+     * @param id port pair id in string
+     * @return object of port pair id
+     */
+    public static PortPairId portPairId(String id) {
+        return new PortPairId(UUID.fromString(id));
+    }
+
+    /**
+     * Returns teh value of port pair id.
+     *
+     * @return port pair id
+     */
+    public UUID value() {
+        return portPairId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj.getClass()  == this.getClass()) {
+            PortPairId that = (PortPairId) obj;
+            return Objects.equal(this.portPairId, that.portPairId);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.portPairId);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("portPairId", portPairId.toString())
+                .toString();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java
new file mode 100644 (file)
index 0000000..e379be8
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.flowClassifier;
+
+import org.onosproject.vtnrsc.FlowClassifier;
+import org.onosproject.vtnrsc.FlowClassifierId;
+
+/**
+ * Provides Services for Flow Classifier.
+ */
+public interface FlowClassifierService {
+
+    /**
+     * Store Flow Classifier.
+     *
+     * @param flowClassifier Flow Classifier
+     * @return true if adding Flow Classifier into store is success otherwise return false.
+     */
+    boolean createFlowClassifier(FlowClassifier flowClassifier);
+
+    /**
+     * Return the existing collection of Flow Classifier.
+     *
+     * @return Flow Classifier collections.
+     */
+    Iterable<FlowClassifier> getFlowClassifiers();
+
+    /**
+     * Check whether Flow Classifier is present based on given Flow Classifier Id.
+     *
+     * @param id Flow Classifier.
+     * @return true if Flow Classifier is present otherwise return false.
+     */
+    boolean hasFlowClassifier(FlowClassifierId id);
+
+    /**
+     * Retrieve the Flow Classifier based on given Flow Classifier id.
+     *
+     * @param id Flow Classifier Id.
+     * @return Flow Classifier if present otherwise returns null.
+     */
+    FlowClassifier getFlowClassifier(FlowClassifierId id);
+
+    /**
+     * Update Flow Classifier based on given Flow Classifier Id.
+     *
+     * @param flowClassifier Flow Classifier.
+     * @return true if update is success otherwise return false.
+     */
+    boolean updateFlowClassifier(FlowClassifier flowClassifier);
+
+    /**
+     * Remove Flow Classifier from store based on given Flow Classifier Id.
+     *
+     * @param id Flow Classifier Id.
+     * @return true if Flow Classifier removal is success otherwise return false.
+     */
+    boolean removeFlowClassifier(FlowClassifierId id);
+}
\ No newline at end of file
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java
new file mode 100644 (file)
index 0000000..7238558
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.flowClassifier.impl;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.vtnrsc.FlowClassifierId;
+import org.onosproject.vtnrsc.FlowClassifier;
+import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService;
+
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Provides implementation of the Flow Classifier Service.
+ */
+@Component(immediate = true)
+@Service
+public class FlowClassifierManager implements FlowClassifierService {
+
+    private final Logger log = getLogger(FlowClassifierManager.class);
+
+    private static final String FLOW_CLASSIFIER_NOT_NULL = "Flow Classifier cannot be null";
+    private static final String FLOW_CLASSIFIER_ID_NOT_NULL = "Flow Classifier Id cannot be null";
+
+    private ConcurrentMap<FlowClassifierId, FlowClassifier> flowClassifierStore
+    = new ConcurrentHashMap<FlowClassifierId, FlowClassifier>();
+
+    @Activate
+    private void activate() {
+        log.info("Flow Classifier service activated");
+    }
+
+    @Deactivate
+    private void deactivate() {
+        log.info("Flow Classifier service deactivated");
+    }
+
+    @Override
+    public boolean createFlowClassifier(FlowClassifier flowClassifier) {
+        log.debug("createFlowClassifier");
+        checkNotNull(flowClassifier, FLOW_CLASSIFIER_NOT_NULL);
+        FlowClassifierId id = flowClassifier.flowClassifierId();
+
+        flowClassifierStore.put(id, flowClassifier);
+        if (!flowClassifierStore.containsKey(id)) {
+            log.debug("Flow Classifier creation is failed whose identifier is {}.", id.toString());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public Iterable<FlowClassifier> getFlowClassifiers() {
+        return ImmutableList.copyOf(flowClassifierStore.values());
+    }
+
+    @Override
+    public boolean hasFlowClassifier(FlowClassifierId id) {
+        checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL);
+        return flowClassifierStore.containsKey(id);
+    }
+
+    @Override
+    public FlowClassifier getFlowClassifier(FlowClassifierId id) {
+        checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL);
+        return flowClassifierStore.get(id);
+    }
+
+    @Override
+    public boolean updateFlowClassifier(FlowClassifier flowClassifier) {
+        checkNotNull(flowClassifier, FLOW_CLASSIFIER_NOT_NULL);
+        FlowClassifierId id = flowClassifier.flowClassifierId();
+        return flowClassifierStore.replace(id, flowClassifierStore.get(id), flowClassifier);
+    }
+
+    @Override
+    public boolean removeFlowClassifier(FlowClassifierId id) {
+        checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL);
+        flowClassifierStore.remove(id);
+        if (flowClassifierStore.containsKey(id)) {
+            log.debug("The Flow Classifier removal is failed whose identifier is {}", id.toString());
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java
new file mode 100644 (file)
index 0000000..4ea050b
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides implementation of the flow Classifier service.
+ */
+package org.onosproject.vtnrsc.flowClassifier.impl;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java
new file mode 100644 (file)
index 0000000..0758417
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Service for interacting with flow Classifier of SFC.
+ */
+package org.onosproject.vtnrsc.flowClassifier;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java
new file mode 100644 (file)
index 0000000..b4ff917
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.portchain;
+
+import org.onosproject.vtnrsc.PortChain;
+import org.onosproject.vtnrsc.PortChainId;
+
+/**
+ * Service for interacting with the inventory of port chains.
+ */
+public interface PortChainService {
+
+    /**
+     * Returns if the port chain is existed.
+     *
+     * @param portChainId port chain identifier
+     * @return true or false if one with the given identifier exists.
+     */
+    boolean exists(PortChainId portChainId);
+
+    /**
+     * Returns the number of port chains known to the system.
+     *
+     * @return number of port chains.
+     */
+    int getPortChainCount();
+
+    /**
+     * Returns an iterable collection of the currently known port chains.
+     *
+     * @return collection of port chains.
+     */
+    Iterable<PortChain> getPortChains();
+
+    /**
+     * Returns the portChain with the given identifier.
+     *
+     * @param portChainId port chain identifier
+     * @return PortChain or null if port chain with the given identifier is not
+     *         known.
+     */
+    PortChain getPortChain(PortChainId portChainId);
+
+    /**
+     * Creates a PortChain in the store.
+     *
+     * @param portChain the port chain to create
+     * @return true if given port chain is created successfully.
+     */
+    boolean createPortChain(PortChain portChain);
+
+    /**
+     * Updates the portChain in the store.
+     *
+     * @param portChain the port chain to update
+     * @return true if given port chain is updated successfully.
+     */
+    boolean updatePortChain(PortChain portChain);
+
+    /**
+     * Deletes portChain by given portChainId.
+     *
+     * @param portChainId id of port chain to remove
+     * @return true if the give port chain is deleted successfully.
+     */
+    boolean removePortChain(PortChainId portChainId);
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java
new file mode 100644 (file)
index 0000000..74642bc
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Service for interacting with the inventory of port chains.
+ */
+package org.onosproject.vtnrsc.portchain;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java
new file mode 100644 (file)
index 0000000..77f483f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.portpairgroup;
+
+import org.onosproject.vtnrsc.PortPairGroup;
+import org.onosproject.vtnrsc.PortPairGroupId;
+
+/**
+ * Service for interacting with the inventory of port pair groups.
+ */
+public interface PortPairGroupService {
+
+    /**
+     * Returns if the port pair group is existed.
+     *
+     * @param portPairGroupId port pair group identifier
+     * @return true or false if one with the given identifier exists.
+     */
+    boolean exists(PortPairGroupId portPairGroupId);
+
+    /**
+     * Returns the number of port pair groups known to the system.
+     *
+     * @return number of port pair groups.
+     */
+    int getPortPairGroupCount();
+
+    /**
+     * Returns an iterable collection of the currently known port pair groups.
+     *
+     * @return collection of port pair groups.
+     */
+    Iterable<PortPairGroup> getPortPairGroups();
+
+    /**
+     * Returns the portPairGroup with the given identifier.
+     *
+     * @param portPairGroupId port pair group identifier
+     * @return PortPairGroup or null if port pair group with the given identifier is not
+     *         known.
+     */
+    PortPairGroup getPortPairGroup(PortPairGroupId portPairGroupId);
+
+    /**
+     * Creates a PortPairGroup in the store.
+     *
+     * @param portPairGroup the port pair group to create
+     * @return true if given port pair group is created successfully.
+     */
+    boolean createPortPairGroup(PortPairGroup portPairGroup);
+
+    /**
+     * Updates the portPairGroup in the store.
+     *
+     * @param portPairGroup the port pair group to update
+     * @return true if given port pair group is updated successfully.
+     */
+    boolean updatePortPairGroup(PortPairGroup portPairGroup);
+
+    /**
+     * Deletes portPairGroup by given portPairGroupId.
+     *
+     * @param portPairGroupId id of port pair group to remove
+     * @return true if the give port pair group is deleted successfully.
+     */
+    boolean removePortPairGroup(PortPairGroupId portPairGroupId);
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java
new file mode 100644 (file)
index 0000000..8a79fe9
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Service for interacting with the inventory of port pair groups.
+ */
+package org.onosproject.vtnrsc.portpairgroup;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java
deleted file mode 100644 (file)
index 6f3cf65..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.vtnrsc.tunnel;
-
-import org.onosproject.vtnrsc.Subnet;
-import org.onosproject.vtnrsc.SubnetId;
-
-
-/**
- * Service for interacting with the inventory of subnets.
- */
-public interface TunnelConfigService {
-    /**
-     * Returns the subnet with the specified identifier.
-     *
-     * @param subnetId subnet identifier
-     * @return true or false
-     */
-    boolean exists(SubnetId subnetId);
-    /**
-     * Returns a collection of the currently known subnets.
-     *
-     * @return iterable collection of subnets
-     */
-    Iterable<Subnet> getSubnets();
-
-    /**
-     * Returns the subnet with the specified identifier.
-     *
-     * @param subnetId subnet identifier
-     * @return subnet or null if one with the given identifier is not known
-     */
-    Subnet getSubnet(SubnetId subnetId);
-    /**
-     * Creates new subnets.
-     *
-     * @param subnets the iterable collection of subnets
-     * @return true  if the identifier subnet has been created right
-     */
-    boolean createSubnets(Iterable<Subnet> subnets);
-
-    /**
-     * Updates existing subnets.
-     *
-     * @param subnets the iterable collection of subnets
-     * @return true if all subnets were updated successfully
-     */
-    boolean updateSubnets(Iterable<Subnet> subnets);
-
-    /**
-     * Administratively removes the specified subnets from the store.
-     *
-     * @param subnetIds the iterable collection of  subnets identifier
-     * @return true if remove identifier subnets successfully
-     */
-    boolean removeSubnets(Iterable<SubnetId> subnetIds);
-
-
-}
index c45373b..daec783 100644 (file)
@@ -191,22 +191,20 @@ public class VirtualPortManager implements VirtualPortService {
     @Override
     public boolean updatePorts(Iterable<VirtualPort> vPorts) {
         checkNotNull(vPorts, VIRTUALPORT_NOT_NULL);
-        if (vPorts != null) {
-            for (VirtualPort vPort : vPorts) {
-                vPortStore.put(vPort.portId(), vPort);
-                if (!vPortStore.containsKey(vPort.portId())) {
-                    log.debug("The virtualPort is not exist whose identifier is {}",
-                              vPort.portId().toString());
-                    return false;
-                }
+        for (VirtualPort vPort : vPorts) {
+            vPortStore.put(vPort.portId(), vPort);
+            if (!vPortStore.containsKey(vPort.portId())) {
+                log.debug("The virtualPort is not exist whose identifier is {}",
+                          vPort.portId().toString());
+                return false;
+            }
 
-                vPortStore.put(vPort.portId(), vPort);
+            vPortStore.put(vPort.portId(), vPort);
 
-                if (!vPort.equals(vPortStore.get(vPort.portId()))) {
-                    log.debug("The virtualPort is updated failed whose  identifier is {}",
-                              vPort.portId().toString());
-                    return false;
-                }
+            if (!vPort.equals(vPortStore.get(vPort.portId()))) {
+                log.debug("The virtualPort is updated failed whose  identifier is {}",
+                          vPort.portId().toString());
+                return false;
             }
         }
         return true;
@@ -215,14 +213,12 @@ public class VirtualPortManager implements VirtualPortService {
     @Override
     public boolean removePorts(Iterable<VirtualPortId> vPortIds) {
         checkNotNull(vPortIds, VIRTUALPORT_ID_NULL);
-        if (vPortIds != null) {
-            for (VirtualPortId vPortId : vPortIds) {
-                vPortStore.remove(vPortId);
-                if (vPortStore.containsKey(vPortId)) {
-                    log.debug("The virtualPort is removed failed whose identifier is {}",
-                              vPortId.toString());
-                    return false;
-                }
+        for (VirtualPortId vPortId : vPortIds) {
+            vPortStore.remove(vPortId);
+            if (vPortStore.containsKey(vPortId)) {
+                log.debug("The virtualPort is removed failed whose identifier is {}",
+                          vPortId.toString());
+                return false;
             }
         }
         return true;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java
new file mode 100644 (file)
index 0000000..fd5b1ee
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import java.util.UUID;
+
+import org.onlab.packet.IpPrefix;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.DefaultFlowClassifier;
+import org.onosproject.vtnrsc.FlowClassifier;
+import org.onosproject.vtnrsc.FlowClassifierId;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.TenantId;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Flow Classifier JSON codec.
+ */
+public final class FlowClassifierCodec extends JsonCodec<FlowClassifier> {
+
+    private static final String FLOW_CLASSIFIER_ID = "id";
+    private static final String TENANT_ID = "tenant_id";
+    private static final String NAME = "name";
+    private static final String DESCRIPTION = "description";
+    private static final String ETHER_TYPE = "etherType";
+    private static final String PROTOCOL = "protocol";
+    private static final String MIN_SRC_PORT_RANGE = "source_port_range_min";
+    private static final String MAX_SRC_PORT_RANGE = "source_port_range_max";
+    private static final String MIN_DST_PORT_RANGE = "destination_port_range_min";
+    private static final String MAX_DST_PORT_RANGE = "destination_port_range_max";
+    private static final String SRC_IP_PREFIX = "source_ip_prefix";
+    private static final String DST_IP_PREFIX = "destination_ip_prefix";
+    private static final String SRC_PORT = "logical_source_port";
+    private static final String DST_PORT = "logical_destination_port";
+    private static final String MISSING_MEMBER_MESSAGE = " member is required in Flow Classifier.";
+
+    @Override
+    public FlowClassifier decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        FlowClassifier.Builder resultBuilder = new DefaultFlowClassifier.Builder();
+
+        String flowClassifierId = nullIsIllegal(json.get(FLOW_CLASSIFIER_ID),
+                FLOW_CLASSIFIER_ID + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setFlowClassifierId(FlowClassifierId.flowClassifierId(UUID.fromString(flowClassifierId)));
+
+        String tenantId = nullIsIllegal(json.get(TENANT_ID), TENANT_ID + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setTenantId(TenantId.tenantId(tenantId));
+
+        String flowClassiferName = nullIsIllegal(json.get(NAME), NAME + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setName(flowClassiferName);
+
+        String flowClassiferDescription = nullIsIllegal(json.get(DESCRIPTION), DESCRIPTION + MISSING_MEMBER_MESSAGE)
+                .asText();
+        resultBuilder.setDescription(flowClassiferDescription);
+
+        String etherType = nullIsIllegal(json.get(ETHER_TYPE), ETHER_TYPE + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setEtherType(etherType);
+
+        String protocol = nullIsIllegal(json.get(PROTOCOL), PROTOCOL + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setProtocol(protocol);
+
+        int minSrcPortRange = nullIsIllegal(json.get(MIN_SRC_PORT_RANGE), MIN_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE)
+                .asInt();
+        resultBuilder.setMinSrcPortRange(minSrcPortRange);
+
+        int maxSrcPortRange = nullIsIllegal(json.get(MAX_SRC_PORT_RANGE), MAX_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE)
+                .asInt();
+        resultBuilder.setMaxSrcPortRange(maxSrcPortRange);
+
+        int minDstPortRange = nullIsIllegal(json.get(MIN_DST_PORT_RANGE), MIN_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE)
+                .asInt();
+        resultBuilder.setMinDstPortRange(minDstPortRange);
+
+        int maxDstPortRange = nullIsIllegal(json.get(MAX_DST_PORT_RANGE), MAX_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE)
+                .asInt();
+        resultBuilder.setMaxDstPortRange(maxDstPortRange);
+
+        String srcIpPrefix = nullIsIllegal(json.get(SRC_IP_PREFIX), SRC_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setSrcIpPrefix(IpPrefix.valueOf(srcIpPrefix));
+
+        String dstIpPrefix = nullIsIllegal(json.get(DST_IP_PREFIX), DST_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setDstIpPrefix(IpPrefix.valueOf(dstIpPrefix));
+
+        String srcPort = nullIsIllegal(json.get(SRC_PORT), SRC_PORT + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setSrcPort(VirtualPortId.portId(srcPort));
+
+        String dstPort = nullIsIllegal(json.get(DST_PORT), DST_PORT + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setDstPort(VirtualPortId.portId(dstPort));
+
+        return resultBuilder.build();
+    }
+
+    @Override
+    public ObjectNode encode(FlowClassifier flowClassifier, CodecContext context) {
+        checkNotNull(flowClassifier, "flowClassifier cannot be null");
+        ObjectNode result = context.mapper().createObjectNode()
+                .put("FLOW_CLASSIFIER_ID", flowClassifier.flowClassifierId().toString())
+                .put("TENANT_ID", flowClassifier.tenantId().toString())
+                .put("NAME", flowClassifier.name())
+                .put("DESCRIPTION", flowClassifier.description())
+                .put("ETHER_TYPE", flowClassifier.etherType())
+                .put("PROTOCOL", flowClassifier.protocol())
+                .put("MIN_SRC_PORT_RANGE", flowClassifier.minSrcPortRange())
+                .put("MAX_SRC_PORT_RANGE", flowClassifier.maxSrcPortRange())
+                .put("MIN_DST_PORT_RANGE", flowClassifier.minDstPortRange())
+                .put("MAX_DST_PORT_RANGE", flowClassifier.maxDstPortRange())
+                .put("SRC_IP_PREFIX", flowClassifier.srcIpPrefix().toString())
+                .put("DST_IP_PREFIX", flowClassifier.dstIpPrefix().toString())
+                .put("SRC_PORT", flowClassifier.srcPort().toString())
+                .put("DST_PORT", flowClassifier.dstPort().toString());
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java
new file mode 100644 (file)
index 0000000..b2fed34
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.flowclassifier;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.FlowClassifierId;
+
+import com.google.common.testing.EqualsTester;
+import java.util.UUID;
+
+/**
+ * Unit tests for FlowClassifierId class.
+ */
+public class FlowClassifierIdTest {
+
+    final FlowClassifierId flowClassifierId1 = FlowClassifierId
+            .flowClassifierId("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae");
+    final FlowClassifierId sameAsFlowClassifierId1 = FlowClassifierId
+            .flowClassifierId("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae");
+    final FlowClassifierId flowClassifierId2 = FlowClassifierId
+            .flowClassifierId("dace4513-24fc-4fae-af4b-321c5e2eb3d1");
+
+    /**
+     * Checks that the FlowClassifierId class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(FlowClassifierId.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(flowClassifierId1, sameAsFlowClassifierId1)
+        .addEqualityGroup(flowClassifierId2).testEquals();
+    }
+
+    /**
+     * Checks the construction of a FlowClassifierId object.
+     */
+    @Test
+    public void testConstruction() {
+        final String flowClassifierIdValue = "dace4513-24fc-4fae-af4b-321c5e2eb3d1";
+        final FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(flowClassifierIdValue);
+        assertThat(flowClassifierId, is(notNullValue()));
+        assertThat(flowClassifierId.value(), is(UUID.fromString(flowClassifierIdValue)));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java
new file mode 100644 (file)
index 0000000..4ce4def
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.subnet;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.vtnrsc.AllocationPool;
+import org.onosproject.vtnrsc.DefaultAllocationPool;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for DefaultAllocationPool class.
+ */
+public class DefaultAllocationPoolTest {
+
+    final IpAddress startIP1 = IpAddress.valueOf("192.168.1.1");
+    final IpAddress startIP2 = IpAddress.valueOf("192.168.1.2");
+    final IpAddress endIP1 = IpAddress.valueOf("192.168.1.1");
+    final IpAddress endIP2 = IpAddress.valueOf("192.168.1.2");
+
+    /**
+     * Checks that the DefaultAllocationPool class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultAllocationPool.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        AllocationPool pool1 = new DefaultAllocationPool(startIP1, endIP1);
+        AllocationPool pool2 = new DefaultAllocationPool(startIP1, endIP1);
+        AllocationPool pool3 = new DefaultAllocationPool(startIP2, endIP2);
+        new EqualsTester().addEqualityGroup(pool1, pool2)
+                .addEqualityGroup(pool3).testEquals();
+    }
+
+    /**
+     * Checks the construction of a DefaultAllocationPool object.
+     */
+    @Test
+    public void testConstruction() {
+        final AllocationPool apool = new DefaultAllocationPool(startIP1, endIP1);
+        assertThat(startIP1, is(apool.startIp()));
+        assertThat(endIP1, is(apool.endIp()));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java
new file mode 100644 (file)
index 0000000..2f75174
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.subnet;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.vtnrsc.DefaultHostRoute;
+import org.onosproject.vtnrsc.HostRoute;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for DefaultHostRoute class.
+ */
+public class DefaultHostRouteTest {
+    final IpAddress nexthop1 = IpAddress.valueOf("192.168.1.1");
+    final IpAddress nexthop2 = IpAddress.valueOf("192.168.1.2");
+    final IpPrefix destination1 = IpPrefix.valueOf("1.1.1.1/1");
+    final IpPrefix destination2 = IpPrefix.valueOf("1.1.1.1/2");
+
+    /**
+     * Checks that the DefaultHostRoute class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultHostRoute.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        HostRoute route1 = new DefaultHostRoute(nexthop1, destination1);
+        HostRoute route2 = new DefaultHostRoute(nexthop1, destination1);
+        HostRoute route3 = new DefaultHostRoute(nexthop2, destination2);
+        new EqualsTester().addEqualityGroup(route1, route2)
+                .addEqualityGroup(route3).testEquals();
+    }
+
+    /**
+     * Checks the construction of a DefaultHostRoute object.
+     */
+    @Test
+    public void testConstruction() {
+        final HostRoute host = new DefaultHostRoute(nexthop1, destination1);
+        assertThat(nexthop1, is(host.nexthop()));
+        assertThat(destination1, is(host.destination()));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java
new file mode 100644 (file)
index 0000000..d18dd41
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.subnet;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.SubnetId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for SubnetId class.
+ */
+public class SubnetIdTest {
+
+    final SubnetId subnetId1 = SubnetId.subnetId("1");
+    final SubnetId sameAsSubnetId1 = SubnetId.subnetId("1");
+    final SubnetId subnetId2 = SubnetId.subnetId("2");
+
+    /**
+     * Checks that the SubnetId class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(SubnetId.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(subnetId1, sameAsSubnetId1).addEqualityGroup(subnetId2)
+                .testEquals();
+    }
+
+    /**
+     * Checks the construction of a SubnetId object.
+     */
+    @Test
+    public void testConstruction() {
+        final String subnetIdValue = "s";
+        final SubnetId subnetId = SubnetId.subnetId(subnetIdValue);
+        assertThat(subnetId, is(notNullValue()));
+        assertThat(subnetId.subnetId(), is(subnetIdValue));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java
new file mode 100644 (file)
index 0000000..742d593
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.tenantnetwork;
+
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.DefaultTenantNetwork;
+import org.onosproject.vtnrsc.PhysicalNetwork;
+import org.onosproject.vtnrsc.SegmentationId;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetwork;
+import org.onosproject.vtnrsc.TenantNetworkId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for DefaultNeutronNetwork class.
+ */
+public class DefaultNeutronNetworkTest {
+
+    private String networkIdStr1 = "123";
+    private String networkIdStr2 = "234";
+    private String physicalNetworkStr = "1234";
+    private String tenantIdStr = "345";
+    private String segmentationIdStr = "1";
+    private String name = "456";
+
+    /**
+     * Checks that the DefaultNeutronNetwork class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultTenantNetwork.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquality() {
+        TenantNetworkId networkid1 = TenantNetworkId.networkId(networkIdStr1);
+        TenantNetworkId networkid2 = TenantNetworkId.networkId(networkIdStr2);
+        PhysicalNetwork physicalNetwork = PhysicalNetwork
+                .physicalNetwork(physicalNetworkStr);
+        TenantId tenantId = TenantId.tenantId(tenantIdStr);
+        SegmentationId segmentationID = SegmentationId
+                .segmentationId(segmentationIdStr);
+        TenantNetwork p1 = new DefaultTenantNetwork(networkid1, name, false,
+                                                    TenantNetwork.State.ACTIVE,
+                                                    false, tenantId, false,
+                                                    TenantNetwork.Type.LOCAL,
+                                                    physicalNetwork,
+                                                    segmentationID);
+        TenantNetwork p2 = new DefaultTenantNetwork(networkid1, name, false,
+                                                    TenantNetwork.State.ACTIVE,
+                                                    false, tenantId, false,
+                                                    TenantNetwork.Type.LOCAL,
+                                                    physicalNetwork,
+                                                    segmentationID);
+        TenantNetwork p3 = new DefaultTenantNetwork(networkid2, name, false,
+                                                    TenantNetwork.State.ACTIVE,
+                                                    false, tenantId, false,
+                                                    TenantNetwork.Type.LOCAL,
+                                                    physicalNetwork,
+                                                    segmentationID);
+        new EqualsTester().addEqualityGroup(p1, p2).addEqualityGroup(p3)
+                .testEquals();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java
new file mode 100644 (file)
index 0000000..e101795
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.tenantnetwork;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.PhysicalNetwork;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for PhysicalNetwork class.
+ */
+public class PhysicalNetworkTest {
+
+    final PhysicalNetwork physicalNetwork1 = PhysicalNetwork.physicalNetwork("1");
+    final PhysicalNetwork sameAsPhysicalNetwork1 = PhysicalNetwork.physicalNetwork("1");
+    final PhysicalNetwork physicalNetwork2 = PhysicalNetwork.physicalNetwork("2");
+
+    /**
+     * Checks that the PhysicalNetwork class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(PhysicalNetwork.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(physicalNetwork1, sameAsPhysicalNetwork1)
+                .addEqualityGroup(physicalNetwork2).testEquals();
+    }
+
+    /**
+     * Checks the construction of a PhysicalNetwork object.
+     */
+    @Test
+    public void testConstruction() {
+        final String physicalNetworkValue = "s";
+        final PhysicalNetwork physicalNetwork = PhysicalNetwork
+                .physicalNetwork(physicalNetworkValue);
+        assertThat(physicalNetwork, is(notNullValue()));
+        assertThat(physicalNetwork.physicalNetwork(), is(physicalNetworkValue));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java
new file mode 100644 (file)
index 0000000..dea7baf
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.tenantnetwork;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.SegmentationId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for SegmentationId class.
+ */
+public class SegmentationIdTest {
+
+    final SegmentationId segmentationID1 = SegmentationId.segmentationId("1");
+    final SegmentationId sameAsSegmentationID1 = SegmentationId.segmentationId("1");
+    final SegmentationId segmentationID2 = SegmentationId.segmentationId("2");
+
+    /**
+     * Checks that the SegmentationId class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(SegmentationId.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(segmentationID1, sameAsSegmentationID1)
+                .addEqualityGroup(segmentationID2).testEquals();
+    }
+
+    /**
+     * Checks the construction of a segmentationId object.
+     */
+    @Test
+    public void testConstruction() {
+        final String segmentationIdValue = "s";
+        final SegmentationId segmentationId = SegmentationId.segmentationId(segmentationIdValue);
+        assertThat(segmentationId, is(notNullValue()));
+        assertThat(segmentationId.segmentationId(), is(segmentationIdValue));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java
new file mode 100644 (file)
index 0000000..e921638
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.tenantnetwork;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.TenantId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for TenantId class.
+ */
+public class TenantIdTest {
+
+    final TenantId tenantId1 = TenantId.tenantId("1");
+    final TenantId sameAsTenantId1 = TenantId.tenantId("1");
+    final TenantId tenantId2 = TenantId.tenantId("2");
+
+    /**
+     * Checks that the TenantId class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(TenantId.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(tenantId1, sameAsTenantId1).addEqualityGroup(tenantId2)
+                .testEquals();
+    }
+
+    /**
+     * Checks the construction of a TenantId object.
+     */
+    @Test
+    public void testConstruction() {
+        final String tenantIdValue = "s";
+        final TenantId tenantId = TenantId.tenantId(tenantIdValue);
+        assertThat(tenantId, is(notNullValue()));
+        assertThat(tenantId.tenantId(), is(tenantIdValue));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java
new file mode 100644 (file)
index 0000000..8271b51
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.tenantnetwork;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.TenantNetworkId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for TenantNetworkId class.
+ */
+public class TenantNetworkIdTest {
+
+    final TenantNetworkId networkId1 = TenantNetworkId.networkId("1");
+    final TenantNetworkId sameAsnetworkId1 = TenantNetworkId.networkId("1");
+    final TenantNetworkId networkId2 = TenantNetworkId.networkId("2");
+
+    /**
+     * Checks that the TenantNetworkId class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(TenantNetworkId.class);
+    }
+
+    /**
+     * Checks the operation of equals() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(networkId1, sameAsnetworkId1)
+                .addEqualityGroup(networkId2).testEquals();
+    }
+
+    /**
+     * Checks the construction of a TenantNetworkId object.
+     */
+    @Test
+    public void testConstruction() {
+        final String networkIdValue = "s";
+        final TenantNetworkId networkId = TenantNetworkId.networkId(networkIdValue);
+        assertThat(networkId, is(notNullValue()));
+        assertThat(networkId.networkId(), is(networkIdValue));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java
new file mode 100644 (file)
index 0000000..dabe589
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.vtnrsc.virtualport;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.vtnrsc.AllowedAddressPair;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for AllowedAddressPair class.
+ */
+public class AllowedAddressPairTest {
+
+    final IpAddress ip1 = IpAddress.valueOf("192.168.0.1");
+    final IpAddress ip2 = IpAddress.valueOf("192.168.0.2");
+    final MacAddress mac1 = MacAddress.valueOf("fa:16:3e:76:83:88");
+    final MacAddress mac2 = MacAddress.valueOf("aa:16:3e:76:83:88");
+
+    /**
+     * Checks that the AllowedAddressPair class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(AllowedAddressPair.class);
+    }
+
+    /**
+     * Checks the operation of equals().
+     */
+    @Test
+    public void testEquals() {
+        AllowedAddressPair p1 = AllowedAddressPair
+                .allowedAddressPair(ip1, mac1);
+        AllowedAddressPair p2 = AllowedAddressPair
+                .allowedAddressPair(ip1, mac1);
+        AllowedAddressPair p3 = AllowedAddressPair
+                .allowedAddressPair(ip2, mac2);
+        new EqualsTester().addEqualityGroup(p1, p2).addEqualityGroup(p3)
+                .testEquals();
+    }
+
+    /**
+     * Checks the construction of a AllowedAddressPair object.
+     */
+    @Test
+    public void testConstruction() {
+        AllowedAddressPair allowedAddressPair = AllowedAddressPair
+                .allowedAddressPair(ip1, mac1);
+        assertThat(ip1, is(notNullValue()));
+        assertThat(ip1, is(allowedAddressPair.ip()));
+        assertThat(mac1, is(notNullValue()));
+        assertThat(mac1, is(allowedAddressPair.mac()));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java
new file mode 100644 (file)
index 0000000..8a0c800
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.vtnrsc.virtualport;
+
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.vtnrsc.AllowedAddressPair;
+import org.onosproject.vtnrsc.BindingHostId;
+import org.onosproject.vtnrsc.DefaultVirtualPort;
+import org.onosproject.vtnrsc.FixedIp;
+import org.onosproject.vtnrsc.SecurityGroup;
+import org.onosproject.vtnrsc.SubnetId;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for DefaultVirtualPort class.
+ */
+public class DefaultVirtualPortTest {
+
+    private Set<FixedIp> fixedIps;
+    private Map<String, String> propertyMap;
+    private Set<AllowedAddressPair> allowedAddressPairs;
+    private Set<SecurityGroup> securityGroups;
+    private VirtualPortId id1;
+    private VirtualPortId id2;
+    private String macAddressStr = "fa:12:3e:56:ee:a2";
+    private String ipAddress = "10.1.1.1";
+    private String deviceStr = "of:000000000000001";
+    private String tenantIdStr = "123";
+    private String portId1 = "1241";
+    private String portId2 = "1242";
+    private String tenantNetworkId = "1234567";
+    private String subnet = "1212";
+    private String hostIdStr = "fa:e2:3e:56:ee:a2";
+
+    private void initVirtualPortId() {
+        id1 = VirtualPortId.portId(portId1);
+        id2 = VirtualPortId.portId(portId2);
+    }
+
+    private void initFixedIpSet() {
+        FixedIp fixedIp = FixedIp.fixedIp(SubnetId.subnetId(subnet),
+                                          IpAddress.valueOf(ipAddress));
+        fixedIps = Sets.newHashSet();
+        fixedIps.add(fixedIp);
+    }
+
+    private void initPropertyMap() {
+        String deviceOwner = "james";
+        propertyMap = Maps.newHashMap();
+        propertyMap.putIfAbsent("deviceOwner", deviceOwner);
+    }
+
+    private void initAddressPairSet() {
+        allowedAddressPairs = Sets.newHashSet();
+        AllowedAddressPair allowedAddressPair = AllowedAddressPair
+                .allowedAddressPair(IpAddress.valueOf(ipAddress),
+                                    MacAddress.valueOf(macAddressStr));
+        allowedAddressPairs.add(allowedAddressPair);
+    }
+
+    private void initSecurityGroupSet() {
+        securityGroups = Sets.newHashSet();
+    }
+
+    /**
+     * Checks that the DefaultVirtualPort class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(SecurityGroup.class);
+    }
+
+    /**
+     * Checks the operation of equals().
+     */
+    @Test
+    public void testEquals() {
+        initVirtualPortId();
+        initFixedIpSet();
+        initPropertyMap();
+        initAddressPairSet();
+        initSecurityGroupSet();
+        TenantNetworkId networkId = TenantNetworkId.networkId(tenantNetworkId);
+        MacAddress macAddress = MacAddress.valueOf(macAddressStr);
+        TenantId tenantId = TenantId.tenantId(tenantIdStr);
+        DeviceId deviceId = DeviceId.deviceId(deviceStr);
+        BindingHostId bindingHostId = BindingHostId.bindingHostId(hostIdStr);
+
+        VirtualPort d1 = new DefaultVirtualPort(id1, networkId, true,
+                                                propertyMap,
+                                                VirtualPort.State.ACTIVE,
+                                                macAddress, tenantId, deviceId,
+                                                fixedIps, bindingHostId,
+                                                allowedAddressPairs,
+                                                securityGroups);
+        VirtualPort d2 = new DefaultVirtualPort(id1, networkId, true,
+                                                propertyMap,
+                                                VirtualPort.State.ACTIVE,
+                                                macAddress, tenantId, deviceId,
+                                                fixedIps, bindingHostId,
+                                                allowedAddressPairs,
+                                                securityGroups);
+        VirtualPort d3 = new DefaultVirtualPort(id2, networkId, true,
+                                                propertyMap,
+                                                VirtualPort.State.ACTIVE,
+                                                macAddress, tenantId, deviceId,
+                                                fixedIps, bindingHostId,
+                                                allowedAddressPairs,
+                                                securityGroups);
+        new EqualsTester().addEqualityGroup(d1, d2).addEqualityGroup(d3)
+                .testEquals();
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java
new file mode 100644 (file)
index 0000000..1e33da0
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.vtnrsc.virtualport;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.vtnrsc.FixedIp;
+import org.onosproject.vtnrsc.SubnetId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for FixedIp class.
+ */
+public class FixedIpTest {
+
+    final SubnetId subnetId1 = SubnetId.subnetId("lef11-95w-4er-9c9c");
+    final SubnetId subnetId2 = SubnetId.subnetId("lefaa-95w-4er-9c9c");
+    final IpAddress ip1 = IpAddress.valueOf("192.168.0.1");
+    final IpAddress ip2 = IpAddress.valueOf("192.168.1.1");
+
+    /**
+     * Checks that the FixedIp class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(FixedIp.class);
+    }
+
+    /**
+     * Checks the operation of equals().
+     */
+    @Test
+    public void testEquals() {
+        FixedIp fixedIp1 = FixedIp.fixedIp(subnetId1, ip1);
+        FixedIp fixedIp2 = FixedIp.fixedIp(subnetId1, ip1);
+        FixedIp fixedIp3 = FixedIp.fixedIp(subnetId2, ip2);
+        new EqualsTester().addEqualityGroup(fixedIp1, fixedIp2)
+                .addEqualityGroup(fixedIp3).testEquals();
+    }
+
+    /**
+     * Checks the construction of a FixedIp object.
+     */
+    @Test
+    public void testConstruction() {
+        FixedIp fixedIp = FixedIp.fixedIp(subnetId1, ip1);
+        assertThat(ip1, is(notNullValue()));
+        assertThat(ip1, is(fixedIp.ip()));
+        assertThat(subnetId1, is(notNullValue()));
+        assertThat(subnetId1, is(fixedIp.subnetId()));
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java
new file mode 100644 (file)
index 0000000..8c04e49
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.vtnrsc.virtualport;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.SecurityGroup;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for SecurityGroup class.
+ */
+public class SecurityGroupTest {
+
+    final SecurityGroup securityGroup1 = SecurityGroup.securityGroup("1");
+    final SecurityGroup sameAssecurityGroup = SecurityGroup.securityGroup("1");
+    final SecurityGroup securityGroup2 = SecurityGroup.securityGroup("2");
+
+    /**
+     * Checks that the SecurityGroup class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(SecurityGroup.class);
+    }
+
+    /**
+     * Checks the operation of equals().
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(securityGroup1, sameAssecurityGroup)
+                .addEqualityGroup(securityGroup2).testEquals();
+    }
+
+    /**
+     * Checks the construction of a SecurityGroup object.
+     */
+    @Test
+    public void testConstruction() {
+        final String securityGroupValue = "1";
+        final SecurityGroup securityGroup = SecurityGroup.securityGroup(securityGroupValue);
+        assertThat(securityGroup, is(notNullValue()));
+        assertThat(securityGroup.securityGroup(), is(securityGroupValue));
+
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java
new file mode 100644 (file)
index 0000000..2d63e91
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.vtnrsc.virtualport;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+import org.junit.Test;
+import org.onosproject.vtnrsc.VirtualPortId;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for VirtualPortId class.
+ */
+public class VirtualPortIdTest {
+
+    final VirtualPortId virtualPortId1 = VirtualPortId.portId("1");
+    final VirtualPortId sameAsVirtualPortId1 = VirtualPortId.portId("1");
+    final VirtualPortId virtualPortId2 = VirtualPortId.portId("2");
+
+    /**
+     * Checks that the VirtualPortId class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(VirtualPortId.class);
+    }
+
+    /**
+     * Checks the operation of equals().
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester().addEqualityGroup(virtualPortId1, sameAsVirtualPortId1)
+                .addEqualityGroup(virtualPortId2).testEquals();
+    }
+
+    /**
+     * Checks the construction of a VirtualPortId object.
+     */
+    @Test
+    public void testConstruction() {
+        final String vPortIdValue = "aaa";
+        final VirtualPortId virtualPortId = VirtualPortId.portId(vPortIdValue);
+        assertThat(virtualPortId, is(notNullValue()));
+        assertThat(virtualPortId.portId(), is(vPortIdValue));
+
+    }
+}
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java
new file mode 100644 (file)
index 0000000..1450e4e
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnweb.resources;
+
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+import static org.onlab.util.Tools.nullIsNotFound;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.vtnrsc.FlowClassifier;
+import org.onosproject.vtnrsc.FlowClassifierId;
+import org.onosproject.rest.AbstractWebResource;
+import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService;
+import org.onosproject.vtnrsc.web.FlowClassifierCodec;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Query and program flow classifier.
+ */
+@Path("flow_classifiers")
+public class FlowClassifierWebResource extends AbstractWebResource {
+
+    final FlowClassifierService service = get(FlowClassifierService.class);
+    final ObjectNode root = mapper().createObjectNode();
+    public static final String FLOW_CLASSIFIER_NOT_FOUND = "Flow classifier not found";
+
+    /**
+     * Get all flow classifiers created. Returns list of all flow classifiers
+     * created.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getFlowClassifiers() {
+        Iterable<FlowClassifier> flowClassifiers = service.getFlowClassifiers();
+        ObjectNode result = new ObjectMapper().createObjectNode();
+        result.set("flow_classifiers", new FlowClassifierCodec().encode(flowClassifiers, this));
+        return ok(result.toString()).build();
+    }
+
+    /**
+     * Get details of a flow classifier. Returns details of a specified flow
+     * classifier id.
+     *
+     * @param id flow classifier id
+     * @return 200 OK
+     */
+    @GET
+    @Path("{flow_id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getFlowClassifier(@PathParam("flow_id") String id) {
+
+        if (!service.hasFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id)))) {
+            return Response.status(NOT_FOUND).entity(FLOW_CLASSIFIER_NOT_FOUND).build();
+        }
+        FlowClassifier flowClassifier = nullIsNotFound(
+                service.getFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id))),
+                FLOW_CLASSIFIER_NOT_FOUND);
+
+        ObjectNode result = new ObjectMapper().createObjectNode();
+        result.set("flow_classifier", new FlowClassifierCodec().encode(flowClassifier, this));
+        return ok(result.toString()).build();
+    }
+
+    /**
+     * Creates and stores a new flow classifier.
+     *
+     * @param flowClassifierId flow classifier identifier
+     * @param stream flow classifier from JSON
+     * @return status of the request - CREATED if the JSON is correct,
+     *         BAD_REQUEST if the JSON is invalid
+     */
+    @POST
+    @Path("{flow_id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createFlowClassifier(@PathParam("flow_id") String flowClassifierId, InputStream stream) {
+        URI location;
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+
+            FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this);
+            service.createFlowClassifier(flowClassifier);
+            location = new URI(flowClassifierId);
+        } catch (IOException | URISyntaxException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return Response.created(location).build();
+    }
+
+    /**
+     * Creates and stores a new flow classifier.
+     *
+     * @param stream flow classifier from JSON
+     * @return status of the request - CREATED if the JSON is correct,
+     *         BAD_REQUEST if the JSON is invalid
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createFlowClassifier(InputStream stream) {
+        URI location;
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+
+            FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this);
+            service.createFlowClassifier(flowClassifier);
+            location = new URI(flowClassifier.flowClassifierId().toString());
+        } catch (IOException | URISyntaxException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return Response.created(location).build();
+    }
+
+    /**
+     * Update details of a flow classifier. Update details of a specified flow
+     * classifier id.
+     *
+     * @param id flow classifier id
+     * @param stream InputStream
+     * @return 200 OK
+     */
+    @PUT
+    @Path("{flow_id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateFlowClassifier(@PathParam("flow_id") String id, final InputStream stream) {
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this);
+            Boolean result = nullIsNotFound(service.updateFlowClassifier(flowClassifier), FLOW_CLASSIFIER_NOT_FOUND);
+            if (!result) {
+                return Response.status(204).entity(FLOW_CLASSIFIER_NOT_FOUND).build();
+            }
+            return Response.status(203).entity(result.toString()).build();
+        } catch (Exception e) {
+            return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build();
+        }
+    }
+
+    /**
+     * Delete details of a flow classifier. Delete details of a specified flow
+     * classifier id.
+     *
+     * @param id flow classifier id
+     * @return 200 OK
+     * @throws IOException when input doesn't match.
+     */
+    @Path("{flow_id}")
+    @DELETE
+    public Response deleteFlowClassifier(@PathParam("flow_id") String id) throws IOException {
+        try {
+            FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(UUID.fromString(id));
+            service.removeFlowClassifier(flowClassifierId);
+            return Response.status(201).entity("SUCCESS").build();
+        } catch (Exception e) {
+            return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build();
+        }
+    }
+}
index 251dcff..0cc59a4 100644 (file)
@@ -56,7 +56,7 @@ import org.onosproject.vtnrsc.TenantId;
 import org.onosproject.vtnrsc.TenantNetworkId;
 import org.onosproject.vtnrsc.Subnet.Mode;
 import org.onosproject.vtnrsc.subnet.SubnetService;
-import org.onosproject.vtnrsc.web.SubnetCodec;
+import org.onosproject.vtnweb.web.SubnetCodec;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index 0b87782..2dd931e 100644 (file)
@@ -51,7 +51,7 @@ import org.onosproject.vtnrsc.TenantNetworkId;
 import org.onosproject.vtnrsc.TenantNetwork.State;
 import org.onosproject.vtnrsc.TenantNetwork.Type;
 import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
-import org.onosproject.vtnrsc.web.TenantNetworkCodec;
+import org.onosproject.vtnweb.web.TenantNetworkCodec;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index 03d3a65..e47a57d 100644 (file)
@@ -58,7 +58,7 @@ import org.onosproject.vtnrsc.VirtualPort;
 import org.onosproject.vtnrsc.VirtualPort.State;
 import org.onosproject.vtnrsc.VirtualPortId;
 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
-import org.onosproject.vtnrsc.web.VirtualPortCodec;
+import org.onosproject.vtnweb.web.VirtualPortCodec;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java
new file mode 100644 (file)
index 0000000..28da5cd
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnweb.web;
+
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.DefaultPortChain;
+import org.onosproject.vtnrsc.FlowClassifierId;
+import org.onosproject.vtnrsc.PortChain;
+import org.onosproject.vtnrsc.PortChainId;
+import org.onosproject.vtnrsc.PortPairGroupId;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
+
+/**
+ * Port chain JSON codec.
+ */
+public final class PortChainCodec extends JsonCodec<PortChain> {
+
+    private static final String ID = "id";
+    private static final String TENANT_ID = "tenant_id";
+    private static final String NAME = "name";
+    private static final String DESCRIPTION = "description";
+    private static final String PORT_PAIR_GROUPS = "port_pair_groups";
+    private static final String FLOW_CLASSIFIERS = "flow_classifiers";
+    private static final String MISSING_MEMBER_MESSAGE =
+            " member is required in PortChain";
+
+    @Override
+    public PortChain decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        PortChain.Builder resultBuilder = new DefaultPortChain.Builder();
+
+        String id = nullIsIllegal(json.get(ID),
+                                  ID + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setId(PortChainId.portChainId(id));
+
+        String tenantId = nullIsIllegal(json.get(TENANT_ID),
+                                        TENANT_ID + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setTenantId(TenantId.tenantId(tenantId));
+
+        String name = nullIsIllegal(json.get(NAME),
+                                    NAME + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setName(name);
+
+        String description = nullIsIllegal(json.get(DESCRIPTION),
+                                           DESCRIPTION + MISSING_MEMBER_MESSAGE).asText();
+        resultBuilder.setDescription(description);
+
+        ArrayNode arrayNode = (ArrayNode) json.path(PORT_PAIR_GROUPS);
+        if (arrayNode != null) {
+            List<PortPairGroupId> list = Lists.newArrayList();
+            arrayNode.forEach(i -> list.add(PortPairGroupId.portPairGroupId(i.asText())));
+            resultBuilder.setPortPairGroups(list);
+        }
+
+        arrayNode = (ArrayNode) json.path(FLOW_CLASSIFIERS);
+        if (arrayNode != null) {
+            List<FlowClassifierId> list = Lists.newArrayList();
+            arrayNode.forEach(i -> list.add(FlowClassifierId.flowClassifierId(UUID.fromString(i.asText()))));
+            resultBuilder.setFlowClassifiers(list);
+        }
+
+        return resultBuilder.build();
+    }
+
+    @Override
+    public ObjectNode encode(PortChain portChain, CodecContext context) {
+        checkNotNull(portChain, "port pair cannot be null");
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(ID, portChain.portChainId().toString())
+                .put(TENANT_ID, portChain.tenantId().toString())
+                .put(NAME, portChain.name())
+                .put(DESCRIPTION, portChain.description())
+                .put(PORT_PAIR_GROUPS, portChain.portPairGroups().toString())
+                .put(FLOW_CLASSIFIERS, portChain.flowClassifiers().toString());
+        return result;
+    }
+}
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.vtnrsc.web;
+package org.onosproject.vtnweb.web;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java
new file mode 100644 (file)
index 0000000..3a60943
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Codecs for virtual tenant objects.
+ */
+package org.onosproject.vtnweb.web;
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java
new file mode 100755 (executable)
index 0000000..d223096
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.onosproject.bgp.controller;
+
+/**
+ * Responsible for keeping track of the current set BGPLS peers connected to the system.
+ *
+ */
+public interface BgpPeerManager {
+
+    /**
+     * Add connected peer.
+     *
+     * @param bgpId BGP ID to add
+     * @param bgpPeer BGp peer instance
+     *
+     * @return false if peer already exist, otherwise true
+     */
+    public boolean addConnectedPeer(BGPId bgpId, BGPPeer bgpPeer);
+
+    /**
+     * Validate wheather peer is connected.
+     *
+     * @param bgpId BGP ID to validate
+     *
+     * @return true if peer exist, otherwise false
+     */
+    public boolean isPeerConnected(BGPId bgpId);
+
+    /**
+     * Remove connected peer.
+     *
+     * @param bgpId BGP ID
+     */
+    public void removeConnectedPeer(BGPId bgpId);
+
+    /**
+     * Gets connected peer.
+     *
+     * @param bgpId BGP ID
+     * @return BGPPeer the connected peer, otherwise null
+     */
+    public BGPPeer getPeer(BGPId bgpId);
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java
new file mode 100755 (executable)
index 0000000..71b9cbf
--- /dev/null
@@ -0,0 +1,82 @@
+/*\r
+ * Copyright 2015 Open Networking Laboratory\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package org.onosproject.bgpio.protocol;\r
+\r
+import org.jboss.netty.buffer.ChannelBuffer;\r
+import org.onosproject.bgpio.exceptions.BGPParseException;\r
+import org.onosproject.bgpio.protocol.ver4.BGPFactoryVer4;\r
+import org.onosproject.bgpio.types.BGPHeader;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * Abstraction to provide the version for BGP.\r
+ */\r
+public final class BGPFactories {\r
+\r
+    protected static final Logger log = LoggerFactory.getLogger(BGPFactories.class);\r
+\r
+    private static final GenericReader GENERIC_READER = new GenericReader();\r
+\r
+    private BGPFactories() {\r
+    }\r
+\r
+    /**\r
+     * Returns the instance of BGP Version.\r
+     *\r
+     * @param version BGP version\r
+     * @return BGP version\r
+     */\r
+    public static BGPFactory getFactory(BGPVersion version) {\r
+        switch (version) {\r
+        case BGP_4:\r
+            return BGPFactoryVer4.INSTANCE;\r
+        default:\r
+            throw new IllegalArgumentException("[BGPFactory:]Unknown version: " + version);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Reader class for reading BGP messages from channel buffer.\r
+     *\r
+     */\r
+    private static class GenericReader implements BGPMessageReader<BGPMessage> {\r
+\r
+        @Override\r
+        public BGPMessage readFrom(ChannelBuffer bb, BGPHeader bgpHeader)\r
+                throws BGPParseException {\r
+            BGPFactory factory;\r
+\r
+            if (!bb.readable()) {\r
+                log.error("Empty message received");\r
+                throw new BGPParseException("Empty message received");\r
+            }\r
+            // TODO: Currently only BGP version 4 is supported\r
+            factory = org.onosproject.bgpio.protocol.ver4.BGPFactoryVer4.INSTANCE;\r
+            return factory.getReader().readFrom(bb, bgpHeader);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns BGP messsage generic reader.\r
+     *\r
+     * @return bgp message generic reader\r
+     */\r
+    public static BGPMessageReader<BGPMessage> getGenericReader() {\r
+        return GENERIC_READER;\r
+    }\r
+}\r
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java
new file mode 100755 (executable)
index 0000000..cf6bf00
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgpio.protocol;
+
+/**
+ * Abstraction of an message factory providing builder functions to BGP messages
+ * and objects.
+ *
+ */
+public interface BGPFactory {
+
+    /**
+     * Gets the builder object for a open message.
+     *
+     * @return builder object for open message
+     */
+    BGPOpenMsg.Builder openMessageBuilder();
+
+    /**
+     * Gets the builder object for a keepalive message.
+     *
+     * @return builder object for keepalive message
+     */
+    BGPKeepaliveMsg.Builder keepaliveMessageBuilder();
+
+    /**
+     * Gets the builder object for a notification message.
+     *
+     * @return builder object for notification message.
+     */
+    BGPNotificationMsg.Builder notificationMessageBuilder();
+
+    /**
+     * Gets the BGP message reader.
+     *
+     * @return BGP message reader
+     */
+    BGPMessageReader<BGPMessage> getReader();
+
+    /**
+     * Returns BGP version.
+     *
+     * @return BGP version
+     */
+    BGPVersion getVersion();
+}
index 56540dd..a1d9d57 100644 (file)
 package org.onosproject.bgpio.protocol;
 
 import org.onosproject.bgpio.exceptions.BGPParseException;
-import org.onosproject.bgpio.types.BGPHeader;
 
 /**
- * Abstraction of an entity providing BGP Notification Message.
+ * Abstraction of an entity providing BGP notification message.
  */
 public interface BGPNotificationMsg extends BGPMessage {
     /**
-     * Returns errorCode in Notification message.
+     * Returns errorCode in notification message.
      *
-     * @return errorCode in Notification message
+     * @return errorCode in notification message
      */
     byte getErrorCode();
 
     /**
-     * Returns error SubCode in Notification message.
+     * Returns error subCode in notification message.
      *
-     * @return error SubCode in Notification message
+     * @return error subCode in notification message
      */
     byte getErrorSubCode();
 
     /**
-     * Returns error data in Notification message.
+     * Returns error data in notification message.
      *
-     * @return error data in Notification message
+     * @return error data in notification message
      */
     byte[] getData();
 
     /**
-     * Builder interface with get and set functions to build Notification
-     * message.
+     * Builder interface with get and set functions to build notification message.
      */
     public interface Builder extends BGPMessage.Builder {
 
         @Override
         BGPNotificationMsg build() throws BGPParseException;
 
-        /**
-         * Sets notification message header and returns its builder.
-         *
-         * @param header of notification message
-         * @return Builder by setting notification message header
-         */
-        Builder setNotificationMsgHeader(BGPHeader header);
-
         /**
          * Sets errorCode in notification message and return its builder.
          *
          * @param errorCode in notification message
-         * @return builder by setting ErrorCode in notification message
+         * @return builder by setting errorCode in notification message
          */
         Builder setErrorCode(byte errorCode);
 
         /**
-         * Sets error SubCode in notification message and return its builder.
+         * Sets error subCode in notification message and return its builder.
          *
-         * @param errorSubCode in notification Message
-         * @return builder by setting ErrorSubCode in notification Message
+         * @param errorSubCode in notification message
+         * @return builder by setting error subCode in notification message
          */
         Builder setErrorSubCode(byte errorSubCode);
 
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java
new file mode 100755 (executable)
index 0000000..32af385
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgpio.protocol.ver4;
+
+import org.onosproject.bgpio.protocol.BGPFactory;
+import org.onosproject.bgpio.protocol.BGPKeepaliveMsg;
+import org.onosproject.bgpio.protocol.BGPMessage;
+import org.onosproject.bgpio.protocol.BGPMessageReader;
+import org.onosproject.bgpio.protocol.BGPNotificationMsg;
+import org.onosproject.bgpio.protocol.BGPOpenMsg;
+import org.onosproject.bgpio.protocol.BGPVersion;
+
+/**
+ * Provides BGP Factory and returns builder classes for all objects and messages.
+ */
+public class BGPFactoryVer4 implements BGPFactory {
+
+    public static final BGPFactoryVer4 INSTANCE = new BGPFactoryVer4();
+
+    @Override
+    public BGPOpenMsg.Builder openMessageBuilder() {
+        return new BGPOpenMsgVer4.Builder();
+    }
+
+    @Override
+    public BGPKeepaliveMsg.Builder keepaliveMessageBuilder() {
+        return new BGPKeepaliveMsgVer4.Builder();
+    }
+
+    @Override
+    public BGPNotificationMsg.Builder notificationMessageBuilder() {
+        return new BGPNotificationMsgVer4.Builder();
+    }
+
+    @Override
+    public BGPMessageReader<BGPMessage> getReader() {
+        return BGPMessageVer4.READER;
+    }
+
+    @Override
+    public BGPVersion getVersion() {
+        return BGPVersion.BGP_4;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java
new file mode 100755 (executable)
index 0000000..d45e3de
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgpio.protocol.ver4;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.protocol.BGPFactories;
+import org.onosproject.bgpio.protocol.BGPMessage;
+import org.onosproject.bgpio.protocol.BGPMessageReader;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPHeader;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides BGP messages.
+ */
+public abstract class BGPMessageVer4 {
+
+    protected static final Logger log = LoggerFactory.getLogger(BGPFactories.class);
+
+    static final byte OPEN_MSG_TYPE = 0x1;
+    static final byte KEEPALIVE_MSG_TYPE = 0x4;
+    static final byte UPDATE_MSG_TYPE = 0x2;
+    static final byte NOTIFICATION_MSG_TYPE = 0x3;
+    static final int MINIMUM_COMMON_HEADER_LENGTH = 19;
+    static final int HEADER_AND_MSG_LEN = 18;
+    static final int MAXIMUM_PACKET_LENGTH = 4096;
+
+    public static final BGPMessageVer4.Reader READER = new Reader();
+
+    /**
+     * Reader class for reading BGP messages from channel buffer.
+     *
+     */
+    static class Reader implements BGPMessageReader<BGPMessage> {
+        @Override
+        public BGPMessage readFrom(ChannelBuffer cb, BGPHeader bgpHeader)
+                throws BGPParseException {
+
+            if (cb.readableBytes() < MINIMUM_COMMON_HEADER_LENGTH) {
+                log.error("Packet should have minimum length.");
+                Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH,
+                                       cb.readableBytes());
+            }
+            if (cb.readableBytes() > MAXIMUM_PACKET_LENGTH) {
+                log.error("Packet length should not exceed {}.", MAXIMUM_PACKET_LENGTH);
+                Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH,
+                                       cb.readableBytes());
+            }
+            try {
+                // fixed value property version == 4
+                byte[] marker = new byte[BGPHeader.MARKER_LENGTH];
+                cb.readBytes(marker, 0, BGPHeader.MARKER_LENGTH);
+                bgpHeader.setMarker(marker);
+                for (int i = 0; i < BGPHeader.MARKER_LENGTH; i++) {
+                    if (marker[i] != (byte) 0xff) {
+                        throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR,
+                                                    BGPErrorType.CONNECTION_NOT_SYNCHRONIZED, null);
+                    }
+                }
+                short length = cb.readShort();
+                if (length != (cb.readableBytes() + HEADER_AND_MSG_LEN)) {
+                    Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, length);
+                }
+                bgpHeader.setLength(length);
+                byte type = cb.readByte();
+                bgpHeader.setType(type);
+                log.debug("Reading update message of type " + type);
+
+                int len = length - MINIMUM_COMMON_HEADER_LENGTH;
+                switch (type) {
+                case OPEN_MSG_TYPE:
+                    log.debug("OPEN MESSAGE is received");
+                    return BGPOpenMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader);
+                case KEEPALIVE_MSG_TYPE:
+                    log.debug("KEEPALIVE MESSAGE is received");
+                    return BGPKeepaliveMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader);
+                case UPDATE_MSG_TYPE:
+                    log.debug("UPDATE MESSAGE is received");
+                    // TODO: Update message version 4
+                case NOTIFICATION_MSG_TYPE:
+                    log.debug("NOTIFICATION MESSAGE is received");
+                    return BGPNotificationMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader);
+                default:
+                    Validation.validateType(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_TYPE, type);
+                    return null;
+                }
+            } catch (IndexOutOfBoundsException e) {
+                throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, null);
+            }
+        }
+    }
+}
\ No newline at end of file
index 064dead..3bddd37 100644 (file)
@@ -44,7 +44,7 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg {
               REFERENCE : RFC 4271
     */
 
-    protected static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class);
+    private static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class);
 
     static final byte PACKET_VERSION = 4;
     //BGPHeader(19) + Error code(1) + Error subcode(1)
@@ -52,8 +52,10 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg {
     static final int PACKET_MINIMUM_LENGTH = 2;
     static final BGPType MSG_TYPE = BGPType.NOTIFICATION;
     static final byte DEFAULT_ERRORSUBCODE = 0;
-    static final byte[] MARKER = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-            0x01, 0x01};
+    static final byte[] MARKER = {(byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0xff, (byte) 0xff };
     static final byte MESSAGE_TYPE = 3;
     static final BGPHeader DEFAULT_MESSAGE_HEADER = new BGPHeader(MARKER, BGPHeader.DEFAULT_HEADER_LENGTH,
                                                                   MESSAGE_TYPE);
@@ -65,7 +67,7 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg {
     public static final BGPNotificationMsgVer4.Reader READER = new Reader();
 
     /**
-     * Resets fields.
+     * Initialize fields.
      */
     public BGPNotificationMsgVer4() {
         this.bgpHeader = null;
@@ -153,13 +155,6 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg {
             return this;
         }
 
-        @Override
-        public Builder setNotificationMsgHeader(BGPHeader header) {
-            this.bgpHeader = header;
-            this.isBGPHeaderSet = true;
-            return this;
-        }
-
         @Override
         public Builder setHeader(BGPHeader bgpMsgHeader) {
             this.bgpHeader = bgpMsgHeader;
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java
new file mode 100644 (file)
index 0000000..08fea4c
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.protocol.ver4;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.As4Path;
+import org.onosproject.bgpio.types.AsPath;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.types.LocalPref;
+import org.onosproject.bgpio.types.Med;
+import org.onosproject.bgpio.types.NextHop;
+import org.onosproject.bgpio.types.Origin;
+import org.onosproject.bgpio.util.UnSupportedAttribute;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of BGP Path Attribute.
+ */
+public class BgpPathAttributes {
+
+    /* Path attribute:
+           <attribute type, attribute length, attribute value>
+
+           0                   1
+           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |  Attr. Flags  |Attr. Type Code|
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           REFERENCE : RFC 4271
+    */
+    protected static final Logger log = LoggerFactory.getLogger(BgpPathAttributes.class);
+
+    public static final int LINK_STATE_ATTRIBUTE_TYPE = 50;
+    public static final int MPREACHNLRI_TYPE = 14;
+    public static final int MPUNREACHNLRI_TYPE = 15;
+
+    private final List<BGPValueType> pathAttribute;
+
+    /**
+     * Initialize parameter.
+     */
+    public BgpPathAttributes() {
+        this.pathAttribute = null;
+    }
+
+    /**
+     * Constructor to initialize parameters for BGP path attributes.
+     *
+     * @param pathAttribute list of path attributes
+     */
+    public BgpPathAttributes(List<BGPValueType> pathAttribute) {
+        this.pathAttribute = pathAttribute;
+    }
+
+    /**
+     * Returns list of path attributes.
+     *
+     * @return list of path attributes
+     */
+    public List<BGPValueType> pathAttributes() {
+        return this.pathAttribute;
+    }
+
+    /**
+     * Reads from channelBuffer and parses BGP path attributes.
+     *
+     * @param cb channelBuffer
+     * @return object of BgpPathAttributes
+     * @throws BGPParseException while parsing BGP path attributes
+     */
+    public static BgpPathAttributes read(ChannelBuffer cb)
+            throws BGPParseException {
+
+        BGPValueType pathAttribute = null;
+        List<BGPValueType> pathAttributeList = new LinkedList<>();
+        boolean isOrigin = false;
+        boolean isAsPath = false;
+        boolean isNextHop = false;
+        boolean isMpReach = false;
+        boolean isMpUnReach = false;
+        while (cb.readableBytes() > 0) {
+            cb.markReaderIndex();
+            byte flags = cb.readByte();
+            byte typeCode = cb.readByte();
+            cb.resetReaderIndex();
+            switch (typeCode) {
+            case Origin.ORIGIN_TYPE:
+                pathAttribute = Origin.read(cb);
+                isOrigin = ((Origin) pathAttribute).isOriginSet();
+                break;
+            case AsPath.ASPATH_TYPE:
+                pathAttribute = AsPath.read(cb);
+                isAsPath = ((AsPath) pathAttribute).isaspathSet();
+                break;
+            case As4Path.AS4PATH_TYPE:
+                pathAttribute = As4Path.read(cb);
+                break;
+            case NextHop.NEXTHOP_TYPE:
+                pathAttribute = NextHop.read(cb);
+                isNextHop = ((NextHop) pathAttribute).isNextHopSet();
+                break;
+            case Med.MED_TYPE:
+                pathAttribute = Med.read(cb);
+                break;
+            case LocalPref.LOCAL_PREF_TYPE:
+                pathAttribute = LocalPref.read(cb);
+                break;
+            case MPREACHNLRI_TYPE:
+                //TODO: To be merged later
+                break;
+            case MPUNREACHNLRI_TYPE:
+                //TODO: To be merged later
+                break;
+            case LINK_STATE_ATTRIBUTE_TYPE:
+                //TODO: To be merged later
+                break;
+            default:
+                //skip bytes for unsupported attribute types
+                UnSupportedAttribute.read(cb);
+            }
+            pathAttributeList.add(pathAttribute);
+        }
+
+        checkMandatoryAttr(isOrigin, isAsPath, isNextHop, isMpReach, isMpUnReach);
+        //TODO:if mp_reach or mp_unreach not present ignore the packet
+        return new BgpPathAttributes(pathAttributeList);
+    }
+
+    /**
+     * Checks mandatory attributes are presents, if not present throws exception.
+     *
+     * @param isOrigin say whether origin attribute is present
+     * @param isAsPath say whether aspath attribute is present
+     * @param isNextHop say whether nexthop attribute is present
+     * @param isMpReach say whether mpreach attribute is present
+     * @param isMpUnReach say whether mpunreach attribute is present
+     * @throws BGPParseException if mandatory path attribute is not present
+     */
+    public static void checkMandatoryAttr(boolean isOrigin, boolean isAsPath,
+            boolean isNextHop, boolean isMpReach, boolean isMpUnReach)
+            throws BGPParseException {
+        if (!isOrigin) {
+            log.debug("Mandatory Attributes not Present");
+            Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                    BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE,
+                    Origin.ORIGIN_TYPE);
+        }
+        if (!isAsPath) {
+            log.debug("Mandatory Attributes not Present");
+            Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                    BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE,
+                    AsPath.ASPATH_TYPE);
+        }
+        if (!isMpUnReach && !isMpReach && !isNextHop) {
+            log.debug("Mandatory Attributes not Present");
+            Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                    BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE,
+                    NextHop.NEXTHOP_TYPE);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("pathAttribute", pathAttribute)
+                .toString();
+    }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java
new file mode 100644 (file)
index 0000000..90e94e8
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of As4Path BGP Path Attribute.
+ */
+public class As4Path implements BGPValueType {
+    private static final Logger log = LoggerFactory.getLogger(AsPath.class);
+    public static final byte AS4PATH_TYPE = 17;
+    public static final byte ASNUM_SIZE = 4;
+    public static final int TYPE_AND_LEN_AS_SHORT = 4;
+    public static final int TYPE_AND_LEN_AS_BYTE = 3;
+
+    private List<Integer> as4pathSet;
+    private List<Integer> as4pathSeq;
+
+    /**
+     * Initialize fields.
+     */
+    public As4Path() {
+        this.as4pathSeq = null;
+        this.as4pathSet = null;
+    }
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param as4pathSet AS4path Set
+     * @param as4pathSeq AS4path Sequence
+     */
+    public As4Path(List<Integer> as4pathSet, List<Integer> as4pathSeq) {
+        this.as4pathSeq = as4pathSeq;
+        this.as4pathSet = as4pathSet;
+    }
+
+    /**
+     * Reads from the channel buffer and parses As4Path.
+     *
+     * @param cb ChannelBuffer
+     * @return object of As4Path
+     * @throws BGPParseException while parsing As4Path
+     */
+    public static As4Path read(ChannelBuffer cb) throws BGPParseException {
+        List<Integer> as4pathSet = new ArrayList<>();
+        List<Integer> as4pathSeq = new ArrayList<>();
+        ChannelBuffer tempCb = cb.copy();
+        Validation validation = Validation.parseAttributeHeader(cb);
+
+        if (cb.readableBytes() < validation.getLength()) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                    validation.getLength());
+        }
+        //if fourth bit is set length is read as short otherwise as byte , len includes type, length and value
+        int len = validation.isShort() ? validation.getLength() + TYPE_AND_LEN_AS_SHORT : validation
+                .getLength() + TYPE_AND_LEN_AS_BYTE;
+        ChannelBuffer data = tempCb.readBytes(len);
+        if (validation.getFirstBit() && !validation.getSecondBit() && validation.getThirdBit()) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data);
+        }
+
+        ChannelBuffer tempBuf = cb.readBytes(validation.getLength());
+        while (tempBuf.readableBytes() > 0) {
+            byte pathSegType = tempBuf.readByte();
+            //no of ASes
+            byte pathSegLen = tempBuf.readByte();
+            //length = no of Ases * ASnum size (4 bytes)
+            int length = pathSegLen * ASNUM_SIZE;
+            if (tempBuf.readableBytes() < length) {
+                Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                        BGPErrorType.ATTRIBUTE_LENGTH_ERROR, length);
+            }
+            ChannelBuffer aspathBuf = tempBuf.readBytes(length);
+            while (aspathBuf.readableBytes() > 0) {
+                int asNum;
+                asNum = aspathBuf.readInt();
+                switch (pathSegType) {
+                case AsPath.ASPATH_SET_TYPE:
+                    as4pathSet.add(asNum);
+                    break;
+                case AsPath.ASPATH_SEQ_TYPE:
+                    as4pathSeq.add(asNum);
+                    break;
+                default: log.debug("Other type Not Supported:" + pathSegType);
+                }
+            }
+        }
+        return new As4Path(as4pathSet, as4pathSeq);
+    }
+
+    @Override
+    public short getType() {
+        return AS4PATH_TYPE;
+    }
+
+    /**
+     * Returns list of ASNum in AS4path Sequence.
+     *
+     * @return list of ASNum in AS4path Sequence
+     */
+    public List<Integer> as4PathSEQ() {
+        return this.as4pathSeq;
+    }
+
+    /**
+     * Returns list of ASNum in AS4path Set.
+     *
+     * @return list of ASNum in AS4path Set
+     */
+    public List<Integer> as4PathSET() {
+        return this.as4pathSet;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(as4pathSet, as4pathSeq);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof As4Path) {
+            As4Path other = (As4Path) obj;
+            return Objects.equals(as4pathSet, other.as4pathSet) && Objects.equals(as4pathSeq, other.as4pathSeq);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .omitNullValues()
+                .add("as4pathSet", as4pathSet)
+                .add("as4pathSeq", as4pathSeq)
+                .toString();
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        //Not required to Implement as of now
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java
new file mode 100644 (file)
index 0000000..100e14d
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgpio.types;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of AsPath mandatory BGP Path Attribute.
+ */
+public class AsPath implements BGPValueType {
+    /**
+     * Enum to provide AS types.
+     */
+    public enum ASTYPE {
+        AS_SET(1), AS_SEQUENCE(2), AS_CONFED_SEQUENCE(3), AS_CONFED_SET(4);
+        int value;
+
+        /**
+         * Assign val with the value as the AS type.
+         *
+         * @param val AS type
+         */
+        ASTYPE(int val) {
+            value = val;
+        }
+
+        /**
+         * Returns value of AS type.
+         *
+         * @return AS type
+         */
+        public byte getType() {
+            return (byte) value;
+        }
+    }
+
+    private static final Logger log = LoggerFactory.getLogger(AsPath.class);
+    public static final byte ASPATH_TYPE = 2;
+    public static final byte ASPATH_SET_TYPE = 1;
+    public static final byte ASPATH_SEQ_TYPE = 2;
+    public static final byte ASNUM_SIZE = 2;
+    public static final int TYPE_AND_LEN_AS_SHORT = 4;
+    public static final int TYPE_AND_LEN_AS_BYTE = 3;
+
+    private boolean isAsPath = false;
+    private List<Short> aspathSet;
+    private List<Short> aspathSeq;
+
+    /**
+     * Initialize Fields.
+     */
+    public AsPath() {
+        this.aspathSeq = null;
+        this.aspathSet = null;
+    }
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param aspathSet ASpath Set type
+     * @param aspathSeq ASpath Sequence type
+     */
+    public AsPath(List<Short> aspathSet, List<Short> aspathSeq) {
+        this.aspathSeq = aspathSeq;
+        this.aspathSet = aspathSet;
+        this.isAsPath = true;
+    }
+
+    /**
+     * Reads from the channel buffer and parses AsPath.
+     *
+     * @param cb ChannelBuffer
+     * @return object of AsPath
+     * @throws BGPParseException while parsing AsPath
+     */
+    public static AsPath read(ChannelBuffer cb) throws BGPParseException {
+        List<Short> aspathSet = new ArrayList<>();
+        List<Short> aspathSeq = new ArrayList<>();
+        ChannelBuffer tempCb = cb.copy();
+        Validation validation = Validation.parseAttributeHeader(cb);
+
+        if (cb.readableBytes() < validation.getLength()) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                    validation.getLength());
+        }
+        //if fourth bit is set, length is read as short otherwise as byte , len includes type, length and value
+        int len = validation.isShort() ? validation.getLength() + TYPE_AND_LEN_AS_SHORT : validation
+                .getLength() + TYPE_AND_LEN_AS_BYTE;
+        ChannelBuffer data = tempCb.readBytes(len);
+        if (validation.getFirstBit() && !validation.getSecondBit() && validation.getThirdBit()) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data);
+        }
+
+        ChannelBuffer tempBuf = cb.readBytes(validation.getLength());
+        while (tempBuf.readableBytes() > 0) {
+            byte pathSegType = tempBuf.readByte();
+            //no of ASes
+            byte pathSegLen = tempBuf.readByte();
+            int length = pathSegLen * ASNUM_SIZE;
+            if (tempBuf.readableBytes() < length) {
+                Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                        BGPErrorType.ATTRIBUTE_LENGTH_ERROR, length);
+            }
+            ChannelBuffer aspathBuf = tempBuf.readBytes(length);
+            while (aspathBuf.readableBytes() > 0) {
+                short asNum;
+                asNum = aspathBuf.readShort();
+                switch (pathSegType) {
+                case ASPATH_SET_TYPE:
+                    aspathSet.add(asNum);
+                    break;
+                case ASPATH_SEQ_TYPE:
+                    aspathSeq.add(asNum);
+                    break;
+                default: log.debug("Other type Not Supported:" + pathSegType);
+                }
+            }
+        }
+        return new AsPath(aspathSet, aspathSeq);
+    }
+
+    @Override
+    public short getType() {
+        return ASPATH_TYPE;
+    }
+
+    /**
+     * Returns whether ASpath path attribute is present.
+     *
+     * @return whether ASpath path attribute is present
+     */
+    public boolean isaspathSet() {
+        return this.isAsPath;
+    }
+
+    /**
+     * Returns list of ASNum in ASpath Sequence.
+     *
+     * @return list of ASNum in ASpath Sequence
+     */
+    public List<Short> asPathSeq() {
+        return this.aspathSeq;
+    }
+
+    /**
+     * Returns list of ASNum in ASpath SET.
+     *
+     * @return list of ASNum in ASpath SET
+     */
+    public List<Short> asPathSet() {
+        return this.aspathSet;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(aspathSet, aspathSeq);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof AsPath) {
+            AsPath other = (AsPath) obj;
+            return Objects.equals(aspathSet, other.aspathSet) && Objects.equals(aspathSeq, other.aspathSeq);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .omitNullValues()
+                .add("aspathSet", aspathSet)
+                .add("aspathSeq", aspathSeq)
+                .toString();
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        //Not required to Implement as of now
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java
new file mode 100644 (file)
index 0000000..048d81e
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides implementation of LocalPref BGP Path Attribute.
+ */
+public class LocalPref implements BGPValueType {
+
+    private static final Logger log = LoggerFactory.getLogger(LocalPref.class);
+    public static final byte LOCAL_PREF_TYPE = 5;
+    public static final int TYPE_AND_LEN_AS_SHORT = 4;
+    public static final int TYPE_AND_LEN_AS_BYTE = 3;
+    public static final byte LOCAL_PREF_MAX_LEN = 4;
+
+    private int localPref;
+
+    /**
+     * Constructor to initialize LocalPref.
+     *
+     * @param localPref local preference
+     */
+    public LocalPref(int localPref) {
+        this.localPref = localPref;
+    }
+
+    /**
+     * Returns local preference value.
+     *
+     * @return local preference value
+     */
+    public int localPref() {
+        return this.localPref;
+    }
+
+    /**
+     * Reads the channel buffer and returns object of LocalPref.
+     *
+     * @param cb channelBuffer
+     * @return object of LocalPref
+     * @throws BGPParseException while parsing localPref attribute
+     */
+    public static LocalPref read(ChannelBuffer cb) throws BGPParseException {
+        int localPref;
+        ChannelBuffer tempCb = cb.copy();
+        Validation parseFlags = Validation.parseAttributeHeader(cb);
+        if ((parseFlags.getLength() > LOCAL_PREF_MAX_LEN) || cb.readableBytes() < parseFlags.getLength()) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                    parseFlags.getLength());
+        }
+
+        int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags.getLength()
+                + TYPE_AND_LEN_AS_BYTE;
+        ChannelBuffer data = tempCb.readBytes(len);
+        if (parseFlags.getFirstBit()) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data);
+        }
+
+        localPref = cb.readInt();
+        return new LocalPref(localPref);
+    }
+
+    @Override
+    public short getType() {
+        return LOCAL_PREF_TYPE;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(localPref);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalPref) {
+            LocalPref other = (LocalPref) obj;
+            return Objects.equals(localPref, other.localPref);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("localPref", localPref)
+                .toString();
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        //Not to implement as of now
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java
new file mode 100644 (file)
index 0000000..49e1fc5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of Med BGP Path Attribute.
+ */
+public class Med implements BGPValueType {
+    private static final Logger log = LoggerFactory.getLogger(Med.class);
+    public static final byte MED_TYPE = 4;
+    public static final int TYPE_AND_LEN_AS_SHORT = 4;
+    public static final int TYPE_AND_LEN_AS_BYTE = 3;
+    public static final byte MED_MAX_LEN = 4;
+
+    private int med;
+
+    /**
+     * Constructor to initialize med.
+     *
+     * @param med MULTI_EXIT_DISC value
+     */
+    public Med(int med) {
+        this.med = med;
+    }
+
+    /**
+     * Returns Med value.
+     *
+     * @return Med value
+     */
+    public int med() {
+        return this.med;
+    }
+
+    /**
+     * Reads the channel buffer and returns object of Med.
+     *
+     * @param cb ChannelBuffer
+     * @return object of Med
+     * @throws BGPParseException while parsing Med path attribute
+     */
+    public static Med read(ChannelBuffer cb) throws BGPParseException {
+        int med;
+        ChannelBuffer tempCb = cb.copy();
+        Validation parseFlags = Validation.parseAttributeHeader(cb);
+
+        if ((parseFlags.getLength() > MED_MAX_LEN) || cb.readableBytes() < parseFlags.getLength()) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                    parseFlags.getLength());
+        }
+        int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags
+                .getLength() + TYPE_AND_LEN_AS_BYTE;
+        ChannelBuffer data = tempCb.readBytes(len);
+        if (!parseFlags.getFirstBit() && parseFlags.getSecondBit() && parseFlags.getThirdBit()) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data);
+        }
+
+        med = cb.readInt();
+        return new Med(med);
+    }
+
+    @Override
+    public short getType() {
+        return MED_TYPE;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(med);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Med) {
+            Med other = (Med) obj;
+            return Objects.equals(med, other.med);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("med", med)
+                .toString();
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        //Not to implement as of now
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java
new file mode 100644 (file)
index 0000000..353ec3d
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types;
+
+import java.net.InetAddress;
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+/**
+ * Implementation of NextHop BGP Path Attribute.
+ */
+public class NextHop implements BGPValueType {
+    private static final Logger log = LoggerFactory.getLogger(NextHop.class);
+    public static final byte NEXTHOP_TYPE = 3;
+    public static final int TYPE_AND_LEN_AS_SHORT = 4;
+    public static final int TYPE_AND_LEN_AS_BYTE = 3;
+
+    private boolean isNextHop = false;
+    private Ip4Address nextHop;
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param nextHop nextHop address
+     */
+    public NextHop(Ip4Address nextHop) {
+        this.nextHop = Preconditions.checkNotNull(nextHop);
+        this.isNextHop = true;
+    }
+
+    /**
+     * Returns whether next hop is present.
+     *
+     * @return whether next hop is present
+     */
+    public boolean isNextHopSet() {
+        return this.isNextHop;
+    }
+
+    /**
+     * Reads from ChannelBuffer and parses NextHop.
+     *
+     * @param cb ChannelBuffer
+     * @return object of NextHop
+     * @throws BGPParseException while parsing nexthop attribute
+     */
+    public static NextHop read(ChannelBuffer cb) throws BGPParseException {
+        Ip4Address nextHop;
+        ChannelBuffer tempCb = cb.copy();
+        Validation parseFlags = Validation.parseAttributeHeader(cb);
+
+        if (cb.readableBytes() < parseFlags.getLength()) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                    parseFlags.getLength());
+        }
+        int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags
+                .getLength() + TYPE_AND_LEN_AS_BYTE;
+        ChannelBuffer data = tempCb.readBytes(len);
+        if (parseFlags.getFirstBit() && !parseFlags.getSecondBit() && parseFlags.getThirdBit()) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data);
+        }
+
+        //TODO: use Validation.toInetAddress once Validation is merged
+        InetAddress ipAddress = (InetAddress) cb.readBytes(parseFlags.getLength());
+        if (ipAddress.isMulticastAddress()) {
+            throw new BGPParseException("Multicast address is not supported");
+        }
+
+        nextHop = Ip4Address.valueOf(ipAddress);
+        return new NextHop(nextHop);
+    }
+
+    /**
+     * Return nexthop address.
+     *
+     * @return nexthop address
+     */
+    public Ip4Address nextHop() {
+        return nextHop;
+    }
+
+    @Override
+    public short getType() {
+        return NEXTHOP_TYPE;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        //Not required to be implemented now
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(nextHop);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof NextHop) {
+            NextHop other = (NextHop) obj;
+            return Objects.equals(nextHop, other.nextHop);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("nextHop", nextHop)
+                .toString();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java
new file mode 100644 (file)
index 0000000..3b2070d
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of mandatory BGP Origin path attribute.
+ */
+public class Origin implements BGPValueType {
+    private static final Logger log = LoggerFactory.getLogger(Origin.class);
+
+    /**
+     * Enum to provide ORIGIN types.
+     */
+    public enum ORIGINTYPE {
+        IGP(0), EGP(1), INCOMPLETE(2);
+        int value;
+        /**
+         * Assign val with the value as the ORIGIN type.
+         *
+         * @param val ORIGIN type
+         */
+        ORIGINTYPE(int val) {
+            value = val;
+        }
+
+        /**
+         * Returns value of ORIGIN type.
+         *
+         * @return ORIGIN type
+         */
+        public byte getType() {
+            return (byte) value;
+        }
+    }
+
+    public static final byte ORIGIN_TYPE = 1;
+    public static final byte ORIGIN_VALUE_LEN = 1;
+    public static final int TYPE_AND_LEN_AS_SHORT = 4;
+    public static final int TYPE_AND_LEN_AS_BYTE = 3;
+
+    private boolean isOrigin = false;
+    private byte origin;
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param origin origin value
+     */
+    public Origin(byte origin) {
+        this.origin = origin;
+        this.isOrigin = true;
+    }
+
+    /**
+     * Returns true if origin attribute is present otherwise false.
+     *
+     * @return whether origin is present or not
+     */
+    public boolean isOriginSet() {
+        return this.isOrigin;
+    }
+
+    /**
+     * Returns type of Origin in Enum values.
+     *
+     * @return type of Origin in Enum values
+     */
+    public ORIGINTYPE origin() {
+        if (this.origin == 0) {
+            return ORIGINTYPE.IGP;
+        } else if (this.origin == 1) {
+            return ORIGINTYPE.EGP;
+        } else {
+            return ORIGINTYPE.INCOMPLETE;
+        }
+    }
+
+    /**
+     * Reads from ChannelBuffer and parses Origin.
+     *
+     * @param cb ChannelBuffer
+     * @return object of Origin
+     * @throws BGPParseException while parsing Origin path attribute
+     */
+    public static Origin read(ChannelBuffer cb) throws BGPParseException {
+        ChannelBuffer tempCb = cb.copy();
+        Validation parseFlags = Validation.parseAttributeHeader(cb);
+
+        int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags
+                .getLength() + TYPE_AND_LEN_AS_BYTE;
+        ChannelBuffer data = tempCb.readBytes(len);
+        if ((parseFlags.getLength() > ORIGIN_VALUE_LEN) || (cb.readableBytes() < parseFlags.getLength())) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                    parseFlags.getLength());
+        }
+        if (parseFlags.getFirstBit() && !parseFlags.getSecondBit() && parseFlags.getThirdBit()) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data);
+        }
+
+        byte originValue;
+        originValue = cb.readByte();
+        if ((originValue != ORIGINTYPE.INCOMPLETE.value) || (originValue != ORIGINTYPE.IGP.value) ||
+              (originValue != ORIGINTYPE.EGP.value)) {
+            throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.INVALID_ORIGIN_ATTRIBUTE, data);
+        }
+        return new Origin(originValue);
+    }
+
+    @Override
+    public short getType() {
+        return ORIGIN_TYPE;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        //Not required to Implement as of now
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(origin);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Origin) {
+            Origin other = (Origin) obj;
+            return Objects.equals(origin, other.origin);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("origin", origin)
+                .toString();
+    }
+}
\ No newline at end of file
index ba02f6d..e7f4a4c 100755 (executable)
@@ -30,7 +30,7 @@ import com.google.common.base.MoreObjects;
 /**
  * Implements BGP attribute node flag.
  */
-public class BgpAttrNodeFlagBitTlv implements BGPValueType {
+public final class BgpAttrNodeFlagBitTlv implements BGPValueType {
 
     protected static final Logger log = LoggerFactory
             .getLogger(BgpAttrNodeFlagBitTlv.class);
@@ -38,16 +38,15 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
     public static final int ATTRNODE_FLAGBIT = 1024;
 
     /* Node flag bit TLV */
-    private boolean bOverloadBit;
-    private boolean bAttachedBit;
-    private boolean bExternalBit;
-    private boolean bABRBit;
+    private final boolean bOverloadBit;
+    private final boolean bAttachedBit;
+    private final boolean bExternalBit;
+    private final boolean bAbrBit;
 
-    public static final int BIT_SET = 1;
-    public static final int FIRST_BIT = 0x80;
-    public static final int SECOND_BIT = 0x40;
-    public static final int THIRD_BIT = 0x20;
-    public static final int FOURTH_BIT = 0x01;
+    public static final byte FIRST_BIT = (byte) 0x80;
+    public static final byte SECOND_BIT = 0x40;
+    public static final byte THIRD_BIT = 0x20;
+    public static final byte FOURTH_BIT = 0x01;
 
     /**
      * Constructor to initialize parameters.
@@ -55,14 +54,31 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
      * @param bOverloadBit Overload bit
      * @param bAttachedBit Attached bit
      * @param bExternalBit External bit
-     * @param bABRBit ABR Bit
+     * @param bAbrBit ABR Bit
      */
-    BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit,
-                          boolean bExternalBit, boolean bABRBit) {
+    private BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit,
+                                  boolean bExternalBit, boolean bAbrBit) {
         this.bOverloadBit = bOverloadBit;
         this.bAttachedBit = bAttachedBit;
         this.bExternalBit = bExternalBit;
-        this.bABRBit = bABRBit;
+        this.bAbrBit = bAbrBit;
+    }
+
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param bOverloadBit Overload bit
+     * @param bAttachedBit Attached bit
+     * @param bExternalBit External bit
+     * @param bAbrBit ABR Bit
+     * @return object of BgpAttrNodeFlagBitTlv
+     */
+    public static BgpAttrNodeFlagBitTlv of(final boolean bOverloadBit,
+                                           final boolean bAttachedBit,
+                                           final boolean bExternalBit,
+                                           final boolean bAbrBit) {
+        return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit,
+                                         bExternalBit, bAbrBit);
     }
 
     /**
@@ -77,11 +93,11 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
         boolean bOverloadBit = false;
         boolean bAttachedBit = false;
         boolean bExternalBit = false;
-        boolean bABRBit = false;
+        boolean bAbrBit = false;
 
         short lsAttrLength = cb.readShort();
 
-        if (lsAttrLength != 1) {
+        if ((lsAttrLength != 1) || (cb.readableBytes() < lsAttrLength)) {
             Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
                                    BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
                                    lsAttrLength);
@@ -89,13 +105,13 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
 
         byte nodeFlagBits = cb.readByte();
 
-        bOverloadBit = ((nodeFlagBits & (byte) FIRST_BIT) == FIRST_BIT);
-        bAttachedBit = ((nodeFlagBits & (byte) SECOND_BIT) == SECOND_BIT);
-        bExternalBit = ((nodeFlagBits & (byte) THIRD_BIT) == THIRD_BIT);
-        bABRBit = ((nodeFlagBits & (byte) FOURTH_BIT) == FOURTH_BIT);
+        bOverloadBit = ((nodeFlagBits & FIRST_BIT) == FIRST_BIT);
+        bAttachedBit = ((nodeFlagBits & SECOND_BIT) == SECOND_BIT);
+        bExternalBit = ((nodeFlagBits & THIRD_BIT) == THIRD_BIT);
+        bAbrBit = ((nodeFlagBits & FOURTH_BIT) == FOURTH_BIT);
 
-        return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit,
-                                         bExternalBit, bABRBit);
+        return BgpAttrNodeFlagBitTlv.of(bOverloadBit, bAttachedBit,
+                                        bExternalBit, bAbrBit);
     }
 
     /**
@@ -103,7 +119,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
      *
      * @return Overload Bit
      */
-    boolean getOverLoadBit() {
+    public boolean overLoadBit() {
         return bOverloadBit;
     }
 
@@ -112,7 +128,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
      *
      * @return Attached Bit
      */
-    boolean getAttachedBit() {
+    public boolean attachedBit() {
         return bAttachedBit;
     }
 
@@ -121,7 +137,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
      *
      * @return External Bit
      */
-    boolean getExternalBit() {
+    public boolean externalBit() {
         return bExternalBit;
     }
 
@@ -130,8 +146,8 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
      *
      * @return ABR Bit
      */
-    boolean getABRBit() {
-        return bABRBit;
+    public boolean abrBit() {
+        return bAbrBit;
     }
 
     @Override
@@ -141,13 +157,13 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
 
     @Override
     public int write(ChannelBuffer cb) {
-        // TODO will be implementing it later
+        // TODO This will be implemented in the next version
         return 0;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bABRBit);
+        return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bAbrBit);
     }
 
     @Override
@@ -161,7 +177,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
             return Objects.equals(bOverloadBit, other.bOverloadBit)
                     && Objects.equals(bAttachedBit, other.bAttachedBit)
                     && Objects.equals(bExternalBit, other.bExternalBit)
-                    && Objects.equals(bABRBit, other.bABRBit);
+                    && Objects.equals(bAbrBit, other.bAbrBit);
         }
         return false;
     }
@@ -171,7 +187,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType {
         return MoreObjects.toStringHelper(getClass())
                 .add("bOverloadBit", bOverloadBit)
                 .add("bAttachedBit", bAttachedBit)
-                .add("bExternalBit", bExternalBit).add("bABRBit", bABRBit)
+                .add("bExternalBit", bExternalBit).add("bAbrBit", bAbrBit)
                 .toString();
     }
 }
index 00dffb5..a10d167 100755 (executable)
@@ -31,15 +31,15 @@ import com.google.common.base.MoreObjects;
 /**
  * Implements BGP attribute node router ID.
  */
-public class BgpAttrRouterIdV4 implements BGPValueType {
+public final class BgpAttrRouterIdV4 implements BGPValueType {
 
     protected static final Logger log = LoggerFactory
             .getLogger(BgpAttrRouterIdV4.class);
 
-    public short sType;
+    private final short sType;
 
     /* IPv4 Router-ID of Node */
-    private Ip4Address ip4RouterId;
+    private final Ip4Address ip4RouterId;
 
     /**
      * Constructor to initialize the value.
@@ -47,35 +47,45 @@ public class BgpAttrRouterIdV4 implements BGPValueType {
      * @param ip4RouterId IPV4 address of router
      * @param sType TLV type
      */
-    BgpAttrRouterIdV4(Ip4Address ip4RouterId, short sType) {
+    private BgpAttrRouterIdV4(Ip4Address ip4RouterId, short sType) {
         this.ip4RouterId = ip4RouterId;
         this.sType = sType;
     }
 
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param ip4RouterId IPv4 address
+     * @param sType Type of this TLV
+     * @return object of BgpAttrRouterIdV4
+     */
+    public static BgpAttrRouterIdV4 of(final Ip4Address ip4RouterId,
+                                       final short sType) {
+        return new BgpAttrRouterIdV4(ip4RouterId, sType);
+    }
+
     /**
      * Reads the IPv4 Router-ID.
      *
      * @param cb ChannelBuffer
+     * @param sType tag type
      * @return object of BgpAttrRouterIdV4
-     * @throws BGPParseException while parsing BgpAttrNodeRouterId
+     * @throws BGPParseException while parsing BgpAttrRouterIdV4
      */
     public static BgpAttrRouterIdV4 read(ChannelBuffer cb, short sType)
             throws BGPParseException {
-        byte[] ipBytes;
-        Ip4Address ip4RouterId;
-
         short lsAttrLength = cb.readShort();
 
-        if (4 != lsAttrLength) {
+        if ((lsAttrLength != 4) || (cb.readableBytes() < lsAttrLength)) {
             Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
                                    BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
                                    lsAttrLength);
         }
 
-        ipBytes = new byte[lsAttrLength];
-        cb.readBytes(ipBytes);
-        ip4RouterId = Ip4Address.valueOf(ipBytes);
-        return new BgpAttrRouterIdV4(ip4RouterId, sType);
+        byte[] ipBytes = new byte[lsAttrLength];
+        cb.readBytes(ipBytes, 0, lsAttrLength);
+        Ip4Address ip4RouterId = Ip4Address.valueOf(ipBytes);
+        return BgpAttrRouterIdV4.of(ip4RouterId, sType);
     }
 
     /**
@@ -83,7 +93,7 @@ public class BgpAttrRouterIdV4 implements BGPValueType {
      *
      * @return Router ID
      */
-    Ip4Address getAttrRouterId() {
+    public Ip4Address attrRouterId() {
         return ip4RouterId;
     }
 
@@ -112,7 +122,7 @@ public class BgpAttrRouterIdV4 implements BGPValueType {
 
     @Override
     public int write(ChannelBuffer cb) {
-        // TODO Auto-generated method stub
+        // TODO This will be implemented in the next version
         return 0;
     }
 
index 561c3d4..ea63c37 100755 (executable)
@@ -31,15 +31,15 @@ import com.google.common.base.MoreObjects;
 /**
  * Implements BGP attribute IPv6 router ID.
  */
-public class BgpAttrRouterIdV6 implements BGPValueType {
+public final class BgpAttrRouterIdV6 implements BGPValueType {
 
     protected static final Logger log = LoggerFactory
             .getLogger(BgpAttrRouterIdV6.class);
 
-    public short sType;
+    private final short sType;
 
     /* IPv4 Router-ID of Node */
-    private Ip6Address ip6RouterId;
+    private final Ip6Address ip6RouterId;
 
     /**
      * Constructor to initialize the value.
@@ -47,15 +47,28 @@ public class BgpAttrRouterIdV6 implements BGPValueType {
      * @param ip6RouterId IPV6 address of the router ID
      * @param sType TLV type
      */
-    BgpAttrRouterIdV6(Ip6Address ip6RouterId, short sType) {
+    private BgpAttrRouterIdV6(Ip6Address ip6RouterId, short sType) {
         this.ip6RouterId = ip6RouterId;
         this.sType = sType;
     }
 
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param ip6RouterId IPV6 address of the router ID
+     * @param sType TLV type
+     * @return object of BgpAttrRouterIdV6
+     */
+    public static BgpAttrRouterIdV6 of(final Ip6Address ip6RouterId,
+                                       final short sType) {
+        return new BgpAttrRouterIdV6(ip6RouterId, sType);
+    }
+
     /**
      * Reads the IPv6 Router-ID.
      *
      * @param cb ChannelBuffer
+     * @param sType TLV type
      * @return object of BgpAttrRouterIdV6
      * @throws BGPParseException while parsing BgpAttrRouterIdV6
      */
@@ -66,7 +79,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType {
 
         short lsAttrLength = cb.readShort();
 
-        if (16 != lsAttrLength) {
+        if ((lsAttrLength != 16) || (cb.readableBytes() < lsAttrLength)) {
             Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
                                    BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
                                    lsAttrLength);
@@ -75,7 +88,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType {
         ipBytes = new byte[lsAttrLength];
         cb.readBytes(ipBytes);
         ip6RouterId = Ip6Address.valueOf(ipBytes);
-        return new BgpAttrRouterIdV6(ip6RouterId, sType);
+        return BgpAttrRouterIdV6.of(ip6RouterId, sType);
     }
 
     /**
@@ -83,7 +96,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType {
      *
      * @return Router ID
      */
-    Ip6Address getAttrRouterId() {
+    public Ip6Address attrRouterId() {
         return ip6RouterId;
     }
 
@@ -112,7 +125,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType {
 
     @Override
     public int write(ChannelBuffer cb) {
-        // TODO Auto-generated method stub
+        // TODO This will be implemented in the next version
         return 0;
     }
 
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java
new file mode 100755 (executable)
index 0000000..c1cb299
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types.attr;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Implements BGP link IGP metric attribute.
+ */
+public class BgpLinkAttrIgpMetric implements BGPValueType {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(BgpLinkAttrIgpMetric.class);
+
+    public static final int ATTRLINK_IGPMETRIC = 1095;
+    public static final int ATTRLINK_MAX_LEN = 3;
+
+    /* Variable metric length based on protocol */
+    public static final int ISIS_SMALL_METRIC = 1;
+    public static final int OSPF_LINK_METRIC = 2;
+    public static final int ISIS_WIDE_METRIC = 3;
+
+    /* IGP Metric */
+    private final int igpMetric;
+    private final int igpMetricLen;
+
+    /**
+     * Constructor to initialize the value.
+     *
+     * @param igpMetric 3 byte IGP metric data.
+     * @param igpMetricLen length of IGP metric data.
+     */
+    public BgpLinkAttrIgpMetric(final int igpMetric, final int igpMetricLen) {
+        this.igpMetric = igpMetric;
+        this.igpMetricLen = igpMetricLen;
+    }
+
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param igpMetric 3 byte IGP metric data.
+     * @param igpMetricLen length of IGP metric data.
+     * @return object of BgpLinkAttrIgpMetric
+     */
+    public static BgpLinkAttrIgpMetric of(final int igpMetric,
+                                          final int igpMetricLen) {
+        return new BgpLinkAttrIgpMetric(igpMetric, igpMetricLen);
+    }
+
+    /**
+     * Reads the BGP link attributes IGP Metric.
+     *
+     * @param cb Channel buffer
+     * @return object of type BgpLinkAttrIgpMetric
+     * @throws BGPParseException while parsing BgpLinkAttrIgpMetric
+     */
+    public static BgpLinkAttrIgpMetric read(ChannelBuffer cb)
+            throws BGPParseException {
+
+        short linkigp;
+        int igpMetric = 0;
+        int igpMetricLen = 0;
+
+        short lsAttrLength = cb.readShort();
+
+        if (cb.readableBytes() < lsAttrLength
+                || lsAttrLength > ATTRLINK_MAX_LEN) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                                   BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                                   lsAttrLength);
+        }
+
+        switch (lsAttrLength) {
+        case ISIS_SMALL_METRIC:
+            igpMetric = cb.readByte();
+            igpMetricLen = ISIS_SMALL_METRIC;
+            break;
+        case OSPF_LINK_METRIC:
+            igpMetric = cb.readShort();
+            igpMetricLen = OSPF_LINK_METRIC;
+            break;
+        case ISIS_WIDE_METRIC:
+            linkigp = cb.readShort();
+            igpMetric = cb.readByte();
+            igpMetric = (igpMetric << 16) | linkigp;
+            igpMetricLen = ISIS_WIDE_METRIC;
+            break;
+        default: // validation is already in place
+            break;
+        }
+
+        return BgpLinkAttrIgpMetric.of(igpMetric, igpMetricLen);
+    }
+
+    /**
+     * Returns the variable length IGP metric data.
+     *
+     * @return IGP metric data
+     */
+    public int attrLinkIgpMetric() {
+        return igpMetric;
+    }
+
+    /**
+     * Returns IGP metric data length.
+     *
+     * @return IGP metric length
+     */
+    public int attrLinkIgpMetricLength() {
+        return igpMetricLen;
+    }
+
+    @Override
+    public short getType() {
+        return ATTRLINK_IGPMETRIC;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(igpMetric, igpMetricLen);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof BgpLinkAttrIgpMetric) {
+            BgpLinkAttrIgpMetric other = (BgpLinkAttrIgpMetric) obj;
+            return Objects.equals(igpMetric, other.igpMetric)
+                    && Objects.equals(igpMetricLen, other.igpMetricLen);
+        }
+        return false;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        // TODO This will be implemented in the next version
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("igpMetric", igpMetric).add("igpMetricLen", igpMetricLen)
+                .toString();
+    }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java
new file mode 100755 (executable)
index 0000000..61143fa
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types.attr;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Implements BGP MPLS protocol mask attribute.
+ */
+public class BgpLinkAttrMplsProtocolMask implements BGPValueType {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(BgpLinkAttrMplsProtocolMask.class);
+
+    public static final int ATTRLINK_MPLSPROTOMASK = 1094;
+    public static final int MASK_BYTE_LEN = 1;
+
+    private final boolean bLdp;
+    private final boolean bRsvpTe;
+
+    public static final byte FIRST_BIT = (byte) 0x80;
+    public static final byte SECOND_BIT = 0x40;
+
+    /**
+     * Constructor to initialize the values.
+     *
+     * @param bLdp boolean value true if LDP flag is available
+     * @param bRsvpTe boolean value true if RSVP TE information is available
+     */
+    public BgpLinkAttrMplsProtocolMask(boolean bLdp, boolean bRsvpTe) {
+        this.bLdp = bLdp;
+        this.bRsvpTe = bRsvpTe;
+    }
+
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param bLdp boolean value true if LDP flag is available
+     * @param bRsvpTe boolean value true if RSVP TE information is available
+     * @return object of BgpLinkAttrMplsProtocolMask
+     */
+    public static BgpLinkAttrMplsProtocolMask of(final boolean bLdp,
+                                                 final boolean bRsvpTe) {
+        return new BgpLinkAttrMplsProtocolMask(bLdp, bRsvpTe);
+    }
+
+    /**
+     * Reads the BGP link attributes MPLS protocol mask.
+     *
+     * @param cb Channel buffer
+     * @return object of type BgpLinkAttrMPLSProtocolMask
+     * @throws BGPParseException while parsing BgpLinkAttrMplsProtocolMask
+     */
+    public static BgpLinkAttrMplsProtocolMask read(ChannelBuffer cb)
+            throws BGPParseException {
+        boolean bLdp = false;
+        boolean bRsvpTe = false;
+
+        short lsAttrLength = cb.readShort();
+
+        if ((lsAttrLength != MASK_BYTE_LEN)
+                || (cb.readableBytes() < lsAttrLength)) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                                   BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                                   lsAttrLength);
+        }
+
+        byte flags = cb.readByte();
+
+        bLdp = ((flags & (byte) FIRST_BIT) == FIRST_BIT);
+        bRsvpTe = ((flags & (byte) SECOND_BIT) == SECOND_BIT);
+
+        return BgpLinkAttrMplsProtocolMask.of(bLdp, bRsvpTe);
+    }
+
+    /**
+     * Returns true if LDP bit is set.
+     *
+     * @return True if LDP information is set else false.
+     */
+    public boolean ldpBit() {
+        return bLdp;
+    }
+
+    /**
+     * Returns RSVP TE information.
+     *
+     * @return True if RSVP TE information is set else false.
+     */
+    public boolean rsvpBit() {
+        return bRsvpTe;
+    }
+
+    @Override
+    public short getType() {
+        return ATTRLINK_MPLSPROTOMASK;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(bLdp, bRsvpTe);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof BgpLinkAttrMplsProtocolMask) {
+            BgpLinkAttrMplsProtocolMask other = (BgpLinkAttrMplsProtocolMask) obj;
+            return Objects.equals(bLdp, other.bLdp)
+                    && Objects.equals(bRsvpTe, other.bRsvpTe);
+        }
+        return false;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        // TODO This will be implemented in the next version
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("bLdp", bLdp).add("bRsvpTe", bRsvpTe).toString();
+    }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java
new file mode 100755 (executable)
index 0000000..b45d95b
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types.attr;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Implements BGP link protection type attribute.
+ */
+public final class BgpLinkAttrProtectionType implements BGPValueType {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(BgpLinkAttrProtectionType.class);
+
+    public static final int ATTRLINK_PROTECTIONTYPE = 1093;
+    public static final int LINK_PROTECTION_LEN = 2;
+
+    public static final int EXTRA_TRAFFIC = 0x01;
+    public static final int UNPROTECTED = 0x02;
+    public static final int SHARED = 0x04;
+    public static final int DEDICATED_ONE_ISTO_ONE = 0x08;
+    public static final int DEDICATED_ONE_PLUS_ONE = 0x10;
+    public static final int ENHANCED = 0x20;
+
+    /* Link Protection type flags */
+    private final boolean bExtraTraffic;
+    private final boolean bUnprotected;
+    private final boolean bShared;
+    private final boolean bDedOneIstoOne;
+    private final boolean bDedOnePlusOne;
+    private final boolean bEnhanced;
+
+    /**
+     * Constructor to initialize the value.
+     *
+     * @param bExtraTraffic Extra Traffic
+     * @param bUnprotected Unprotected
+     * @param bShared Shared
+     * @param bDedOneIstoOne Dedicated 1:1
+     * @param bDedOnePlusOne Dedicated 1+1
+     * @param bEnhanced Enhanced
+     */
+    private BgpLinkAttrProtectionType(boolean bExtraTraffic,
+                                      boolean bUnprotected,
+                                      boolean bShared, boolean bDedOneIstoOne,
+                                      boolean bDedOnePlusOne, boolean bEnhanced) {
+        this.bExtraTraffic = bExtraTraffic;
+        this.bUnprotected = bUnprotected;
+        this.bShared = bShared;
+        this.bDedOneIstoOne = bDedOneIstoOne;
+        this.bDedOnePlusOne = bDedOnePlusOne;
+        this.bEnhanced = bEnhanced;
+    }
+
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param bExtraTraffic Extra Traffic
+     * @param bUnprotected Unprotected
+     * @param bShared Shared
+     * @param bDedOneIstoOne Dedicated 1:1
+     * @param bDedOnePlusOne Dedicated 1+1
+     * @param bEnhanced Enhanced
+     * @return object of BgpLinkAttrProtectionType
+     */
+    public static BgpLinkAttrProtectionType of(boolean bExtraTraffic,
+                                               boolean bUnprotected,
+                                               boolean bShared,
+                                               boolean bDedOneIstoOne,
+                                               boolean bDedOnePlusOne,
+                                               boolean bEnhanced) {
+        return new BgpLinkAttrProtectionType(bExtraTraffic, bUnprotected,
+                                             bShared, bDedOneIstoOne,
+                                             bDedOnePlusOne, bEnhanced);
+    }
+
+    /**
+     * Reads the BGP link attributes protection type.
+     *
+     * @param cb Channel buffer
+     * @return object of type BgpLinkAttrProtectionType
+     * @throws BGPParseException while parsing BgpLinkAttrProtectionType
+     */
+    public static BgpLinkAttrProtectionType read(ChannelBuffer cb)
+            throws BGPParseException {
+        short linkProtectionType;
+        byte higherByte;
+        short lsAttrLength = cb.readShort();
+
+        boolean bExtraTraffic;
+        boolean bUnprotected;
+        boolean bShared;
+        boolean bDedOneIstoOne;
+        boolean bDedOnePlusOne;
+        boolean bEnhanced;
+
+        if ((lsAttrLength != LINK_PROTECTION_LEN)
+                || (cb.readableBytes() < lsAttrLength)) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                                   BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                                   lsAttrLength);
+        }
+
+        linkProtectionType = cb.readShort();
+        higherByte = (byte) (linkProtectionType >> 8);
+
+        bExtraTraffic = ((higherByte & (byte) EXTRA_TRAFFIC) == EXTRA_TRAFFIC);
+        bUnprotected = ((higherByte & (byte) UNPROTECTED) == UNPROTECTED);
+        bShared = ((higherByte & (byte) SHARED) == SHARED);
+        bDedOneIstoOne = ((higherByte & (byte) DEDICATED_ONE_ISTO_ONE) == DEDICATED_ONE_ISTO_ONE);
+        bDedOnePlusOne = ((higherByte & (byte) DEDICATED_ONE_PLUS_ONE) == DEDICATED_ONE_PLUS_ONE);
+        bEnhanced = ((higherByte & (byte) ENHANCED) == ENHANCED);
+
+        return BgpLinkAttrProtectionType.of(bExtraTraffic, bUnprotected,
+                                            bShared, bDedOneIstoOne,
+                                            bDedOnePlusOne, bEnhanced);
+    }
+
+    /**
+     * Returns ExtraTraffic Bit.
+     *
+     * @return ExtraTraffic Bit
+     */
+    public boolean extraTraffic() {
+        return bExtraTraffic;
+    }
+
+    /**
+     * Returns Unprotected Bit.
+     *
+     * @return Unprotected Bit
+     */
+    public boolean unprotected() {
+        return bUnprotected;
+    }
+
+    /**
+     * Returns Shared Bit.
+     *
+     * @return Shared Bit
+     */
+    public boolean shared() {
+        return bShared;
+    }
+
+    /**
+     * Returns DedOneIstoOne Bit.
+     *
+     * @return DedOneIstoOne Bit
+     */
+    public boolean dedOneIstoOne() {
+        return bDedOneIstoOne;
+    }
+
+    /**
+     * Returns DedOnePlusOne Bit.
+     *
+     * @return DedOnePlusOne Bit
+     */
+    public boolean dedOnePlusOne() {
+        return bDedOnePlusOne;
+    }
+
+    /**
+     * Returns Enhanced Bit.
+     *
+     * @return Enhanced Bit
+     */
+    public boolean enhanced() {
+        return bEnhanced;
+    }
+
+    @Override
+    public short getType() {
+        return ATTRLINK_PROTECTIONTYPE;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(bExtraTraffic, bUnprotected, bShared,
+                            bDedOneIstoOne, bDedOnePlusOne, bEnhanced);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof BgpLinkAttrProtectionType) {
+            BgpLinkAttrProtectionType other = (BgpLinkAttrProtectionType) obj;
+            return Objects.equals(bExtraTraffic, other.bExtraTraffic)
+                    && Objects.equals(bUnprotected, other.bUnprotected)
+                    && Objects.equals(bShared, other.bShared)
+                    && Objects.equals(bDedOneIstoOne, other.bDedOneIstoOne)
+                    && Objects.equals(bDedOnePlusOne, other.bDedOnePlusOne)
+                    && Objects.equals(bEnhanced, other.bEnhanced);
+        }
+        return false;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        // TODO This will be implemented in the next version
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("bExtraTraffic", bExtraTraffic)
+                .add("bUnprotected", bUnprotected).add("bShared", bShared)
+                .add("bDedOneIstoOne", bDedOneIstoOne)
+                .add("bDedOnePlusOne", bDedOnePlusOne)
+                .add("bEnhanced", bEnhanced).toString();
+    }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java
new file mode 100755 (executable)
index 0000000..0678b81
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types.attr;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Implements BGP prefix metric attribute.
+ */
+public class BgpPrefixAttrMetric implements BGPValueType {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(BgpPrefixAttrMetric.class);
+
+    public static final int ATTR_PREFIX_METRIC = 1155;
+    public static final int ATTR_PREFIX_LEN = 4;
+
+    /* TE Default Metric */
+    private final int linkPfxMetric;
+
+    /**
+     * Constructor to initialize value.
+     *
+     * @param linkPfxMetric Prefix Metric
+     */
+    public BgpPrefixAttrMetric(int linkPfxMetric) {
+        this.linkPfxMetric = linkPfxMetric;
+    }
+
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param linkPfxMetric Prefix Metric
+     * @return object of BgpPrefixAttrMetric
+     */
+    public static BgpPrefixAttrMetric of(final int linkPfxMetric) {
+        return new BgpPrefixAttrMetric(linkPfxMetric);
+    }
+
+    /**
+     * Reads the Prefix Metric.
+     *
+     * @param cb ChannelBuffer
+     * @return object of BgpPrefixAttrMetric
+     * @throws BGPParseException while parsing BgpPrefixAttrMetric
+     */
+    public static BgpPrefixAttrMetric read(ChannelBuffer cb)
+            throws BGPParseException {
+        int linkPfxMetric;
+
+        short lsAttrLength = cb.readShort(); // 4 Bytes
+
+        if ((lsAttrLength != ATTR_PREFIX_LEN)
+                || (cb.readableBytes() < lsAttrLength)) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                                   BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                                   lsAttrLength);
+        }
+
+        linkPfxMetric = cb.readInt();
+
+        return BgpPrefixAttrMetric.of(linkPfxMetric);
+    }
+
+    /**
+     * Returns the Prefix Metric.
+     *
+     * @return Prefix Metric
+     */
+    public int attrPfxMetric() {
+        return linkPfxMetric;
+    }
+
+    @Override
+    public short getType() {
+        return ATTR_PREFIX_METRIC;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(linkPfxMetric);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof BgpPrefixAttrMetric) {
+            BgpPrefixAttrMetric other = (BgpPrefixAttrMetric) obj;
+            return Objects.equals(linkPfxMetric, other.linkPfxMetric);
+        }
+        return false;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        // TODO This will be implemented in the next version
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("linkPfxMetric", linkPfxMetric).toString();
+    }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java
new file mode 100755 (executable)
index 0000000..cf04304
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgpio.types.attr;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Implements BGP prefix OSPF Forwarding address attribute.
+ */
+public class BgpPrefixAttrOspfFwdAddr implements BGPValueType {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(BgpPrefixAttrOspfFwdAddr.class);
+
+    public static final int ATTR_PREFIX_OSPFFWDADDR = 1156;
+    public static final int IPV4_LEN = 4;
+    public static final int IPV6_LEN = 16;
+
+    /* OSPF Forwarding Address */
+    private final short lsAttrLength;
+    private final Ip4Address ip4RouterId;
+    private final Ip6Address ip6RouterId;
+
+    /**
+     * Constructor to initialize the value.
+     *
+     * @param lsAttrLength length of the IP address
+     * @param ip4RouterId Valid IPV4 address if length is 4 else null
+     * @param ip6RouterId Valid IPV6 address if length is 16 else null
+     */
+    public BgpPrefixAttrOspfFwdAddr(short lsAttrLength, Ip4Address ip4RouterId,
+                                    Ip6Address ip6RouterId) {
+        this.lsAttrLength = lsAttrLength;
+        this.ip4RouterId = ip4RouterId;
+        this.ip6RouterId = ip6RouterId;
+    }
+
+    /**
+     * Returns object of this class with specified values.
+     *
+     * @param lsAttrLength length of the IP address
+     * @param ip4RouterId Valid IPV4 address if length is 4 else null
+     * @param ip6RouterId Valid IPV6 address if length is 16 else null
+     * @return object of BgpPrefixAttrOspfFwdAddr
+     */
+    public static BgpPrefixAttrOspfFwdAddr of(final short lsAttrLength,
+                                              final Ip4Address ip4RouterId,
+                                              final Ip6Address ip6RouterId) {
+        return new BgpPrefixAttrOspfFwdAddr(lsAttrLength, ip4RouterId,
+                                            ip6RouterId);
+    }
+
+    /**
+     * Reads the OSPF Forwarding Address.
+     *
+     * @param cb ChannelBuffer
+     * @return object of BgpPrefixAttrOSPFFwdAddr
+     * @throws BGPParseException while parsing BgpPrefixAttrOspfFwdAddr
+     */
+    public static BgpPrefixAttrOspfFwdAddr read(ChannelBuffer cb)
+            throws BGPParseException {
+        short lsAttrLength;
+        byte[] ipBytes;
+        Ip4Address ip4RouterId = null;
+        Ip6Address ip6RouterId = null;
+
+        lsAttrLength = cb.readShort();
+        ipBytes = new byte[lsAttrLength];
+
+        if ((cb.readableBytes() < lsAttrLength)) {
+            Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                                   BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+                                   lsAttrLength);
+        }
+
+        cb.readBytes(ipBytes);
+
+        if (IPV4_LEN == lsAttrLength) {
+            ip4RouterId = Ip4Address.valueOf(ipBytes);
+        } else if (IPV6_LEN == lsAttrLength) {
+            ip6RouterId = Ip6Address.valueOf(ipBytes);
+        }
+
+        return BgpPrefixAttrOspfFwdAddr.of(lsAttrLength, ip4RouterId,
+                                           ip6RouterId);
+    }
+
+    /**
+     * Returns IPV4 Address of OSPF forwarding address.
+     *
+     * @return IPV4 address
+     */
+    public Ip4Address ospfv4FwdAddr() {
+        return ip4RouterId;
+    }
+
+    /**
+     * Returns IPV6 Address of OSPF forwarding address.
+     *
+     * @return IPV6 address
+     */
+    public Ip6Address ospfv6FwdAddr() {
+        return ip6RouterId;
+    }
+
+    /**
+     * Returns OSPF forwarding address length.
+     *
+     * @return length of the ip address
+     */
+    public short ospfFwdAddrLen() {
+        return lsAttrLength;
+    }
+
+    @Override
+    public short getType() {
+        return ATTR_PREFIX_OSPFFWDADDR;
+    }
+
+    @Override
+    public int hashCode() {
+        if (IPV4_LEN == lsAttrLength) {
+            return Objects.hash(ip4RouterId);
+        } else {
+            return Objects.hash(ip6RouterId);
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof BgpPrefixAttrOspfFwdAddr) {
+            BgpPrefixAttrOspfFwdAddr other = (BgpPrefixAttrOspfFwdAddr) obj;
+            if (IPV4_LEN == lsAttrLength) {
+                return Objects.equals(ip4RouterId, other.ip4RouterId);
+            } else {
+                return Objects.equals(ip6RouterId, other.ip6RouterId);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        // TODO This will be implemented in the next version
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        if (IPV4_LEN == lsAttrLength) {
+            return MoreObjects.toStringHelper(getClass()).omitNullValues()
+                    .add("ip4RouterId", ip4RouterId).toString();
+        } else {
+            return MoreObjects.toStringHelper(getClass()).omitNullValues()
+                    .add("ip6RouterId", ip6RouterId).toString();
+        }
+    }
+}
index 915aa58..bc13189 100644 (file)
@@ -16,6 +16,8 @@
 
 package org.onosproject.bgpio.util;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.Arrays;
 
 import org.jboss.netty.buffer.ChannelBuffer;
@@ -23,6 +25,8 @@ import org.jboss.netty.buffer.ChannelBuffers;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.primitives.Ints;
 
@@ -30,10 +34,11 @@ import com.google.common.primitives.Ints;
  * Provides methods to parse attribute header, validate length and type.
  */
 public class Validation {
+    private static final Logger log = LoggerFactory.getLogger(Validation.class);
     public static final byte FIRST_BIT = (byte) 0x80;
     public static final byte SECOND_BIT = 0x40;
     public static final byte THIRD_BIT = 0x20;
-    public static final byte FOURTH_BIT = 0x01;
+    public static final byte FOURTH_BIT = (byte) 0x10;
     public static final byte IPV4_SIZE = 4;
     private boolean firstBit;
     private boolean secondBit;
@@ -42,6 +47,16 @@ public class Validation {
     private int len;
     private boolean isShort;
 
+    /**
+     * Constructor to initialize parameter.
+     *
+     * @param firstBit in AttributeFlags
+     * @param secondBit in AttributeFlags
+     * @param thirdBit in AttributeFlags
+     * @param fourthBit in AttributeFlags
+     * @param len length
+     * @param isShort true if length is read as short otherwise false
+     */
     Validation(boolean firstBit, boolean secondBit, boolean thirdBit, boolean fourthBit, int len, boolean isShort) {
         this.firstBit = firstBit;
         this.secondBit = secondBit;
@@ -118,6 +133,25 @@ public class Validation {
         throw new BGPParseException(errorCode, subErrCode, buffer);
     }
 
+    /**
+     * Convert byte array to InetAddress.
+     *
+     * @param length of IpAddress
+     * @param cb channelBuffer
+     * @return InetAddress
+     */
+    public static InetAddress toInetAddress(int length, ChannelBuffer cb) {
+        byte[] address = new byte[length];
+        cb.readBytes(address, 0, length);
+        InetAddress ipAddress = null;
+        try {
+            ipAddress = InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+             log.info("InetAddress convertion failed");
+        }
+        return ipAddress;
+    }
+
     /**
      * Returns first bit in type flags.
      *
diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java
new file mode 100644 (file)
index 0000000..5f1411f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgp;
+
+import org.junit.Test;
+import org.onosproject.bgpio.types.attr.BgpAttrNodeFlagBitTlv;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Test for BGP attribute node flag.
+ */
+public class BgpAttrNodeFlagBitTlvTest {
+
+    private final boolean bOverloadBit = true;
+    private final boolean bAttachedBit = true;
+    private final boolean bExternalBit = true;
+    private final boolean bABRBit = true;
+
+    private final boolean bOverloadBit1 = false;
+    private final boolean bAttachedBit1 = false;
+    private final boolean bExternalBit1 = false;
+    private final boolean bABRBit1 = false;
+
+    private final BgpAttrNodeFlagBitTlv data = BgpAttrNodeFlagBitTlv
+            .of(bOverloadBit, bAttachedBit, bExternalBit, bABRBit);
+    private final BgpAttrNodeFlagBitTlv sameAsData = BgpAttrNodeFlagBitTlv
+            .of(bOverloadBit, bAttachedBit, bExternalBit, bABRBit);
+    private final BgpAttrNodeFlagBitTlv diffData = BgpAttrNodeFlagBitTlv
+            .of(bOverloadBit1, bAttachedBit1, bExternalBit1, bABRBit1);
+
+    @Test
+    public void basics() {
+
+        new EqualsTester().addEqualityGroup(data, sameAsData)
+        .addEqualityGroup(diffData).testEquals();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java
new file mode 100644 (file)
index 0000000..72ca5db
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgp;
+
+import org.junit.Test;
+import org.onlab.packet.Ip6Address;
+import org.onosproject.bgpio.types.attr.BgpAttrRouterIdV6;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Test for BGP attribute node router ID.
+ */
+public class BgpAttrRouterIdV6Test {
+
+    private final short sType = 1;
+    private final Ip6Address ip6RouterId = Ip6Address
+            .valueOf("2001:0db8:0a0b:12f0:0000:0000:0000:0001");
+
+    private final short sType1 = 2;
+    private final Ip6Address ip6RouterId1 = Ip6Address
+            .valueOf("2004:0db8:0a0b:12f0:0000:0000:0000:0004");
+
+    private final BgpAttrRouterIdV6 data = BgpAttrRouterIdV6.of(ip6RouterId,
+                                                                sType);
+    private final BgpAttrRouterIdV6 sameAsData = BgpAttrRouterIdV6
+            .of(ip6RouterId, sType);
+    private final BgpAttrRouterIdV6 diffData = BgpAttrRouterIdV6
+            .of(ip6RouterId1, sType1);
+
+    @Test
+    public void basics() {
+
+        new EqualsTester().addEqualityGroup(data, sameAsData)
+        .addEqualityGroup(diffData).testEquals();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java
new file mode 100644 (file)
index 0000000..32280a7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgp;
+
+import org.junit.Test;
+import org.onosproject.bgpio.types.attr.BgpLinkAttrIgpMetric;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Test for BGP link IGP metric attribute.
+ */
+public class BgpLinkAttrIgpMetricTest {
+    private final int val = 0x010203;
+    private final int valLen = 3;
+    private final int val1 = 0x01020304;
+    private final int val1Len = 4;
+
+    private final BgpLinkAttrIgpMetric data = BgpLinkAttrIgpMetric.of(val,
+                                                                      valLen);
+    private final BgpLinkAttrIgpMetric sameAsData = BgpLinkAttrIgpMetric
+            .of(val, valLen);
+    private final BgpLinkAttrIgpMetric diffData = BgpLinkAttrIgpMetric
+            .of(val1, val1Len);
+
+    @Test
+    public void basics() {
+        new EqualsTester().addEqualityGroup(data, sameAsData)
+        .addEqualityGroup(diffData).testEquals();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java
new file mode 100644 (file)
index 0000000..89f97a8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgp;
+
+import org.junit.Test;
+import org.onosproject.bgpio.types.attr.BgpLinkAttrProtectionType;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Test for MPLS protocol mask attribute.
+ */
+public class BgpLinkAttrProtectionTypeTest {
+    boolean bExtraTraffic = true;
+    boolean bUnprotected = true;
+    boolean bShared = true;
+    boolean bDedOneIstoOne = true;
+    boolean bDedOnePlusOne = true;
+    boolean bEnhanced = true;
+
+    boolean bExtraTraffic1 = false;
+    boolean bUnprotected1 = false;
+    boolean bShared1 = false;
+    boolean bDedOneIstoOne1 = false;
+    boolean bDedOnePlusOne1 = false;
+    boolean bEnhanced1 = false;
+
+    private final BgpLinkAttrProtectionType data = BgpLinkAttrProtectionType
+            .of(bExtraTraffic, bUnprotected, bShared, bDedOneIstoOne,
+                bDedOnePlusOne, bEnhanced);
+    private final BgpLinkAttrProtectionType sameAsData = BgpLinkAttrProtectionType
+            .of(bExtraTraffic, bUnprotected, bShared, bDedOneIstoOne,
+                bDedOnePlusOne, bEnhanced);
+    private final BgpLinkAttrProtectionType diffData = BgpLinkAttrProtectionType
+            .of(bExtraTraffic1, bUnprotected1, bShared1, bDedOneIstoOne1,
+                bDedOnePlusOne1, bEnhanced1);
+
+    @Test
+    public void basics() {
+
+        new EqualsTester().addEqualityGroup(data, sameAsData)
+        .addEqualityGroup(diffData).testEquals();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java
new file mode 100644 (file)
index 0000000..f736bea
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgp;
+
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
+import org.onosproject.bgpio.types.attr.BgpPrefixAttrOspfFwdAddr;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Test for BGP prefix metric attribute.
+ */
+public class BgpPrefixAttrOspfFwdAddrTest {
+
+    private final short lsAttrLength = 4;
+    private final Ip4Address ip4RouterId = Ip4Address.valueOf("192.168.1.1");
+    private final Ip6Address ip6RouterId = Ip6Address
+            .valueOf("2001:0db8:0a0b:12f0:0000:0000:0000:0001");
+
+    private final short lsAttrLength1 = 16;
+    private final Ip4Address ip4RouterId1 = Ip4Address.valueOf("192.168.1.2");
+    private final Ip6Address ip6RouterId1 = Ip6Address
+            .valueOf("1002:0db8:0a0b:12f0:0000:0000:0000:0002");
+
+    private final BgpPrefixAttrOspfFwdAddr data = BgpPrefixAttrOspfFwdAddr
+            .of(lsAttrLength, ip4RouterId, ip6RouterId);
+    private final BgpPrefixAttrOspfFwdAddr sameAsData = BgpPrefixAttrOspfFwdAddr
+            .of(lsAttrLength, ip4RouterId, ip6RouterId);
+    private final BgpPrefixAttrOspfFwdAddr diffData = BgpPrefixAttrOspfFwdAddr
+            .of(lsAttrLength1, ip4RouterId1, ip6RouterId1);
+
+    @Test
+    public void basics() {
+        new EqualsTester().addEqualityGroup(data, sameAsData)
+        .addEqualityGroup(diffData).testEquals();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java
new file mode 100755 (executable)
index 0000000..109197b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.bgp;
+
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.bgpio.types.NextHop;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Test for NextHop BGP Path Attribute.
+ */
+public class NextHopTest {
+    private final Ip4Address value1 = Ip4Address.valueOf("12.12.12.12");
+    private final Ip4Address value2 = Ip4Address.valueOf("12.12.12.13");
+    private final NextHop attr1 = new NextHop(value1);
+    private final NextHop sameAsAttr1 = new NextHop(value1);
+    private final NextHop attr2 = new NextHop(value2);
+
+    @Test
+    public void basics() {
+        new EqualsTester()
+        .addEqualityGroup(attr1, sameAsAttr1)
+        .addEqualityGroup(attr2)
+        .testEquals();
+    }
+}
\ No newline at end of file
index 1df2f04..03d25ce 100644 (file)
@@ -71,7 +71,10 @@ public final class Comparators {
     public static final Comparator<FlowRule> FLOW_RULE_COMPARATOR = new Comparator<FlowRule>() {
         @Override
         public int compare(FlowRule f1, FlowRule f2) {
-            return Long.valueOf(f1.id().value()).compareTo(f2.id().value());
+            int tableCompare = Integer.valueOf(f1.tableId()).compareTo(f2.tableId());
+            return (tableCompare == 0)
+                    ? Long.valueOf(f1.id().value()).compareTo(f2.id().value())
+                    : tableCompare;
         }
     };
 
index 57c4100..1049d90 100644 (file)
@@ -44,12 +44,12 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand {
     @Argument(index = 0, name = "ingressDevice",
               description = "Ingress Device/Port Description",
               required = true, multiValued = false)
-    String ingressDeviceString = null;
+    String ingressDeviceString = "";
 
     @Argument(index = 1, name = "egressDevice",
               description = "Egress Device/Port Description",
               required = true, multiValued = false)
-    String egressDeviceString = null;
+    String egressDeviceString = "";
 
     @Option(name = "-b", aliases = "--bidirectional",
             description = "If this argument is passed the optical link created will be bidirectional, " +
@@ -65,7 +65,6 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand {
                 "Connect point must be in \"deviceUri/portNumber\" format");
 
         DeviceId deviceId = DeviceId.deviceId(splitted[0]);
-
         DeviceService deviceService = get(DeviceService.class);
 
         List<Port> ports = deviceService.getPorts(deviceId);
@@ -87,7 +86,8 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand {
         ConnectPoint egress = createConnectPoint(egressDeviceString);
 
         if (ingress == null || egress == null) {
-            print("Could not create optical intent");
+            print("Invalid endpoint(s); could not create optical intent");
+            return;
         }
 
         DeviceService deviceService = get(DeviceService.class);
index de84f51..331cca1 100644 (file)
@@ -123,8 +123,14 @@ public class FlowsListCommand extends AbstractShellCommand {
         if (state != null && !state.equals("any")) {
             s = FlowEntryState.valueOf(state.toUpperCase());
         }
-        Iterable<Device> devices = uri == null ? deviceService.getDevices() :
-                Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri)));
+        Iterable<Device> devices = null;
+        if (uri == null) {
+            devices = deviceService.getDevices();
+        } else {
+            Device dev = deviceService.getDevice(DeviceId.deviceId(uri));
+            devices = (dev == null) ? deviceService.getDevices()
+                                    : Collections.singletonList(dev);
+        }
         for (Device d : devices) {
             if (s == null) {
                 rules = newArrayList(service.getFlowEntries(d.id()));
index afbcab8..b10621d 100644 (file)
@@ -46,7 +46,7 @@ import static com.google.common.collect.Lists.newArrayList;
 public class GroupsListCommand extends AbstractShellCommand {
 
     private static final String FORMAT =
-            "   id=%s, state=%s, bytes=%s, packets=%s, appId=%s";
+            "   id=%s, state=%s, type=%s, bytes=%s, packets=%s, appId=%s";
     private static final String BUCKET_FORMAT =
             "   id=%s, bucket=%s, bytes=%s, packets=%s, actions=%s";
 
@@ -121,7 +121,7 @@ public class GroupsListCommand extends AbstractShellCommand {
     private void printGroups(DeviceId deviceId, List<Group> groups) {
         print("deviceId=%s", deviceId);
         for (Group group : groups) {
-            print(FORMAT, group.id().id(), group.state(),
+            print(FORMAT, group.id().id(), group.state(), group.type(),
                   group.bytes(), group.packets(), group.appId().name());
             int i = 0;
             for (GroupBucket bucket:group.buckets().buckets()) {
index cf76feb..9bd5dd9 100644 (file)
@@ -19,7 +19,6 @@
         <command>
             <action class="org.onosproject.cli.SummaryCommand"/>
         </command>
-
         <command>
             <action class="org.onosproject.cli.security.ReviewCommand"/>
             <completers>
index 5f2b5ff..4794487 100644 (file)
@@ -30,9 +30,8 @@ public interface ClusterAdminService {
      * instance.
      *
      * @param nodes    set of nodes that form the cluster
-     * @param ipPrefix IP address prefix, e.g. 10.0.1.*
      */
-    void formCluster(Set<ControllerNode> nodes, String ipPrefix);
+    void formCluster(Set<ControllerNode> nodes);
 
     /**
      * Adds a new controller node to the cluster.
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java
deleted file mode 100644 (file)
index 1ee78b1..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.cluster;
-
-import java.util.Set;
-
-/**
- * Service for obtaining the static definition of a controller cluster.
- */
-public interface ClusterDefinitionService {
-
-    /**
-     * Returns the local controller node.
-     * @return local controller node
-     */
-    ControllerNode localNode();
-
-    /**
-     * Returns the set of seed nodes that should be used for discovering other members
-     * of the cluster.
-     * @return set of seed controller nodes
-     */
-    Set<ControllerNode> seedNodes();
-
-    /**
-     * Forms cluster configuration based on the specified set of node
-     * information. Assumes subsequent restart for the new configuration to
-     * take hold.
-     *
-     * @param nodes    set of nodes that form the cluster
-     * @param ipPrefix IP address prefix, e.g. 10.0.1.*
-     */
-    void formCluster(Set<ControllerNode> nodes, String ipPrefix);
-}
\ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java
new file mode 100644 (file)
index 0000000..e1eacfe
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Verify.verifyNotNull;
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+/**
+ * Cluster metadata.
+ * <p>
+ * Metadata specifies the attributes that define a ONOS cluster and comprises the collection
+ * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data
+ * {@link org.onosproject.cluster.Partition partitions}.
+ */
+public final class ClusterMetadata {
+
+    private String name;
+    private Set<ControllerNode> nodes;
+    private Set<Partition> partitions;
+
+    /**
+     * Returns a new cluster metadata builder.
+     * @return The cluster metadata builder.
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Returns the name of the cluster.
+     *
+     * @return cluster name
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Returns the collection of {@link org.onosproject.cluster.ControllerNode nodes} that make up the cluster.
+     * @return cluster nodes
+     */
+    public Collection<ControllerNode> getNodes() {
+        return this.nodes;
+    }
+
+    /**
+     * Returns the collection of data {@link org.onosproject.cluster.Partition partitions} that make up the cluster.
+     * @return collection of partitions.
+     */
+    public Collection<Partition> getPartitions() {
+        return this.partitions;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(ClusterMetadata.class)
+                .add("name", name)
+                .add("nodes", nodes)
+                .add("partitions", partitions)
+                .toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.deepHashCode(new Object[] {name, nodes, partitions});
+    }
+
+    /*
+     * Provide a deep quality check of the meta data (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object object) {
+
+        if (!ClusterMetadata.class.isInstance(object)) {
+            return false;
+        }
+        ClusterMetadata that = (ClusterMetadata) object;
+
+        if (!this.name.equals(that.name) || this.nodes.size() != that.nodes.size()
+                || this.partitions.size() != that.partitions.size()) {
+            return false;
+        }
+
+        return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty()
+                && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty();
+    }
+
+    /**
+     * Builder for a {@link ClusterMetadata} instance.
+     */
+    public static class Builder {
+
+        private final ClusterMetadata metadata;
+
+        public Builder() {
+            metadata = new ClusterMetadata();
+        }
+
+        /**
+         * Sets the cluster name, returning the cluster metadata builder for method chaining.
+         * @param name cluster name
+         * @return this cluster metadata builder
+         */
+        public Builder withName(String name) {
+            metadata.name = checkNotNull(name);
+            return this;
+        }
+
+        /**
+         * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining.
+         * @param controllerNodes collection of cluster nodes
+         * @return this cluster metadata builder
+         */
+        public Builder withControllerNodes(Collection<ControllerNode> controllerNodes) {
+            metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes));
+            return this;
+        }
+
+        /**
+         * Sets the collection of data partitions, returning the cluster metadata builder for method chaining.
+         * @param partitions collection of partitions
+         * @return this cluster metadata builder
+         */
+        public Builder withPartitions(Collection<Partition> partitions) {
+            metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
+            return this;
+        }
+
+        /**
+         * Builds the cluster metadata.
+         * @return cluster metadata
+         * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured
+         */
+        public ClusterMetadata build() {
+            verifyMetadata();
+            return metadata;
+        }
+
+        /**
+         * Validates the constructed metadata for semantic correctness.
+         * @throws VerifyException if the metadata is misconfigured.
+         */
+        private void verifyMetadata() {
+            verifyNotNull(metadata.getName(), "Cluster name must be specified");
+            verifyNotNull(metadata.getNodes(), "Cluster nodes must be specified");
+            verifyNotNull(metadata.getPartitions(), "Cluster partitions must be specified");
+            verify(!metadata.getNodes().isEmpty(), "Cluster nodes must not be empty");
+            verify(!metadata.getPartitions().isEmpty(), "Cluster nodes must not be empty");
+
+            // verify that partitions are constituted from valid cluster nodes.
+            boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id)
+                    .containsAll(metadata.getPartitions()
+                            .stream()
+                            .flatMap(r -> r.getMembers().stream())
+                            .collect(Collectors.toSet()));
+            verify(validPartitions, "Partition locations must be valid cluster nodes");
+        }
+    }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java
new file mode 100644 (file)
index 0000000..a0f461c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Describes a cluster metadata event.
+ */
+public class ClusterMetadataEvent extends AbstractEvent<ClusterMetadataEvent.Type, ClusterMetadata> {
+
+    /**
+     * Type of cluster metadata events.
+     */
+    public enum Type {
+        /**
+         * Signifies that the cluster metadata has changed.
+         */
+        METADATA_CHANGED,
+    }
+
+    /**
+     * Creates an event of a given type and for the specified metadata and the
+     * current time.
+     *
+     * @param type     cluster metadata event type
+     * @param metadata cluster metadata subject
+     */
+    public ClusterMetadataEvent(Type type, ClusterMetadata metadata) {
+        super(type, metadata);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified metadata and time.
+     *
+     * @param type     cluster metadata event type
+     * @param metadata cluster metadata subject
+     * @param time     occurrence time
+     */
+    public ClusterMetadataEvent(Type type, ClusterMetadata metadata, long time) {
+        super(type, metadata, time);
+    }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java
new file mode 100644 (file)
index 0000000..fdfaeed
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Entity capable of receiving cluster metadata related events.
+ */
+public interface ClusterMetadataEventListener  extends EventListener<ClusterMetadataEvent> {
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java
new file mode 100644 (file)
index 0000000..25a6df6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+/**
+ * Service for obtaining metadata information about the cluster.
+ */
+public interface ClusterMetadataService {
+
+    /**
+     * Returns the current cluster metadata.
+     * @return cluster metadata
+     */
+    ClusterMetadata getClusterMetadata();
+
+    /**
+     * Updates the cluster metadata.
+     * @param metadata new metadata
+     */
+    void setClusterMetadata(ClusterMetadata metadata);
+
+    /**
+     * Returns the local controller node representing this instance.
+     * @return local controller node
+     */
+    ControllerNode getLocalNode();
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java
new file mode 100644 (file)
index 0000000..7e83b5b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import java.util.Collection;
+
+import org.onosproject.store.Store;
+import org.onosproject.store.service.Versioned;
+
+/**
+ * Manages persistence of cluster metadata; not intended for direct use.
+ */
+public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, ClusterMetadataStoreDelegate> {
+
+    /**
+     * Returns the cluster metadata.
+     * <p>
+     * The returned metadata is versioned to aid determining if a metadata instance is more recent than another.
+     * @return cluster metadata
+     */
+    Versioned<ClusterMetadata> getClusterMetadata();
+
+    /**
+     * Updates the cluster metadata.
+     * @param metadata new metadata value
+     */
+    void setClusterMetadata(ClusterMetadata metadata);
+
+    // TODO: The below methods should move to a separate store interface that is responsible for
+    // tracking cluster partition operational state.
+
+    /**
+     * Sets a controller node as an active member of a partition.
+     * <p>
+     * Active members are those replicas that are up to speed with the rest of the system and are
+     * usually capable of participating in the replica state management activities in accordance with
+     * the data consistency and replication protocol in use.
+     * @param partitionId partition identifier
+     * @param nodeId id of controller node
+     */
+    void setActiveReplica(String partitionId, NodeId nodeId);
+
+    /**
+     * Removes a controller node as an active member for a partition.
+     * <p>
+     * Active members are those replicas that are up to speed with the rest of the system and are
+     * usually capable of participating in the replica state management activities in accordance with
+     * the data consistency and replication protocol in use.
+     * @param partitionId partition identifier
+     * @param nodeId id of controller node
+     */
+    void unsetActiveReplica(String partitionId, NodeId nodeId);
+
+    /**
+     * Returns the collection of controller nodes that are the active replicas for a partition.
+     * <p>
+     * Active members are those replicas that are up to speed with the rest of the system and are
+     * usually capable of participating in the replica state management activities in accordance with
+     * the data consistency and replication protocol in use.
+     * @param partitionId partition identifier
+     * @return identifiers of controller nodes that are the active replicas
+     */
+    Collection<NodeId> getActiveReplicas(String partitionId);
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java
new file mode 100644 (file)
index 0000000..b56b7a2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Cluster metadata store delegate abstraction.
+ */
+public interface ClusterMetadataStoreDelegate extends StoreDelegate<ClusterMetadataEvent> {
+}
\ No newline at end of file
index 68b490f..6cfb42c 100644 (file)
@@ -20,7 +20,7 @@ import java.util.Objects;
 /**
  * Controller cluster identity.
  */
-public class NodeId {
+public class NodeId implements Comparable<NodeId> {
 
     private final String id;
 
@@ -55,4 +55,9 @@ public class NodeId {
         return id;
     }
 
+    @Override
+    public int compareTo(NodeId that) {
+        return this.id.compareTo(that.id);
+    }
+
 }
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java
new file mode 100644 (file)
index 0000000..1eca4ae
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A data partition.
+ * <p>
+ * Partition represents a slice of the data space and is made up of a collection
+ * of {@link org.onosproject.cluster.ControllerNode nodes}
+ * that all maintain copies of this data.
+ */
+public class Partition {
+
+    private final String name;
+    private final Set<NodeId> members;
+
+    private Partition() {
+        name = null;
+        members = null;
+    }
+
+    public Partition(String name, Collection<NodeId> members) {
+        this.name = checkNotNull(name);
+        this.members = ImmutableSet.copyOf(checkNotNull(members));
+    }
+
+    /**
+     * Returns the partition name.
+     * <p>
+     * Each partition is identified by a unique name.
+     * @return partition name
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Returns the collection of controller node identifiers that make up this partition.
+     * @return collection of controller node identifiers
+     */
+    public Collection<NodeId> getMembers() {
+        return this.members;
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.deepHashCode(new Object[] {name, members});
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (other == null || !Partition.class.isInstance(other)) {
+            return false;
+        }
+
+        Partition that = (Partition) other;
+
+        if (!this.name.equals(that.name) || (this.members == null && that.members != null)
+                || (this.members != null && that.members == null) || this.members.size() != that.members.size()) {
+            return false;
+        }
+
+        return Sets.symmetricDifference(this.members, that.members).isEmpty();
+    }
+}
\ No newline at end of file
index 7f157e9..e3d6993 100644 (file)
@@ -35,6 +35,17 @@ public interface BridgeConfig extends HandlerBehaviour {
      */
     void addBridge(BridgeName bridgeName);
 
+    /**
+     * Adds a bridge with given bridge name and dpid, and sets the controller
+     * of the bridge with given controllers.
+     *
+     * @param bridgeName bridge name
+     * @param dpid dpid
+     * @param controllers list of controller
+     * @return true if succeeds, fail otherwise
+     */
+    boolean addBridge(BridgeName bridgeName, String dpid, List<ControllerInfo> controllers);
+
     /**
      * Remove a bridge.
      *
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java
new file mode 100644 (file)
index 0000000..54cbc7a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.behaviour;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+
+/**
+ * Provides access to the extension implemented by this driver.
+ */
+@Beta
+public interface ExtensionResolver extends HandlerBehaviour {
+
+    /**
+     * Gets an extension instruction instance of the specified type, if supported
+     * by the driver.
+     *
+     * @param type type of extension to get
+     * @return extension instruction
+     * @throws UnsupportedOperationException if the extension type is not
+     * supported by this driver
+     */
+    ExtensionInstruction getExtensionInstruction(ExtensionType type);
+}
index 7e79a57..e3b4c19 100644 (file)
@@ -31,6 +31,15 @@ public interface TunnelConfig extends HandlerBehaviour {
      */
     void createTunnel(TunnelDescription tunnel);
 
+    /**
+     * Creates a tunnel interface on a given bridge of this device.
+     *
+     * @param bridgeName bridge name
+     * @param tunnel tunnel description
+     * @return true if succeeds, false otherwise
+     */
+    boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel);
+
     /**
      * Removes a tunnel on this device.
      *
index 4416456..453a764 100644 (file)
  */
 package org.onosproject.net.flow;
 
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.ImmutableSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
+
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
@@ -27,13 +33,8 @@ import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.criteria.Criteria;
 import org.onosproject.net.flow.criteria.Criterion;
 
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeSet;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Default traffic selector implementation.
index 6174cef..6beeecc 100644 (file)
  */
 package org.onosproject.net.flow;
 
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Objects;
+
 import org.onlab.packet.EthType;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
@@ -25,16 +27,17 @@ import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.meter.MeterId;
 
-import java.util.List;
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 /**
  * Default traffic treatment implementation.
@@ -239,9 +242,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
                 case GROUP:
                 case QUEUE:
                 case L0MODIFICATION:
+                case L1MODIFICATION:
                 case L2MODIFICATION:
                 case L3MODIFICATION:
                 case L4MODIFICATION:
+                case EXTENSION:
                     current.add(instruction);
                     break;
                 case TABLE:
@@ -478,6 +483,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
             return add(Instructions.modUdpDst(port));
         }
 
+        @Override
+        public TrafficTreatment.Builder extension(ExtensionInstruction extension,
+                                                  DeviceId deviceId) {
+            return add(Instructions.extension(extension, deviceId));
+        }
+
         @Override
         public TrafficTreatment build() {
             if (deferred.size() == 0 && immediate.size() == 0
index c7fe8b8..b14ab99 100644 (file)
@@ -15,6 +15,8 @@
  */
 package org.onosproject.net.flow;
 
+import java.util.List;
+
 import org.onlab.packet.EthType;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
@@ -22,13 +24,13 @@ import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.meter.MeterId;
 
-import java.util.List;
-
 /**
  * Abstraction of network traffic treatment.
  */
@@ -412,6 +414,15 @@ public interface TrafficTreatment {
          */
         Builder setUdpDst(TpPort port);
 
+        /**
+         * Uses an extension treatment.
+         *
+         * @param extension extension treatment
+         * @param deviceId device ID
+         * @return a treatment builder
+         */
+        Builder extension(ExtensionInstruction extension, DeviceId deviceId);
+
         /**
          * Builds an immutable traffic treatment descriptor.
          * <p>
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java
deleted file mode 100644 (file)
index a77079c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.net.flow;
-
-import org.onosproject.net.PortNumber;
-
-/**
- * Abstraction of different kinds of treatment that can be applied to an
- * outbound packet.
- */
-public interface Treatment {
-
-    // TODO: implement these later: modifications, group
-    // TODO: elsewhere provide factory methods for some default treatments
-
-    /**
-     * Returns the port number where the packet should be emitted.
-     *
-     * @return output port number
-     */
-    PortNumber output();
-
-}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java
new file mode 100644 (file)
index 0000000..9f22f88
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.flow.instructions;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract implementation of the set/get property methods of ExtensionInstruction.
+ */
+public abstract class AbstractExtensionInstruction implements ExtensionInstruction {
+
+    private static final String INVALID_KEY = "Invalid property key: ";
+    private static final String INVALID_TYPE = "Given type does not match field type: ";
+
+    @Override
+    public <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException {
+        Class<?> clazz = this.getClass();
+        try {
+            Field field = clazz.getDeclaredField(key);
+            field.setAccessible(true);
+            field.set(this, value);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new ExtensionPropertyException(INVALID_KEY + key);
+        }
+    }
+
+    @Override
+    public <T> T getPropertyValue(String key) throws ExtensionPropertyException {
+        Class<?> clazz = this.getClass();
+        try {
+            Field field = clazz.getDeclaredField(key);
+            field.setAccessible(true);
+            @SuppressWarnings("unchecked")
+            T result = (T) field.get(this);
+            return result;
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new ExtensionPropertyException(INVALID_KEY + key);
+        } catch (ClassCastException e) {
+            throw new ExtensionPropertyException(INVALID_TYPE + key);
+        }
+    }
+
+    @Override
+    public List<String> getProperties() {
+        Class<?> clazz = this.getClass();
+
+        List<String> fields = new ArrayList<>();
+
+        for (Field field : clazz.getDeclaredFields()) {
+            fields.add(field.getName());
+        }
+
+        return fields;
+    }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java
new file mode 100644 (file)
index 0000000..89e0cc5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.flow.instructions;
+
+import java.util.List;
+
+/**
+ * An extensible instruction type.
+ */
+public interface ExtensionInstruction {
+
+    /**
+     * Gets the type of the extension instruction.
+     *
+     * @return type
+     */
+    ExtensionType type();
+
+    /**
+     * Sets a property on the extension instruction.
+     *
+     * @param key property key
+     * @param value value to set for the given key
+     * @param <T> class of the value
+     * @throws ExtensionPropertyException if the given key is not a valid
+     * property on this extension instruction
+     */
+    <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException;
+
+    /**
+     * Gets a property value of an extension instruction.
+     *
+     * @param key property key
+     * @param <T> class of the value
+     * @return value of the property
+     * @throws ExtensionPropertyException if the given key is not a valid
+     * property on this extension instruction
+     */
+    <T> T getPropertyValue(String key) throws ExtensionPropertyException;
+
+    /**
+     * Gets a list of all properties on the extension instruction.
+     *
+     * @return list of properties
+     */
+    List<String> getProperties();
+
+    /**
+     * Serialize the extension instruction to a byte array.
+     *
+     * @return byte array
+     */
+    byte[] serialize();
+
+    /**
+     * Deserialize the extension instruction from a byte array. The properties
+     * of this object will be overwritten with the data in the byte array.
+     *
+     * @param data input byte array
+     */
+    void deserialize(byte[] data);
+
+
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java
new file mode 100644 (file)
index 0000000..5750d09
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.flow.instructions;
+
+/**
+ * Exception indicating there was an error while setting/getting an extension
+ * instruction property.
+ */
+public class ExtensionPropertyException extends Exception {
+
+    public ExtensionPropertyException(String message) {
+        super(message);
+    }
+
+    public ExtensionPropertyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java
new file mode 100644 (file)
index 0000000..747a85b
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.flow.instructions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+/**
+ * Type of extension instructions.
+ */
+@Beta
+public final class ExtensionType {
+
+    /**
+     * A list of well-known named extension instruction type codes.
+     */
+    public enum ExtensionTypes {
+        // TODO fix type numbers to include experimenter id
+        NICIRA_SET_TUNNEL_DST(31);
+
+        private ExtensionType type;
+
+        /**
+         * Creates a new named extension instruction type.
+         *
+         * @param type type code
+         */
+        ExtensionTypes(int type) {
+            this.type = new ExtensionType(type);
+        }
+
+        /**
+         * Gets the extension type object for this named type code.
+         *
+         * @return extension type object
+         */
+        public ExtensionType type() {
+            return type;
+        }
+    }
+
+    private final int type;
+
+    /**
+     * Creates an extension type with the given int type code.
+     *
+     * @param type type code
+     */
+    public ExtensionType(int type) {
+        this.type = type;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ExtensionType) {
+            final ExtensionType that = (ExtensionType) obj;
+            return this.type == that.type;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(ExtensionType.class)
+                .add("type", type)
+                .toString();
+    }
+}
index 2f6a1cc..31ad80c 100644 (file)
@@ -92,7 +92,12 @@ public interface Instruction {
         /**
          * Signifies that the traffic should be modified in L4 way.
          */
-        L4MODIFICATION
+        L4MODIFICATION,
+
+        /**
+         * Signifies that an extension instruction will be used.
+         */
+        EXTENSION
     }
 
     /**
index 8868bf7..aad407c 100644 (file)
@@ -22,6 +22,7 @@ import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignal;
@@ -479,6 +480,20 @@ public final class Instructions {
         return new ModTransportPortInstruction(L4SubType.UDP_DST, port);
     }
 
+    /**
+     * Creates an extension instruction.
+     *
+     * @param extension extension instruction
+     * @param deviceId device ID
+     * @return extension instruction
+     */
+    public static ExtensionInstructionWrapper extension(ExtensionInstruction extension,
+                                                        DeviceId deviceId) {
+        checkNotNull(extension, "Extension instruction cannot be null");
+        checkNotNull(deviceId, "Device ID cannot be null");
+        return new ExtensionInstructionWrapper(extension, deviceId);
+    }
+
     /**
      *  Drop instruction.
      */
@@ -820,6 +835,59 @@ public final class Instructions {
         }
     }
 
+    /**
+     *  Extension instruction.
+     */
+    public static class ExtensionInstructionWrapper implements Instruction {
+        private final ExtensionInstruction extensionInstruction;
+        private final DeviceId deviceId;
+
+        ExtensionInstructionWrapper(ExtensionInstruction extension, DeviceId deviceId) {
+            extensionInstruction = extension;
+            this.deviceId = deviceId;
+        }
+
+        public ExtensionInstruction extensionInstruction() {
+            return extensionInstruction;
+        }
+
+        public DeviceId deviceId() {
+            return deviceId;
+        }
+
+        @Override
+        public Type type() {
+            return Type.EXTENSION;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(type().toString())
+                    .add("extension", extensionInstruction)
+                    .add("deviceId", deviceId)
+                    .toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type().ordinal(), extensionInstruction, deviceId);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof ExtensionInstructionWrapper) {
+                ExtensionInstructionWrapper that = (ExtensionInstructionWrapper) obj;
+                return Objects.equals(extensionInstruction, that.extensionInstruction)
+                        && Objects.equals(deviceId, that.deviceId);
+
+            }
+            return false;
+        }
+    }
+
 }
 
 
index 7b5924f..06305bf 100644 (file)
@@ -18,6 +18,7 @@ package org.onosproject.net.flowobjective;
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableList;
 import org.onosproject.core.ApplicationId;
+import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.Criteria;
 import org.onosproject.net.flow.criteria.Criterion;
 
@@ -46,6 +47,7 @@ public final class DefaultFilteringObjective implements FilteringObjective {
     private final int id;
     private final Operation op;
     private final Optional<ObjectiveContext> context;
+    private final TrafficTreatment meta;
 
     private DefaultFilteringObjective(Builder builder) {
         this.key = builder.key;
@@ -57,6 +59,7 @@ public final class DefaultFilteringObjective implements FilteringObjective {
         this.conditions = builder.conditions;
         this.op = builder.op;
         this.context = Optional.ofNullable(builder.context);
+        this.meta = builder.meta;
 
         this.id = Objects.hash(type, key, conditions, permanent,
                 timeout, appId, priority);
@@ -82,6 +85,12 @@ public final class DefaultFilteringObjective implements FilteringObjective {
         return id;
     }
 
+    @Override
+    public TrafficTreatment meta() {
+        return meta;
+    }
+
+
     @Override
     public int priority() {
         return priority;
@@ -135,6 +144,7 @@ public final class DefaultFilteringObjective implements FilteringObjective {
         private List<Criterion> conditions;
         private Operation op;
         private ObjectiveContext context;
+        private TrafficTreatment meta;
 
         @Override
         public Builder withKey(Criterion key) {
@@ -185,6 +195,12 @@ public final class DefaultFilteringObjective implements FilteringObjective {
             return this;
         }
 
+        @Override
+        public Builder setMeta(TrafficTreatment treatment) {
+            this.meta = treatment;
+            return this;
+        }
+
         @Override
         public FilteringObjective add() {
             conditions = listBuilder.build();
index 5830457..29257c6 100644 (file)
@@ -17,49 +17,54 @@ package org.onosproject.net.flowobjective;
 
 import com.google.common.annotations.Beta;
 import org.onosproject.core.ApplicationId;
+import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.Criterion;
 
 import java.util.Collection;
 
 /**
  * Represents a filtering flow objective. Each filtering flow objective
- * is made up of a key (criterion) to a set of criteria. Using this information
- * a pipeline aware driver will decide how this objective should be mapped
- * to the specific device pipeline. For example, consider the following
- * filtering objective:
- *
- * portX -&gt; {MAC1, IP1, MAC2}
- *
- * The driver could decide to pass L3 packet to the L3 table and L2 packets to
- * the L2 table for packets arriving on portX.
- *
- * Filtering objectives do not only represent what should be permitted into the
- * pipeline but can also be used to deny or drop unwanted packets by specifying
- * the appropriate type of filtering objective. It is also important to note
- * that submitting a filtering objective does not necessarily result in rules
- * programmed at the switch, the driver is free to decide when these rules are
- * programmed. For example, a filtering rule may only be programmed once a
- * corresponding forwarding objective has been received.
+ * is made up of a key (typically a PortCriterion) mapped to a set of criteria.
+ * Using this information, a pipeline aware driver will decide how this objective
+ * should be mapped to the device specific pipeline-tables in order to satisfy the
+ * filtering condition. For example, consider the following PERMIT filtering
+ * objective:
+ * <p>
+ * portX -&gt; {MAC1, VLAN1}
+ * <p>
+ * The driver could decide to pass packets to the MAC table or VLAN or PORT
+ * tables to ensure that only those packets arriving with the correct dst MAC
+ * and VLAN ids from Port X are allowed into the pipeline.
+ * <p>
+ * Filtering objectives of type PERMIT allow packets that match the key:criteria
+ * to enter the pipeline. As a result, the implication is that packets that don't
+ * match are automatically denied (dropped).
+ * <p>
+ * Filtering objectives of type DENY, are used to deny packets that would
+ * otherwise be permitted and forwarded through the pipeline (ie. those packets
+ * that make it through the PERMIT filters).
  */
 @Beta
 public interface FilteringObjective extends Objective {
 
     enum Type {
         /**
-         * Enables the filtering condition.
+         * Permits packets that match the filtering condition to be processed
+         * by the rest of the pipeline. Automatically denies packets that don't
+         * match the criteria.
          */
         PERMIT,
 
         /**
-         * Disables the filtering condition.
+         * Denies packets that make it through the permit filters.
          */
         DENY
     }
 
     /**
-     * Obtain the key for this filter.
+     * Obtain the key for this filter. The filter may or may not require a key.
      *
-     * @return a criterion
+     * @return a criterion, which could be null if no key was provided.
      */
     Criterion key();
 
@@ -77,6 +82,16 @@ public interface FilteringObjective extends Objective {
      */
     Collection<Criterion> conditions();
 
+    /**
+     * Auxiliary optional information provided to the device-driver.Typically
+     * conveys information about changes (treatments) to packets that are
+     * permitted into the pipeline by the PERMIT filtering condition.
+     *
+     * @return a treatment on the packets that make it through the PERMIT filters.
+     *         Value may be null if no meta information is provided.
+     */
+    TrafficTreatment meta();
+
     /**
      * Builder of Filtering objective entities.
      */
@@ -112,12 +127,21 @@ public interface FilteringObjective extends Objective {
          */
         Builder deny();
 
+        /**
+         * Set meta information about this filtering condition set.
+         *
+         * @param treatment traffic treatment to use
+         * @return a filtering builder
+         */
+        Builder setMeta(TrafficTreatment treatment);
+
         /**
          * Assigns an application id.
          *
          * @param appId an application id
          * @return a filtering builder
          */
+        @Override
         Builder fromApp(ApplicationId appId);
 
         /**
index 6efd3e7..9d942ee 100644 (file)
@@ -139,6 +139,20 @@ public final class DefaultGroupBucket implements GroupBucket, StoredGroupBucketE
                                       watchGroup);
     }
 
+    /**
+     * Creates all group bucket.
+     *
+     * @param treatment traffic treatment associated with group bucket
+     * @return all group bucket object
+     */
+    public static GroupBucket createAllGroupBucket(TrafficTreatment treatment) {
+        return new DefaultGroupBucket(GroupDescription.Type.ALL,
+                                      treatment,
+                                      (short) -1,
+                                      null,
+                                      null);
+    }
+
     @Override
     public GroupDescription.Type type() {
         return this.type;
index bd4219a..c146724 100644 (file)
@@ -17,11 +17,15 @@ package org.onosproject.net.intent;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.constraint.LinkTypeConstraint;
 
 import java.util.List;
 
@@ -33,6 +37,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
 @Beta
 public final class HostToHostIntent extends ConnectivityIntent {
 
+    static final LinkTypeConstraint NOT_OPTICAL = new LinkTypeConstraint(false, Link.Type.OPTICAL);
+
     private final HostId one;
     private final HostId two;
 
@@ -115,6 +121,15 @@ public final class HostToHostIntent extends ConnectivityIntent {
          */
         public HostToHostIntent build() {
 
+            List<Constraint> theConstraints = constraints;
+            // If not-OPTICAL constraint hasn't been specified, add them
+            if (!constraints.contains(NOT_OPTICAL)) {
+                theConstraints = ImmutableList.<Constraint>builder()
+                                    .add(NOT_OPTICAL)
+                                    .addAll(constraints)
+                                    .build();
+            }
+
             return new HostToHostIntent(
                     appId,
                     key,
@@ -122,7 +137,7 @@ public final class HostToHostIntent extends ConnectivityIntent {
                     two,
                     selector,
                     treatment,
-                    constraints,
+                    theConstraints,
                     priority
             );
         }
index 18baafc..0344acb 100644 (file)
@@ -28,7 +28,7 @@ import java.util.Objects;
  */
 // TODO maybe pull this up to utils
 @Beta
-public abstract class Key {
+public abstract class Key implements Comparable<Key> {
 
     //TODO consider making this a HashCode object (worry about performance)
     private final long hash;
@@ -117,6 +117,12 @@ public abstract class Key {
                     Objects.equals(this.appId, other.appId) &&
                     Objects.equals(this.key, other.key);
         }
+
+        @Override
+        public int compareTo(Key o) {
+            StringKey sk = (StringKey) o;
+            return this.key.compareTo(sk.key);
+        }
     }
 
     private static final class LongKey extends Key {
@@ -157,6 +163,13 @@ public abstract class Key {
                     this.key == other.key &&
                     Objects.equals(this.appId, other.appId);
         }
+
+        @Override
+        public int compareTo(Key o) {
+            Long myKey = key;
+            Long otherKey = ((LongKey) o).key;
+            return myKey.compareTo(otherKey);
+        }
     }
 }
 
index 43b8e4b..20ccb55 100644 (file)
@@ -16,6 +16,8 @@
 package org.onosproject.net.intent.constraint;
 
 import com.google.common.annotations.Beta;
+
+import org.onlab.util.DataRateUnit;
 import org.onosproject.net.Link;
 import org.onosproject.net.resource.link.BandwidthResource;
 import org.onosproject.net.resource.link.BandwidthResourceRequest;
@@ -32,7 +34,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
  * Constraint that evaluates links based on available bandwidths.
  */
 @Beta
-public class BandwidthConstraint extends BooleanConstraint {
+public final class BandwidthConstraint extends BooleanConstraint {
 
     private final BandwidthResource bandwidth;
 
@@ -45,6 +47,17 @@ public class BandwidthConstraint extends BooleanConstraint {
         this.bandwidth = checkNotNull(bandwidth, "Bandwidth cannot be null");
     }
 
+    /**
+     * Creates a new bandwidth constraint.
+     *
+     * @param v         required amount of bandwidth
+     * @param unit      {@link DataRateUnit} of {@code v}
+     * @return  {@link BandwidthConstraint} instance with given bandwidth requirement
+     */
+    public static BandwidthConstraint of(double v, DataRateUnit unit) {
+        return new BandwidthConstraint(BandwidthResource.of(v, unit));
+    }
+
     // Constructor for serialization
     private BandwidthConstraint() {
         this.bandwidth = null;
index 82d8474..ad684c8 100644 (file)
@@ -152,6 +152,14 @@ public interface ResourceService {
      */
     Collection<ResourceAllocation> getResourceAllocations(ResourceConsumer consumer);
 
+    /**
+     * Returns resource paths that point available child resources under the specified resource path.
+     *
+     * @param parent parent resource path
+     * @return available resource paths under the specified resource path
+     */
+    Collection<ResourcePath> getAvailableResources(ResourcePath parent);
+
     /**
      * Returns the availability of the specified resource.
      *
index 5a034b4..2cab9d4 100644 (file)
@@ -91,6 +91,14 @@ public interface ResourceStore {
      */
     Collection<ResourcePath> getResources(ResourceConsumer consumer);
 
+    /**
+     * Returns a collection of the child resources of the specified parent.
+     *
+     * @param parent parent of the resource to be returned
+     * @return a collection of the child resources of the specified resource
+     */
+    Collection<ResourcePath> getChildResources(ResourcePath parent);
+
     /**
      * Returns a collection of the resources which are children of the specified parent and
      * whose type is the specified class.
index fe21e04..0bfb379 100644 (file)
@@ -16,7 +16,7 @@
 package org.onosproject.net.resource.link;
 
 import org.onlab.util.Bandwidth;
-
+import org.onlab.util.DataRateUnit;
 import java.util.Objects;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -42,6 +42,17 @@ public final class BandwidthResource implements LinkResource {
         this.bandwidth = null;
     }
 
+    /**
+     * Creates a new bandwidth resource.
+     *
+     * @param v         amount of bandwidth to request
+     * @param unit      {@link DataRateUnit} of {@code v}
+     * @return  {@link BandwidthResource} instance with given bandwidth
+     */
+    public static BandwidthResource of(double v, DataRateUnit unit) {
+        return new BandwidthResource(Bandwidth.of(v, unit));
+    }
+
     /**
      * Returns bandwidth as a double value.
      *
index 5153aeb..f8e143a 100644 (file)
 package org.onosproject.net.resource.link;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
 import org.onlab.util.Bandwidth;
 import org.onosproject.net.Link;
 import org.onosproject.net.intent.Constraint;
 import org.onosproject.net.intent.IntentId;
 
-import com.google.common.collect.ImmutableSet;
-
 import org.onosproject.net.intent.constraint.BandwidthConstraint;
 import org.onosproject.net.intent.constraint.LambdaConstraint;
 import org.onosproject.net.resource.ResourceRequest;
 import org.onosproject.net.resource.ResourceType;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Implementation of {@link LinkResourceRequest}.
  */
 public final class DefaultLinkResourceRequest implements LinkResourceRequest {
 
     private final IntentId intentId;
-    private final Collection<Link> links;
-    private final Set<ResourceRequest> resources;
+    protected final Map<Link, Set<ResourceRequest>> requests;
 
     /**
-     * Creates a new link resource request with the given ID, links, and
-     * resource requests.
+     * Creates a new link resource request with the specified Intent ID,
+     * and resource requests over links.
      *
-     * @param intentId intent ID related to this request
-     * @param links a set of links for the request
-     * @param resources a set of resources to be requested
+     * @param intentId intent ID associated with this request
+     * @param requests resource requests over links
      */
-    private DefaultLinkResourceRequest(IntentId intentId,
-            Collection<Link> links,
-            Set<ResourceRequest> resources) {
-        this.intentId = intentId;
-        this.links = ImmutableSet.copyOf(links);
-        this.resources = ImmutableSet.copyOf(resources);
+    private DefaultLinkResourceRequest(IntentId intentId, Map<Link, Set<ResourceRequest>> requests) {
+        this.intentId = checkNotNull(intentId);
+        this.requests = checkNotNull(ImmutableMap.copyOf(requests));
     }
 
-
     @Override
     public ResourceType type() {
         return null;
@@ -70,12 +69,19 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
 
     @Override
     public Collection<Link> links() {
-        return links;
+        return requests.keySet();
     }
 
     @Override
     public Set<ResourceRequest> resources() {
-        return resources;
+        return requests.values().stream()
+                .flatMap(Collection::stream)
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Set<ResourceRequest> resources(Link link) {
+        return requests.get(link);
     }
 
     /**
@@ -95,8 +101,7 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
      */
     public static final class Builder implements LinkResourceRequest.Builder {
         private IntentId intentId;
-        private Collection<Link> links;
-        private Set<ResourceRequest> resources;
+        private Map<Link, Set<ResourceRequest>> requests;
 
         /**
          * Creates a new link resource request.
@@ -106,18 +111,33 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
          */
         private Builder(IntentId intentId, Collection<Link> links) {
             this.intentId = intentId;
-            this.links = links;
-            this.resources = new HashSet<>();
+            this.requests = new HashMap<>();
+            for (Link link : links) {
+                requests.put(link, new HashSet<>());
+            }
         }
 
         /**
          * Adds lambda request.
          *
          * @return self
+         * @deprecated in Emu Release
          */
+        @Deprecated
         @Override
         public Builder addLambdaRequest() {
-            resources.add(new LambdaResourceRequest());
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new LambdaResourceRequest());
+            }
+            return this;
+        }
+
+        @Beta
+        @Override
+        public LinkResourceRequest.Builder addLambdaRequest(LambdaResource lambda) {
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new LambdaResourceRequest(lambda));
+            }
             return this;
         }
 
@@ -125,10 +145,36 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
          * Adds Mpls request.
          *
          * @return self
+         * @deprecated in Emu Release
          */
+        @Deprecated
         @Override
         public Builder addMplsRequest() {
-            resources.add(new MplsLabelResourceRequest());
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new MplsLabelResourceRequest());
+            }
+            return this;
+        }
+
+        @Beta
+        @Override
+        public Builder addMplsRequest(MplsLabel label) {
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new MplsLabelResourceRequest(label));
+            }
+            return this;
+        }
+
+        @Beta
+        @Override
+        public LinkResourceRequest.Builder addMplsRequest(Map<Link, MplsLabel> labels) {
+            for (Link link : labels.keySet()) {
+                if (!requests.containsKey(link)) {
+                    requests.put(link, new HashSet<>());
+                }
+                requests.get(link).add(new MplsLabelResourceRequest(labels.get(link)));
+            }
+
             return this;
         }
 
@@ -140,7 +186,9 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
          */
         @Override
         public Builder addBandwidthRequest(double bandwidth) {
-            resources.add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth))));
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth))));
+            }
             return this;
         }
 
@@ -162,13 +210,13 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
          */
         @Override
         public LinkResourceRequest build() {
-            return new DefaultLinkResourceRequest(intentId, links, resources);
+            return new DefaultLinkResourceRequest(intentId, requests);
         }
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(intentId, links);
+        return Objects.hash(intentId, links());
     }
 
     @Override
@@ -181,6 +229,6 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
         }
         final DefaultLinkResourceRequest other = (DefaultLinkResourceRequest) obj;
         return Objects.equals(this.intentId, other.intentId)
-                && Objects.equals(this.links, other.links);
+                && Objects.equals(this.links(), other.links());
     }
 }
index b0391f5..d264d5e 100644 (file)
  */
 package org.onosproject.net.resource.link;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import org.onosproject.net.resource.ResourceRequest;
 import org.onosproject.net.resource.ResourceType;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Representation of a request for lambda resource.
  */
 public class LambdaResourceRequest implements ResourceRequest {
 
+    private final LambdaResource lambda;
+
+    /**
+     * Constructs a request specifying the given lambda.
+     *
+     * @param lambda lambda to be requested
+     */
+    @Beta
+    public LambdaResourceRequest(LambdaResource lambda) {
+        this.lambda = checkNotNull(lambda);
+    }
+
+    /**
+     * Constructs a request asking an arbitrary available lambda.
+     *
+     * @deprecated in Emu Release
+     */
+    @Deprecated
+    public LambdaResourceRequest() {
+        this.lambda = null;
+    }
+
+    /**
+     * Returns the lambda this request expects.
+     *
+     * @return the lambda this request expects
+     */
+    @Beta
+    public LambdaResource lambda() {
+        return lambda;
+    }
+
     @Override
     public ResourceType type() {
         return ResourceType.LAMBDA;
@@ -32,6 +67,7 @@ public class LambdaResourceRequest implements ResourceRequest {
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
+                .add("lambda", lambda)
                 .toString();
     }
 }
index 8023a92..37622e7 100644 (file)
 package org.onosproject.net.resource.link;
 
 import java.util.Collection;
+import java.util.Map;
 import java.util.Set;
 
+import com.google.common.annotations.Beta;
 import org.onosproject.net.Link;
 import org.onosproject.net.intent.Constraint;
 import org.onosproject.net.intent.IntentId;
@@ -49,23 +51,63 @@ public interface LinkResourceRequest extends ResourceRequest {
      */
     Set<ResourceRequest> resources();
 
+    /**
+     * Returns the set of resource request against the specified link.
+     *
+     * @param link link whose associated resource request is to be returned
+     * @return set of resource request against the specified link
+     */
+    @Beta
+    Set<ResourceRequest> resources(Link link);
+
     /**
      * Builder of link resource request.
      */
     interface Builder {
-         /**
+        /**
          * Adds lambda request.
          *
          * @return self
+         * @deprecated in Emu Release
          */
+        @Deprecated
         Builder addLambdaRequest();
 
         /**
-        * Adds MPLS request.
-        *
-        * @return self
-        */
-       Builder addMplsRequest();
+         * Adds lambda request.
+         *
+         * @param lambda lambda to be requested
+         * @return self
+         */
+        @Beta
+        Builder addLambdaRequest(LambdaResource lambda);
+
+        /**
+         * Adds MPLS request.
+         *
+         * @return self
+         * @deprecated in Emu Release
+         */
+        @Deprecated
+        Builder addMplsRequest();
+
+        /**
+         * Adds MPLS request.
+         *
+         * @param label MPLS label to be requested
+         * @return self
+         */
+        @Beta
+        Builder addMplsRequest(MplsLabel label);
+
+        /**
+         * Adds MPLS request against the specified links.
+         *
+         * @param labels MPLS labels to be requested against links
+         * @return self
+         */
+        @Beta
+        Builder addMplsRequest(Map<Link, MplsLabel> labels);
 
         /**
          * Adds bandwidth request with bandwidth value.
index 6dc04df..71ea7e1 100644 (file)
@@ -22,7 +22,10 @@ import org.onosproject.net.resource.ResourceRequest;
 
 /**
  * Service for providing link resource allocation.
+ *
+ * @deprecated in Emu Release
  */
+@Deprecated
 public interface LinkResourceService
     extends ListenerService<LinkResourceEvent, LinkResourceListener> {
 
@@ -31,14 +34,18 @@ public interface LinkResourceService
      *
      * @param req resources to be allocated
      * @return allocated resources
+     * @deprecated in Emu Release
      */
+    @Deprecated
     LinkResourceAllocations requestResources(LinkResourceRequest req);
 
     /**
      * Releases resources.
      *
      * @param allocations resources to be released
+     * @deprecated in Emu Release
      */
+    @Deprecated
     void releaseResources(LinkResourceAllocations allocations);
 
     /**
@@ -47,7 +54,9 @@ public interface LinkResourceService
      * @param req            updated resource request
      * @param oldAllocations old resource allocations
      * @return new resource allocations
+     * @deprecated in Emu Release
      */
+    @Deprecated
     LinkResourceAllocations updateResources(LinkResourceRequest req,
                                             LinkResourceAllocations oldAllocations);
 
@@ -55,7 +64,9 @@ public interface LinkResourceService
      * Returns all allocated resources.
      *
      * @return allocated resources
+     * @deprecated in Emu Release
      */
+    @Deprecated
     Iterable<LinkResourceAllocations> getAllocations();
 
     /**
@@ -63,7 +74,9 @@ public interface LinkResourceService
      *
      * @param link a target link
      * @return allocated resources
+     * @deprecated in Emu Release
      */
+    @Deprecated
     Iterable<LinkResourceAllocations> getAllocations(Link link);
 
     /**
@@ -71,7 +84,9 @@ public interface LinkResourceService
      *
      * @param intentId the target Intent's id
      * @return allocated resources for Intent
+     * @deprecated in Emu Release
      */
+    @Deprecated
     LinkResourceAllocations getAllocations(IntentId intentId);
 
     /**
@@ -79,7 +94,9 @@ public interface LinkResourceService
      *
      * @param link a target link
      * @return available resources for the target link
+     * @deprecated in Emu Release
      */
+    @Deprecated
     Iterable<ResourceRequest> getAvailableResources(Link link);
 
     /**
@@ -88,7 +105,9 @@ public interface LinkResourceService
      * @param link        a target link
      * @param allocations allocations to be included as available
      * @return available resources for the target link
+     * @deprecated in Emu Release
      */
+    @Deprecated
     Iterable<ResourceRequest> getAvailableResources(Link link,
                                                     LinkResourceAllocations allocations);
 
index 0a03f45..01a048b 100644 (file)
  */
 package org.onosproject.net.resource.link;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import org.onosproject.net.resource.ResourceRequest;
 import org.onosproject.net.resource.ResourceType;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Representation of a request for lambda resource.
  */
 public class MplsLabelResourceRequest implements ResourceRequest {
 
+    private final MplsLabel mplsLabel;
+
+    /**
+     * Constructs a request specifying the given MPLS label.
+     *
+     * @param mplsLabel MPLS label to be requested
+     */
+    @Beta
+    public MplsLabelResourceRequest(MplsLabel mplsLabel) {
+        this.mplsLabel = checkNotNull(mplsLabel);
+    }
+
+    /**
+     * Constructs a request asking an arbitrary available MPLS label.
+     *
+     * @deprecated in Emu Release
+     */
+    @Deprecated
+    public MplsLabelResourceRequest() {
+        this.mplsLabel = null;
+    }
+
+    /**
+     * Returns the MPLS label this request expects.
+     *
+     * @return the MPLS label this request expects
+     */
+    @Beta
+    public MplsLabel mplsLabel() {
+        return mplsLabel;
+    }
+
     @Override
     public ResourceType type() {
         return ResourceType.MPLS_LABEL;
@@ -32,6 +67,7 @@ public class MplsLabelResourceRequest implements ResourceRequest {
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
+                .add("mplsLabel", mplsLabel)
                 .toString();
     }
 }
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java
new file mode 100644 (file)
index 0000000..09065de
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence;
+
+/**
+ * Service that allows for the creation of local disk backed map for instance specific values that persist across
+ * restarts. Empty maps and sets are deleted on shutdown.
+ */
+public interface PersistenceService {
+    /**
+     * A builder for the creation of local persistent maps backed by disk.
+     *
+     * @param <K> the type of keys in this map
+     * @param <V> the type of values in this map
+     * @return a persistent map builder
+     */
+    <K, V> PersistentMapBuilder<K, V> persistentMapBuilder();
+
+    /**
+     * A builder for the creation of local persistent sets backed by disk.
+     *
+     * @param <E> the type of the elements
+     * @return a persistent set builder
+     */
+    <E> PersistentSetBuilder<E> persistentSetBuilder();
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java
new file mode 100644 (file)
index 0000000..c3c855e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence;
+
+
+import org.onosproject.store.service.Serializer;
+
+import java.util.Map;
+
+/**
+ * The interface for a persistent map builder for use with mapDB.
+ */
+public interface PersistentMapBuilder<K, V> {
+
+    /**
+     * Sets the name of this map.
+     * @param name the string name of this map
+     * @return a persistent map builder with the name option now set
+     */
+    PersistentMapBuilder<K, V> withName(String name);
+
+    /**
+     * Sets the key serializer to be used to serialize this map, this is a required parameter.
+     * @param serializer the serializer to be used for keys
+     * @return a persistent map builder with the key serializer set
+     */
+    PersistentMapBuilder<K, V> withSerializer(Serializer serializer);
+
+    /**
+     * Validates the map settings and then builds this map in the database.  Throws an exception if invalid settings
+     * are found.
+     * @return The map that was created
+     */
+    Map<K, V> build();
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java
new file mode 100644 (file)
index 0000000..851872c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence;
+
+import org.onosproject.store.service.Serializer;
+
+import java.util.Set;
+
+/**
+ * The default interface for the persistent set builder for use with mapDB.
+ */
+public interface PersistentSetBuilder<E> {
+
+    /**
+     * Sets the name of this set.
+     * @param name the string name of this set
+     * @return a persistent set builder with the name option now set
+     */
+    PersistentSetBuilder<E> withName(String name);
+
+    /**
+     * Sets the serializer to be used to serialize this set, this is a required parameter.
+     * @param serializer the serializer to be used
+     * @return a persistent set builder with the serializer set
+     */
+    PersistentSetBuilder<E> withSerializer(Serializer serializer);
+
+    /**
+     * Validates the set settings and then builds this map in the database.  Throws an exception if invalid settings
+     * are found.
+     * @return The set that was created
+     */
+    Set<E> build();
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java
new file mode 100644 (file)
index 0000000..6e11a5e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Persistence service and builders.
+ */
+package org.onosproject.persistence;
index 94942e2..ef97253 100644 (file)
@@ -56,9 +56,9 @@ public interface TransactionContext {
      * Commits a transaction that was previously started thereby making its changes permanent
      * and externally visible.
      *
-     * @throws TransactionException if transaction fails to commit
+     * @return true if this transaction succeeded, otherwise false.
      */
-    void commit();
+    boolean commit();
 
     /**
      * Aborts any changes made in this transaction context and discarding all locally cached updates.
index e0d7d23..88796de 100644 (file)
@@ -16,6 +16,8 @@
 
 package org.onosproject.ui;
 
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
 import org.onosproject.ui.topo.PropertyPanel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -105,8 +107,9 @@ public class UiTopoOverlay {
      * This default implementation does nothing.
      *
      * @param pp property panel model of summary data
+     * @param deviceId device id
      */
-    public void modifyDeviceDetails(PropertyPanel pp) {
+    public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) {
     }
 
     /**
@@ -115,7 +118,8 @@ public class UiTopoOverlay {
      * This default implementation does nothing.
      *
      * @param pp property panel model of summary data
+     * @param hostId host id
      */
-    public void modifyHostDetails(PropertyPanel pp) {
+    public void modifyHostDetails(PropertyPanel pp, HostId hostId) {
     }
 }
index 0e1c248..f7947a7 100644 (file)
@@ -27,6 +27,7 @@ public final class AppIdFormatter extends AbstractCellFormatter {
     // non-instantiable
     private AppIdFormatter() { }
 
+    // NOTE: do not change this format; we parse it on the client side.
     @Override
     protected String nonNullFormat(Object value) {
         ApplicationId appId = (ApplicationId) value;
index 7b51711..4edb671 100644 (file)
@@ -40,7 +40,7 @@ public final class NodeBadge {
             return "{" + code + "}";
         }
 
-        /** Returns the status code in string form. */
+        /* Returns the status code in string form. */
         public String code() {
             return code;
         }
index 3f7650e..c3a9547 100644 (file)
 package org.onosproject.net.intent;
 
 import org.junit.Test;
+import org.onlab.util.DataRateUnit;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.HostId;
 import org.onosproject.net.flow.TrafficSelector;
-
+import org.onosproject.net.intent.constraint.BandwidthConstraint;
+import com.google.common.collect.ImmutableList;
 import com.google.common.testing.EqualsTester;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
 import static org.hamcrest.Matchers.is;
 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
 import static org.onosproject.net.NetTestTools.hid;
@@ -102,6 +105,55 @@ public class HostToHostIntentTest extends IntentTest {
                 .testEquals();
     }
 
+    @Test
+    public void testImplicitConstraintsAreAdded() {
+        final Constraint other = BandwidthConstraint.of(1, DataRateUnit.GBPS);
+        final HostToHostIntent intent = HostToHostIntent.builder()
+                .appId(APPID)
+                .one(id1)
+                .two(id2)
+                .selector(selector)
+                .treatment(treatment)
+                .constraints(ImmutableList.of(other))
+                .build();
+
+        assertThat(intent.constraints(), hasItem(HostToHostIntent.NOT_OPTICAL));
+    }
+
+    @Test
+    public void testImplicitConstraints() {
+        final HostToHostIntent implicit = HostToHostIntent.builder()
+                .appId(APPID)
+                .one(id1)
+                .two(id2)
+                .selector(selector)
+                .treatment(treatment)
+                .build();
+        final HostToHostIntent empty = HostToHostIntent.builder()
+                .appId(APPID)
+                .one(id1)
+                .two(id2)
+                .selector(selector)
+                .treatment(treatment)
+                .constraints(ImmutableList.of())
+                .build();
+        final HostToHostIntent exact = HostToHostIntent.builder()
+                .appId(APPID)
+                .one(id1)
+                .two(id2)
+                .selector(selector)
+                .treatment(treatment)
+                .constraints(ImmutableList.of(HostToHostIntent.NOT_OPTICAL))
+                .build();
+
+        new EqualsTester()
+            .addEqualityGroup(implicit.constraints(),
+                              empty.constraints(),
+                              exact.constraints())
+            .testEquals();
+
+    }
+
     @Override
     protected Intent createOne() {
         return HostToHostIntent.builder()
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java
new file mode 100644 (file)
index 0000000..592cd98
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet;
+
+import org.junit.Test;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+
+import com.google.common.testing.EqualsTester;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Unit tests for the DefaultPacketRequest class.
+ */
+public class DefaultPacketRequestTest {
+
+    private final TrafficSelector selector = DefaultTrafficSelector
+            .builder()
+            .matchIcmpCode((byte) 1)
+            .build();
+
+    private final DefaultPacketRequest packetRequest1 =
+            new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(),
+                                     PacketPriority.CONTROL,
+                                     NetTestTools.APP_ID);
+    private final DefaultPacketRequest sameAsacketRequest1 =
+            new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(),
+                                     PacketPriority.CONTROL,
+                                     NetTestTools.APP_ID);
+    private final DefaultPacketRequest packetRequest2 =
+            new DefaultPacketRequest(selector,
+                                     PacketPriority.CONTROL,
+                                     NetTestTools.APP_ID);
+    private final DefaultPacketRequest packetRequest3 =
+            new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(),
+                                     PacketPriority.REACTIVE,
+                                     NetTestTools.APP_ID);
+    private final DefaultPacketRequest packetRequest4 =
+            new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(),
+                                     PacketPriority.CONTROL,
+                                     new DefaultApplicationId(1, "foo"));
+
+    /**
+     * Tests the operation of the equals(), toAstring() and hashCode() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(packetRequest1, sameAsacketRequest1)
+                .addEqualityGroup(packetRequest2)
+                .addEqualityGroup(packetRequest3)
+                .addEqualityGroup(packetRequest4)
+                .testEquals();
+    }
+
+    /**
+     * Tests that building and fetching from a DefaultPacketRequest is correct.
+     */
+    @Test
+    public void testConstruction() {
+        assertThat(packetRequest1.priority(), is(PacketPriority.CONTROL));
+        assertThat(packetRequest1.priority().priorityValue(),
+                   is(PacketPriority.CONTROL.priorityValue()));
+        assertThat(packetRequest1.selector(), is(DefaultTrafficSelector.emptySelector()));
+        assertThat(packetRequest1.appId(), is(NetTestTools.APP_ID));
+    }
+
+    /**
+     * Checks that the DefaultPacketRequest class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultPacketRequest.class);
+    }
+}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java
new file mode 100644 (file)
index 0000000..f0d45f0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet;
+
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Unit tests for PacketEvent class.
+ */
+public class PacketEventTest {
+
+    OutboundPacket packet;
+
+    @Test
+    public void testConstruction1() {
+        long time = System.currentTimeMillis();
+        PacketEvent event = new PacketEvent(PacketEvent.Type.EMIT, packet);
+
+        assertThat(event.type(), is(PacketEvent.Type.EMIT));
+        assertThat(event.subject(), is(packet));
+        assertThat(event.time(), greaterThanOrEqualTo(time));
+    }
+
+    @Test
+    public void testConstruction2() {
+        long time = 12345678;
+        PacketEvent event = new PacketEvent(PacketEvent.Type.EMIT, packet, time);
+
+        assertThat(event.type(), is(PacketEvent.Type.EMIT));
+        assertThat(event.subject(), is(packet));
+        assertThat(event.time(), is(time));
+    }
+
+}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java
new file mode 100644 (file)
index 0000000..7b2ef54
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet;
+
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThan;
+
+/**
+ * Unit tests for static APIs in the packet processor class.
+ */
+public class PacketProcessorTest {
+
+    /**
+     * Tests a priority in the advisor range.
+     */
+    @Test
+    public void testAdvisorPriorities() {
+        int advisorPriority = PacketProcessor.advisor(3);
+        assertThat(advisorPriority, lessThan(PacketProcessor.ADVISOR_MAX));
+        assertThat(advisorPriority, greaterThanOrEqualTo(0));
+    }
+
+    /**
+     * Tests a priority in the director range.
+     */
+    @Test
+    public void testDirectorPriorities() {
+        int directorPriority = PacketProcessor.director(3);
+        assertThat(directorPriority, lessThan(PacketProcessor.DIRECTOR_MAX));
+        assertThat(directorPriority, greaterThanOrEqualTo(PacketProcessor.ADVISOR_MAX));
+    }
+
+    /**
+     * Tests a priority in the observer range.
+     */
+    @Test
+    public void testObserverPriorities() {
+        int observerPriority = PacketProcessor.observer(3);
+        assertThat(observerPriority, lessThan(PacketProcessor.OBSERVER_MAX));
+        assertThat(observerPriority, greaterThanOrEqualTo(PacketProcessor.DIRECTOR_MAX));
+    }
+
+}
index 4e0f2bd..69c5e79 100644 (file)
@@ -15,6 +15,8 @@
  */
 package org.onosproject.codec.impl;
 
+import static org.onlab.util.Tools.nullIsIllegal;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -24,9 +26,13 @@ import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
+import org.onlab.util.HexString;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.OduSignalId;
+import org.onosproject.net.OduSignalType;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.criteria.Criteria;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -34,8 +40,6 @@ import org.onosproject.net.flow.criteria.Criterion;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
-import static org.onlab.util.Tools.nullIsIllegal;
-
 /**
  * Decode portion of the criterion codec.
  */
@@ -95,6 +99,8 @@ public final class DecodeCriterionCodecHelper {
         decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder());
         decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder());
         decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder());
+        decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder());
+        decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder());
     }
 
     private class EthTypeDecoder implements CriterionDecoder {
@@ -415,7 +421,9 @@ public final class DecodeCriterionCodecHelper {
     private class OchSigTypeDecoder implements CriterionDecoder {
         @Override
         public Criterion decodeCriterion(ObjectNode json) {
-            return null;
+            OchSignalType ochSignalType = OchSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_TYPE),
+                    CriterionCodec.OCH_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText());
+            return Criteria.matchOchSignalType(ochSignalType);
         }
     }
 
@@ -428,6 +436,34 @@ public final class DecodeCriterionCodecHelper {
         }
     }
 
+    private class OduSigIdDecoder implements CriterionDecoder {
+        @Override
+        public Criterion decodeCriterion(ObjectNode json) {
+            JsonNode oduSignalId = nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_ID),
+                    CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE);
+
+            int tributaryPortNumber = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_PORT_NUMBER),
+                    CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE).asInt();
+            int tributarySlotLen = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_LEN),
+                    CriterionCodec.TRIBUTARY_SLOT_LEN + MISSING_MEMBER_MESSAGE).asInt();
+            byte[] tributarySlotBitmap = HexString.fromHexString(
+                    nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP),
+                    CriterionCodec.TRIBUTARY_SLOT_BITMAP + MISSING_MEMBER_MESSAGE).asText());
+
+            return Criteria.matchOduSignalId(
+                    OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap));
+        }
+    }
+
+    private class OduSigTypeDecoder implements CriterionDecoder {
+        @Override
+        public Criterion decodeCriterion(ObjectNode json) {
+            OduSignalType oduSignalType = OduSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_TYPE),
+                    CriterionCodec.ODU_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText());
+            return Criteria.matchOduSignalType(oduSignalType);
+        }
+    }
+
     /**
      * Decodes the JSON into a criterion object.
      *
index 6a97a07..14555b3 100644 (file)
  */
 package org.onosproject.codec.impl;
 
+import static org.onlab.util.Tools.nullIsIllegal;
+
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
+import org.onlab.util.HexString;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
 
-import static org.onlab.util.Tools.nullIsIllegal;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 /**
  * Decoding portion of the instruction codec.
@@ -173,6 +176,30 @@ public final class DecodeInstructionCodecHelper {
                 + subType + " is not supported");
     }
 
+    /**
+     * Decodes a Layer 1 instruction.
+     *
+     * @return instruction object decoded from the JSON
+     * @throws IllegalArgumentException if the JSON is invalid
+     */
+    private Instruction decodeL1() {
+        String subType = json.get(InstructionCodec.SUBTYPE).asText();
+        if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) {
+            int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER),
+                    InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN),
+                    InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            byte[] tributarySlotBitmap = null;
+            tributarySlotBitmap = HexString.fromHexString(
+                    nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP),
+                    InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
+            return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen,
+                    tributarySlotBitmap));
+        }
+        throw new IllegalArgumentException("L1 Instruction subtype "
+                + subType + " is not supported");
+    }
+
     /**
      * Decodes a Layer 4 instruction.
      *
@@ -221,6 +248,8 @@ public final class DecodeInstructionCodecHelper {
             return Instructions.createDrop();
         } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) {
             return decodeL0();
+        } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) {
+            return decodeL1();
         } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) {
             return decodeL2();
         } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) {
index f7af736..8fc6bbc 100644 (file)
@@ -17,8 +17,10 @@ package org.onosproject.codec.impl;
 
 import java.util.EnumMap;
 
+import org.onlab.util.HexString;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
@@ -370,12 +372,18 @@ public final class EncodeCriterionCodecHelper {
     private static class FormatOduSignalId implements CriterionTypeFormatter {
         @Override
         public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
-            final OduSignalIdCriterion oduSignalIdCriterion =
-                    (OduSignalIdCriterion) criterion;
-            return root.put(CriterionCodec.ODU_SIGNAL_ID, oduSignalIdCriterion.oduSignalId().toString());
+            OduSignalId oduSignalId = ((OduSignalIdCriterion) criterion).oduSignalId();
+            ObjectNode child = root.putObject(CriterionCodec.ODU_SIGNAL_ID);
+
+            child.put(CriterionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber());
+            child.put(CriterionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength());
+            child.put(CriterionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap()));
+
+            return root;
         }
     }
 
+
     private static class FormatOduSignalType implements CriterionTypeFormatter {
         @Override
         public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
index d12e4ad..2ec301d 100644 (file)
  */
 package org.onosproject.codec.impl;
 
+import org.onlab.util.HexString;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
@@ -80,6 +83,36 @@ public final class EncodeInstructionCodecHelper {
         }
     }
 
+    /**
+     * Encode an L1 modification instruction.
+     *
+     * @param result json node that the instruction attributes are added to
+     * @param instruction The L1 instruction
+     * @param context context of the request
+     */
+    private void encodeL1(ObjectNode result) {
+        L1ModificationInstruction instruction =
+                (L1ModificationInstruction) this.instruction;
+        result.put(InstructionCodec.SUBTYPE, instruction.subtype().name());
+
+        switch (instruction.subtype()) {
+        case ODU_SIGID:
+            final L1ModificationInstruction.ModOduSignalIdInstruction oduSignalIdInstruction =
+                    (L1ModificationInstruction.ModOduSignalIdInstruction) instruction;
+            OduSignalId oduSignalId = oduSignalIdInstruction.oduSignalId();
+
+            ObjectNode child = result.putObject("oduSignalId");
+
+            child.put(InstructionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber());
+            child.put(InstructionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength());
+            child.put(InstructionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap()));
+            break;
+        default:
+            log.info("Cannot convert L1 subtype of {}", instruction.subtype());
+            break;
+        }
+    }
+
     /**
      * Encode an L2 modification instruction.
      *
@@ -222,6 +255,10 @@ public final class EncodeInstructionCodecHelper {
                 encodeL0(result);
                 break;
 
+            case L1MODIFICATION:
+                encodeL1(result);
+                break;
+
             case L2MODIFICATION:
                 encodeL2(result);
                 break;
index f4d5008..d7307ad 100644 (file)
@@ -50,6 +50,9 @@ public final class InstructionCodec extends JsonCodec<Instruction> {
     protected static final String TUNNEL_ID = "tunnelId";
     protected static final String TCP_PORT = "tcpPort";
     protected static final String UDP_PORT = "udpPort";
+    protected static final String TRIBUTARY_PORT_NUMBER = "tributaryPortNumber";
+    protected static final String TRIBUTARY_SLOT_LEN = "tributarySlotLength";
+    protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap";
 
     protected static final String MISSING_MEMBER_MESSAGE =
             " member is required in Instruction";
index 54e1146..86374f8 100644 (file)
@@ -31,6 +31,8 @@ import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignalType;
+import org.onosproject.net.OduSignalId;
+import org.onosproject.net.OduSignalType;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.criteria.Criteria;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -54,6 +56,10 @@ public class CriterionCodecTest {
     final IpPrefix ipPrefix6 = IpPrefix.valueOf("fe80::/64");
     final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
     final TpPort tpPort = TpPort.tpPort(40000);
+    final int tributaryPortNumber = 11;
+    final int tributarySlotLen = 80;
+    final byte[] tributarySlotBitmap = new byte[] {1, 2, 3, 4, 2, 3, 4, 2, 3, 4};
+
 
     /**
      * Sets up for each test.  Creates a context and fetches the criterion
@@ -427,4 +433,31 @@ public class CriterionCodecTest {
         ObjectNode result = criterionCodec.encode(criterion, context);
         assertThat(result, matchesCriterion(criterion));
     }
+
+   /**
+     * Tests Odu Signal ID criterion.
+     */
+    @Test
+    public void matchOduSignalIdTest() {
+
+        OduSignalId oduSignalId = OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap);
+
+        Criterion criterion = Criteria.matchOduSignalId(oduSignalId);
+        ObjectNode result = criterionCodec.encode(criterion, context);
+        assertThat(result, matchesCriterion(criterion));
+    }
+
+    /**
+     * Tests Odu Signal Type criterion.
+     */
+    @Test
+    public void matchOduSignalTypeTest() {
+
+        OduSignalType signalType = OduSignalType.ODU2;
+
+        Criterion criterion = Criteria.matchOduSignalType(signalType);
+        ObjectNode result = criterionCodec.encode(criterion, context);
+        assertThat(result, matchesCriterion(criterion));
+    }
+
 }
index bb3acad..b00632c 100644 (file)
  */
 package org.onosproject.codec.impl;
 
-import com.google.common.base.Joiner;
+import java.util.Objects;
+
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onlab.util.HexString;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.criteria.Criterion;
-
-import com.fasterxml.jackson.databind.JsonNode;
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
@@ -40,6 +41,8 @@ import org.onosproject.net.flow.criteria.MetadataCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.OchSignalCriterion;
 import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
+import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
+import org.onosproject.net.flow.criteria.OduSignalTypeCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
@@ -47,7 +50,8 @@ import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
 
-import java.util.Objects;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.Joiner;
 
 /**
  * Hamcrest matcher for criterion objects.
@@ -496,6 +500,44 @@ public final class CriterionJsonMatcher extends
         return true;
     }
 
+   /**
+     * Matches an ODU signal ID criterion object.
+     *
+     * @param criterion criterion to match
+     * @return true if the JSON matches the criterion, false otherwise.
+     */
+    private boolean matchCriterion(OduSignalIdCriterion criterion) {
+        final OduSignalId oduSignal = criterion.oduSignalId();
+        final JsonNode jsonOduSignal = jsonCriterion.get(CriterionCodec.ODU_SIGNAL_ID);
+        int jsonTpn = jsonOduSignal.get(CriterionCodec.TRIBUTARY_PORT_NUMBER).intValue();
+        int jsonTsLen = jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_LEN).intValue();
+        byte[] jsonTributaryBitMap = HexString.fromHexString(
+                jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP).asText());
+        OduSignalId jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, jsonTributaryBitMap);
+        if (!oduSignal.equals(jsonOduSignalId)) {
+            description.appendText("oduSignalId was " + criterion);
+            return false;
+        }
+       return true;
+    }
+
+    /**
+     * Matches an ODU signal Type criterion object.
+     *
+     * @param criterion criterion to match
+     * @return true if the JSON matches the criterion, false otherwise.
+     */
+    private boolean matchCriterion(OduSignalTypeCriterion criterion) {
+        final String signalType = criterion.signalType().name();
+        final String jsonOduSignalType = jsonCriterion.get("oduSignalType").textValue();
+        if (!signalType.equals(jsonOduSignalType)) {
+            description.appendText("signalType was " + signalType);
+            return false;
+        }
+        return true;
+    }
+
+
     @Override
     public boolean matchesSafely(JsonNode jsonCriterion,
                                  Description description) {
@@ -594,6 +636,12 @@ public final class CriterionJsonMatcher extends
             case OCH_SIGTYPE:
                 return matchCriterion((OchSignalTypeCriterion) criterion);
 
+            case ODU_SIGID:
+                return matchCriterion((OduSignalIdCriterion) criterion);
+
+            case ODU_SIGTYPE:
+                return matchCriterion((OduSignalTypeCriterion) criterion);
+
             default:
                 // Don't know how to format this type
                 description.appendText("unknown criterion type " +
index 6c88ac1..f6a9213 100644 (file)
  */
 package org.onosproject.codec.impl;
 
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.SortedMap;
@@ -35,6 +44,8 @@ import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.OduSignalType;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -55,6 +66,9 @@ import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
 import org.onosproject.net.flow.criteria.IndexedLambdaCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.OchSignalCriterion;
+import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
+import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
+import org.onosproject.net.flow.criteria.OduSignalTypeCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
@@ -62,9 +76,6 @@ import org.onosproject.net.flow.criteria.TunnelIdCriterion;
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
@@ -72,14 +83,8 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
 
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.onosproject.net.NetTestTools.APP_ID;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 /**
  * Flow rule codec unit tests.
@@ -382,7 +387,7 @@ public class FlowRuleCodecTest {
 
         checkCommonData(rule);
 
-        assertThat(rule.selector().criteria().size(), is(33));
+        assertThat(rule.selector().criteria().size(), is(36));
 
         rule.selector().criteria()
                 .stream()
@@ -518,6 +523,25 @@ public class FlowRuleCodecTest {
         criterion = getCriterion(Criterion.Type.TUNNEL_ID);
         assertThat(((TunnelIdCriterion) criterion).tunnelId(),
                 is(100L));
+
+        criterion = getCriterion(Criterion.Type.OCH_SIGTYPE);
+        assertThat(((OchSignalTypeCriterion) criterion).signalType(),
+                is(OchSignalType.FIXED_GRID));
+
+        criterion = getCriterion(Criterion.Type.ODU_SIGTYPE);
+        assertThat(((OduSignalTypeCriterion) criterion).signalType(),
+                is(OduSignalType.ODU4));
+
+
+        criterion = getCriterion(Criterion.Type.ODU_SIGID);
+        assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributaryPortNumber(),
+                is(1));
+
+       assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributarySlotLength(),
+                is(80));
+
+       assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributarySlotBitmap(),
+                is(new byte [] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}));
     }
 
     /**
index bafbc0f..f7b0261 100644 (file)
  */
 package org.onosproject.codec.impl;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.Ip4Address;
@@ -28,26 +32,23 @@ import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.Lambda;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction;
-
 /**
  * Unit tests for Instruction codec.
  */
 public class InstructionCodecTest {
     CodecContext context;
     JsonCodec<Instruction> instructionCodec;
-
     /**
      * Sets up for each test.  Creates a context and fetches the instruction
      * codec.
@@ -121,6 +122,20 @@ public class InstructionCodecTest {
         assertThat(instructionJson, matchesInstruction(instruction));
     }
 
+    /**
+     * Tests the encoding of mod ODU signal ID instructions.
+     */
+    @Test
+    public void modOduSignalIdInstructionTest() {
+        OduSignalId oduSignalId = OduSignalId.oduSignalId(1, 8, new byte [] {8, 0, 0, 0, 0, 0, 0, 0, 0, 0});
+        L1ModificationInstruction.ModOduSignalIdInstruction instruction =
+                (L1ModificationInstruction.ModOduSignalIdInstruction)
+                    Instructions.modL1OduSignalId(oduSignalId);
+        ObjectNode instructionJson =
+                instructionCodec.encode(instruction, context);
+        assertThat(instructionJson, matchesInstruction(instruction));
+    }
+
     /**
      * Tests the encoding of mod ether instructions.
      */
index c3cdca0..9ffb3c3 100644 (file)
@@ -17,15 +17,25 @@ package org.onosproject.codec.impl;
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onlab.util.HexString;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.DropInstruction;
+import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
 
 import com.fasterxml.jackson.databind.JsonNode;
 
-import static org.onosproject.net.flow.instructions.Instructions.*;
-import static org.onosproject.net.flow.instructions.L0ModificationInstruction.*;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*;
-import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*;
-
 /**
  * Hamcrest matcher for instructions.
  */
@@ -133,7 +143,7 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json
     }
 
     /**
-     * Matches teh contents of a mod OCh singal instruction.
+     * Matches the contents of a mod OCh singal instruction.
      *
      * @param instructionJson JSON instruction to match
      * @param description Description object used for recording errors
@@ -183,6 +193,40 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json
         return true;
     }
 
+    /**
+     * Matches the contents of a mod ODU singal Id instruction.
+     *
+     * @param instructionJson JSON instruction to match
+     * @param description Description object used for recording errors
+     * @return true if contents matches, false otherwise
+     */
+    private boolean matchModOduSingalIdInstruction(JsonNode instructionJson,
+                                                   Description description) {
+        ModOduSignalIdInstruction instructionToMatch =
+                (ModOduSignalIdInstruction) instruction;
+        String jsonSubType = instructionJson.get("subtype").textValue();
+        if (!instructionToMatch.subtype().name().equals(jsonSubType)) {
+            description.appendText("subtype was " + jsonSubType);
+            return false;
+        }
+        String jsonType = instructionJson.get("type").textValue();
+        if (!instructionToMatch.type().name().equals(jsonType)) {
+            description.appendText("type was " + jsonType);
+            return false;
+        }
+        final JsonNode jsonOduSignal = instructionJson.get("oduSignalId");
+        int jsonTpn = jsonOduSignal.get("tributaryPortNumber").intValue();
+        int jsonTsLen = jsonOduSignal.get("tributarySlotLength").intValue();
+        byte [] tributaryBitMap = HexString.fromHexString(jsonOduSignal.get("tributarySlotBitmap").asText());
+        OduSignalId  jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, tributaryBitMap);
+        if (!instructionToMatch.oduSignalId().equals(jsonOduSignalId)) {
+            description.appendText("oduSignalId was " + instructionToMatch);
+            return false;
+        }
+        return true;
+    }
+
+
     /**
      * Matches the contents of a mod Ethernet instruction.
      *
@@ -416,6 +460,8 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json
                                                     description);
         } else if (instruction instanceof ModMplsLabelInstruction) {
             return matchModMplsLabelInstruction(jsonInstruction, description);
+        } else if (instruction instanceof ModOduSignalIdInstruction) {
+            return matchModOduSingalIdInstruction(jsonInstruction, description);
         } else if (instruction instanceof NoActionInstruction) {
             return true;
         }
index 1a96e92..ccb2e16 100644 (file)
             {"type":"MPLS_LABEL", "label":123},
             {"type":"IPV6_EXTHDR", "exthdrFlags":99},
             {"type":"OCH_SIGID", "lambda":122},
-            {"type":"TUNNEL_ID", "tunnelId":100}
+            {"type":"TUNNEL_ID", "tunnelId":100},
+            {"type":"OCH_SIGTYPE", "ochSignalType":"FIXED_GRID"},
+            {"type":"ODU_SIGTYPE", "oduSignalType":"ODU4"},
+            {"type":"ODU_SIGID", "oduSignalId" : {"tributaryPortNumber":1, "tributarySlotLen":80, "tributarySlotBitmap":"01:01:01:01:01:01:01:01:01:01"}}
           ]
       }
 }
index 04d1dfd..7ddac0c 100644 (file)
@@ -25,17 +25,26 @@ import org.apache.karaf.system.SystemService;
 import org.joda.time.DateTime;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cluster.ClusterAdminService;
-import org.onosproject.cluster.ClusterDefinitionService;
 import org.onosproject.cluster.ClusterEvent;
 import org.onosproject.cluster.ClusterEventListener;
+import org.onosproject.cluster.ClusterMetadata;
+import org.onosproject.cluster.ClusterMetadataService;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.ClusterStore;
 import org.onosproject.cluster.ClusterStoreDelegate;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
+import org.onosproject.cluster.Partition;
 import org.onosproject.event.AbstractListenerManager;
 import org.slf4j.Logger;
 
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -44,8 +53,6 @@ import static org.onosproject.security.AppGuard.checkPermission;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppPermission.Type.*;
 
-
-
 /**
  * Implementation of the cluster service.
  */
@@ -61,7 +68,7 @@ public class ClusterManager
     private ClusterStoreDelegate delegate = new InternalStoreDelegate();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ClusterDefinitionService clusterDefinitionService;
+    protected ClusterMetadataService clusterMetadataService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ClusterStore store;
@@ -73,8 +80,9 @@ public class ClusterManager
     public void activate() {
         store.setDelegate(delegate);
         eventDispatcher.addSink(ClusterEvent.class, listenerRegistry);
-        clusterDefinitionService.seedNodes()
-                                .forEach(node -> store.addNode(node.id(), node.ip(), node.tcpPort()));
+        clusterMetadataService.getClusterMetadata()
+                              .getNodes()
+                              .forEach(node -> store.addNode(node.id(), node.ip(), node.tcpPort()));
         log.info("Started");
     }
 
@@ -119,11 +127,16 @@ public class ClusterManager
     }
 
     @Override
-    public void formCluster(Set<ControllerNode> nodes, String ipPrefix) {
+    public void formCluster(Set<ControllerNode> nodes) {
         checkNotNull(nodes, "Nodes cannot be null");
         checkArgument(!nodes.isEmpty(), "Nodes cannot be empty");
-        checkNotNull(ipPrefix, "IP prefix cannot be null");
-        clusterDefinitionService.formCluster(nodes, ipPrefix);
+
+        ClusterMetadata metadata = ClusterMetadata.builder()
+                                                  .withName("default")
+                                                  .withControllerNodes(nodes)
+                                                  .withPartitions(buildDefaultPartitions(nodes))
+                                                  .build();
+        clusterMetadataService.setClusterMetadata(metadata);
         try {
             log.warn("Shutting down container for cluster reconfiguration!");
             systemService.reboot("now", SystemService.Swipe.NONE);
@@ -153,4 +166,21 @@ public class ClusterManager
             post(event);
         }
     }
+
+    private static Collection<Partition> buildDefaultPartitions(Collection<ControllerNode> nodes) {
+        List<ControllerNode> sorted = new ArrayList<>(nodes);
+        Collections.sort(sorted, (o1, o2) -> o1.id().toString().compareTo(o2.id().toString()));
+        Collection<Partition> partitions = Lists.newArrayList();
+
+        int length = nodes.size();
+        int count = 3;
+        for (int i = 0; i < length; i++) {
+            Set<NodeId> set = new HashSet<>(count);
+            for (int j = 0; j < count; j++) {
+                set.add(sorted.get((i + j) % length).id());
+            }
+            partitions.add(new Partition("p" + (i + 1), set));
+        }
+        return partitions;
+    }
 }
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java
new file mode 100644 (file)
index 0000000..a0f7a83
--- /dev/null
@@ -0,0 +1,116 @@
+package org.onosproject.cluster.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Collection;
+import java.util.Enumeration;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterMetadata;
+import org.onosproject.cluster.ClusterMetadataEvent;
+import org.onosproject.cluster.ClusterMetadataEventListener;
+import org.onosproject.cluster.ClusterMetadataService;
+import org.onosproject.cluster.ClusterMetadataStore;
+import org.onosproject.cluster.ClusterMetadataStoreDelegate;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+/**
+ * Implementation of ClusterMetadataService.
+ */
+@Component(immediate = true)
+@Service
+public class ClusterMetadataManager
+    extends AbstractListenerManager<ClusterMetadataEvent, ClusterMetadataEventListener>
+    implements ClusterMetadataService {
+
+    private ControllerNode localNode;
+    private final Logger log = getLogger(getClass());
+
+    private ClusterMetadataStoreDelegate delegate = new InternalStoreDelegate();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterMetadataStore store;
+
+    @Activate
+    public void activate() {
+        store.setDelegate(delegate);
+        eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry);
+        establishSelfIdentity();
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        store.unsetDelegate(delegate);
+        eventDispatcher.removeSink(ClusterMetadataEvent.class);
+        log.info("Stopped");
+    }
+
+    @Override
+    public ClusterMetadata getClusterMetadata() {
+        return Versioned.valueOrElse(store.getClusterMetadata(), null);
+    }
+
+    @Override
+    public ControllerNode getLocalNode() {
+        return localNode;
+    }
+
+    @Override
+    public void setClusterMetadata(ClusterMetadata metadata) {
+        checkNotNull(metadata, "Cluster metadata cannot be null");
+        store.setClusterMetadata(metadata);
+    }
+
+    // Store delegate to re-post events emitted from the store.
+    private class InternalStoreDelegate implements ClusterMetadataStoreDelegate {
+        @Override
+        public void notify(ClusterMetadataEvent event) {
+            post(event);
+        }
+    }
+
+    private IpAddress findLocalIp(Collection<ControllerNode> controllerNodes) throws SocketException {
+        Enumeration<NetworkInterface> interfaces =
+                NetworkInterface.getNetworkInterfaces();
+        while (interfaces.hasMoreElements()) {
+            NetworkInterface iface = interfaces.nextElement();
+            Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
+            while (inetAddresses.hasMoreElements()) {
+                IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement());
+                if (controllerNodes.stream()
+                        .map(ControllerNode::ip)
+                        .anyMatch(nodeIp -> ip.equals(nodeIp))) {
+                    return ip;
+                }
+            }
+        }
+        throw new IllegalStateException("Unable to determine local ip");
+    }
+
+    private void establishSelfIdentity() {
+        try {
+            IpAddress ip = findLocalIp(getClusterMetadata().getNodes());
+            localNode = getClusterMetadata().getNodes()
+                                            .stream()
+                                            .filter(node -> node.ip().equals(ip))
+                                            .findFirst()
+                                            .get();
+        } catch (SocketException e) {
+            throw new IllegalStateException("Cannot determine local IP", e);
+        }
+    }
+}
\ No newline at end of file
index 19377cf..8f60149 100644 (file)
@@ -112,10 +112,10 @@ public final class OpticalPortOperator implements ConfigOperator {
                 return new OduCltPortDescription(port, odu.isEnabled(), odu.signalType(), sa);
             case PACKET:
             case FIBER:
+            case COPPER:
                 return new DefaultPortDescription(port, descr.isEnabled(), descr.type(),
                         descr.portSpeed(), sa);
             default:
-                // this includes copper ports.
                 log.warn("Unsupported optical port type {} - can't update", descr.type());
                 return descr;
         }
index 137aca1..0a1af6f 100644 (file)
@@ -29,9 +29,11 @@ import org.onosproject.net.flow.criteria.VlanPcpCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
 import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
+import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
 import org.onosproject.net.flow.criteria.Criteria;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
@@ -155,6 +157,7 @@ public final class FlowObjectiveCompositionUtil {
         return treatmentBuilder.build();
     }
 
+    //CHECKSTYLE:OFF
     public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
                                                           TrafficSelector trafficSelector) {
 
@@ -195,14 +198,30 @@ public final class FlowObjectiveCompositionUtil {
                                 } else {
                                     return null;
                                 }
-                            } else {
-                                break;
                             }
                         default:
                             break;
                     }
                     break;
                 }
+                case L1MODIFICATION: {
+                    L1ModificationInstruction l1 = (L1ModificationInstruction) instruction;
+                    switch (l1.subtype()) {
+                        case ODU_SIGID:
+                            if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) {
+                                if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId()
+                                        .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1)
+                                                .oduSignalId())) {
+                                    criterionMap.remove(Criterion.Type.ODU_SIGID);
+                                } else {
+                                    return null;
+                                }
+                            } 
+                        default:
+                            break;
+                    }
+                    break;
+                }
                 case L2MODIFICATION: {
                     L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
                     switch (l2.subtype()) {
@@ -344,6 +363,7 @@ public final class FlowObjectiveCompositionUtil {
 
         return selectorBuilder.build();
     }
+   //CHECKSTYLE:ON
 
     public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
         Set<Criterion.Type> typeSet = new HashSet<>();
index 5fd1c85..acc5a5d 100644 (file)
@@ -24,12 +24,14 @@ import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.EthType;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -46,24 +48,23 @@ import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
 import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.MplsPathIntent;
-import org.onosproject.net.link.LinkStore;
-import org.onosproject.net.resource.link.DefaultLinkResourceRequest;
+import org.onosproject.net.newresource.ResourcePath;
+import org.onosproject.net.newresource.ResourceService;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
-import org.onosproject.net.resource.link.LinkResourceRequest;
-import org.onosproject.net.resource.link.LinkResourceService;
-import org.onosproject.net.resource.link.MplsLabel;
-import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
-import org.onosproject.net.resource.ResourceAllocation;
-import org.onosproject.net.resource.ResourceType;
 import org.slf4j.Logger;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.LinkKey.linkKey;
 import static org.slf4j.LoggerFactory.getLogger;
 
 @Component(immediate = true)
@@ -78,18 +79,15 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected LinkResourceService resourceService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected LinkStore linkStore;
+    protected ResourceService resourceService;
 
     protected ApplicationId appId;
 
     @Override
     public List<Intent> compile(MplsPathIntent intent, List<Intent> installable,
                                 Set<LinkResourceAllocations> resources) {
-        LinkResourceAllocations allocations = assignMplsLabel(intent);
-        List<FlowRule> rules = generateRules(intent, allocations);
+        Map<LinkKey, MplsLabel> labels = assignMplsLabel(intent);
+        List<FlowRule> rules = generateRules(intent, labels);
 
         return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
     }
@@ -105,39 +103,60 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
         intentExtensionService.unregisterCompiler(MplsPathIntent.class);
     }
 
-    private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) {
+    private Map<LinkKey, MplsLabel> assignMplsLabel(MplsPathIntent intent) {
         // TODO: do it better... Suggestions?
-        Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
+        Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
                 .links().size() - 2);
         for (int i = 1; i <= intent.path().links().size() - 2; i++) {
-            Link link = intent.path().links().get(i);
+            LinkKey link = linkKey(intent.path().links().get(i));
             linkRequest.add(link);
             // add the inverse link. I want that the label is reserved both for
             // the direct and inverse link
-            linkRequest.add(linkStore.getLink(link.dst(), link.src()));
+            linkRequest.add(linkKey(link.dst(), link.src()));
         }
 
-        LinkResourceRequest.Builder request = DefaultLinkResourceRequest
-                .builder(intent.id(), linkRequest).addMplsRequest();
-        LinkResourceAllocations reqMpls = resourceService
-                .requestResources(request.build());
-        return reqMpls;
-    }
+        Map<LinkKey, MplsLabel> labels = findMplsLabels(linkRequest);
+        if (labels.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        List<ResourcePath> resources = labels.entrySet().stream()
+                .map(x -> new ResourcePath(linkKey(x.getKey().src(), x.getKey().src()), x.getValue()))
+                .collect(Collectors.toList());
+        List<org.onosproject.net.newresource.ResourceAllocation> allocations =
+                resourceService.allocate(intent.id(), resources);
+        if (allocations.isEmpty()) {
+            Collections.emptyMap();
+        }
 
-    private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) {
-        for (ResourceAllocation allocation : allocations
-                .getResourceAllocation(link)) {
-            if (allocation.type() == ResourceType.MPLS_LABEL) {
-                return ((MplsLabelResourceAllocation) allocation).mplsLabel();
+        return labels;
+    }
 
+    private Map<LinkKey, MplsLabel> findMplsLabels(Set<LinkKey> links) {
+        Map<LinkKey, MplsLabel> labels = new HashMap<>();
+        for (LinkKey link : links) {
+            Optional<MplsLabel> label = findMplsLabel(link);
+            if (label.isPresent()) {
+                labels.put(link, label.get());
             }
         }
-        log.warn("MPLS label was not assigned successfully");
-        return null;
+
+        return labels;
+    }
+
+    private Optional<MplsLabel> findMplsLabel(LinkKey link) {
+        return resourceService.getAvailableResources(new ResourcePath(link)).stream()
+                .filter(x -> x.lastComponent() instanceof MplsLabel)
+                .map(x -> (MplsLabel) x.lastComponent())
+                .findFirst();
+    }
+
+    private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) {
+        return labels.get(link);
     }
 
     private List<FlowRule> generateRules(MplsPathIntent intent,
-                                         LinkResourceAllocations allocations) {
+                                         Map<LinkKey, MplsLabel> labels) {
 
         Iterator<Link> links = intent.path().links().iterator();
         Link srcLink = links.next();
@@ -149,7 +168,7 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
 
         // Ingress traffic
         // Get the new MPLS label
-        MplsLabel mpls = getMplsLabel(allocations, link);
+        MplsLabel mpls = getMplsLabel(labels, linkKey(link));
         checkNotNull(mpls);
         MplsLabel prevLabel = mpls;
         rules.add(ingressFlow(prev.port(), link, intent, mpls));
@@ -163,7 +182,7 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
             if (links.hasNext()) {
                 // Transit traffic
                 // Get the new MPLS label
-                mpls = getMplsLabel(allocations, link);
+                mpls = getMplsLabel(labels, linkKey(link));
                 checkNotNull(mpls);
                 rules.add(transitFlow(prev.port(), link, intent,
                         prevLabel, mpls));
@@ -181,7 +200,8 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
     }
 
     private FlowRule ingressFlow(PortNumber inPort, Link link,
-                                 MplsPathIntent intent, MplsLabel label) {
+                                 MplsPathIntent intent,
+                                 MplsLabel label) {
 
         TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
                 .builder(intent.selector());
@@ -193,10 +213,10 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
                     .matchMplsLabel(intent.ingressLabel().get());
 
             // Swap the MPLS label
-            treat.setMpls(label.label());
+            treat.setMpls(label);
         } else {
             // Push and set the MPLS label
-            treat.pushMpls().setMpls(label.label());
+            treat.pushMpls().setMpls(label);
         }
         // Add the output action
         treat.setOutput(link.src().port());
@@ -205,21 +225,21 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
     }
 
     private FlowRule transitFlow(PortNumber inPort, Link link,
-                                          MplsPathIntent intent,
-                                          MplsLabel prevLabel,
-                                          MplsLabel outLabel) {
+                                 MplsPathIntent intent,
+                                 MplsLabel prevLabel,
+                                 MplsLabel outLabel) {
 
         // Ignore the ingress Traffic Selector and use only the MPLS label
         // assigned in the previous link
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
-                .matchMplsLabel(prevLabel.label());
+                .matchMplsLabel(prevLabel);
         TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
 
         // Set the new label only if the label on the packet is
         // different
         if (!prevLabel.equals(outLabel)) {
-            treat.setMpls(outLabel.label());
+            treat.setMpls(outLabel);
         }
 
         treat.setOutput(link.src().port());
@@ -227,14 +247,14 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
     }
 
     private FlowRule egressFlow(PortNumber inPort, Link link,
-                                         MplsPathIntent intent,
-                                         MplsLabel prevLabel) {
+                                MplsPathIntent intent,
+                                MplsLabel prevLabel) {
         // egress point: either set the egress MPLS label or pop the
         // MPLS label based on the intent annotations
 
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
-                .matchMplsLabel(prevLabel.label());
+                .matchMplsLabel(prevLabel);
 
         // apply the intent's treatments
         TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
index c6eb7c5..fce8498 100644 (file)
@@ -17,6 +17,7 @@ package org.onosproject.net.intent.impl.compiler;
 
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Modified;
 import org.apache.felix.scr.annotations.Property;
@@ -70,7 +71,7 @@ import static com.google.common.base.Preconditions.checkArgument;
  * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
  */
 // For now, remove component designation until dependency on the new resource manager is available.
-// @Component(immediate = true)
+@Component(immediate = true)
 public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> {
 
     private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class);
index eb5b4af..d6725b7 100644 (file)
 package org.onosproject.net.intent.impl.compiler;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
@@ -24,6 +28,7 @@ import org.onlab.util.Frequency;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.Link;
 import org.onosproject.net.OchPort;
 import org.onosproject.net.OchSignal;
@@ -38,32 +43,29 @@ import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalPathIntent;
 import org.onosproject.net.intent.impl.IntentCompilationException;
+import org.onosproject.net.newresource.ResourceAllocation;
 import org.onosproject.net.newresource.ResourcePath;
 import org.onosproject.net.newresource.ResourceService;
-import org.onosproject.net.resource.ResourceType;
-import org.onosproject.net.resource.link.DefaultLinkResourceRequest;
-import org.onosproject.net.resource.link.LambdaResource;
-import org.onosproject.net.resource.link.LambdaResourceAllocation;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
-import org.onosproject.net.resource.link.LinkResourceRequest;
-import org.onosproject.net.resource.link.LinkResourceService;
 import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.LinkKey.linkKey;
 
 /**
  * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
  */
 // For now, remove component designation until dependency on the new resource manager is available.
-// @Component(immediate = true)
+@Component(immediate = true)
 public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
 
     protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class);
@@ -80,9 +82,6 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceService resourceService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected LinkResourceService linkResourceService;
-
     @Activate
     public void activate() {
         intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
@@ -138,13 +137,12 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
                 ochSignal = srcOchPort.lambda();
             } else {
                 // Request and reserve lambda on path
-                LinkResourceAllocations linkAllocs = assignWavelength(intent, path);
-                if (linkAllocs == null) {
+                IndexedLambda lambda = assignWavelength(intent, path);
+                if (lambda == null) {
                     continue;
                 }
-                LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs);
                 OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
-                ochSignal = new OchSignal(lambdaAlloc.lambda().toInt(), omsPort.maxFrequency(), omsPort.grid());
+                ochSignal = new OchSignal((int) lambda.index(), omsPort.maxFrequency(), omsPort.grid());
             }
 
             // Create installable optical path intent
@@ -170,73 +168,47 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
         throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
     }
 
-    /**
-     * Find the lambda allocated to the path.
-     *
-     * @param path the path
-     * @param linkAllocs the link allocations
-     * @return lambda allocated to the given path
-     */
-    private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) {
-        return path.links().stream()
-                .flatMap(x -> linkAllocs.getResourceAllocation(x).stream())
-                .filter(x -> x.type() == ResourceType.LAMBDA)
-                .findFirst()
-                .map(x -> (LambdaResourceAllocation) x)
-                .orElse(null);
-    }
-
     /**
      * Request and reserve first available wavelength across path.
      *
      * @param path path in WDM topology
-     * @return first available lambda resource allocation
+     * @return first available lambda allocated
      */
-    private LinkResourceAllocations assignWavelength(Intent intent, Path path) {
-        LinkResourceRequest.Builder request =
-                DefaultLinkResourceRequest.builder(intent.id(), path.links())
-                .addLambdaRequest();
-
-        LinkResourceAllocations allocations = linkResourceService.requestResources(request.build());
-
-        if (!checkWavelengthContinuity(allocations, path)) {
-            linkResourceService.releaseResources(allocations);
+    private IndexedLambda assignWavelength(Intent intent, Path path) {
+        Set<IndexedLambda> lambdas = findCommonLambdasOverLinks(path.links());
+        if (lambdas.isEmpty()) {
             return null;
         }
 
-        return allocations;
-    }
+        IndexedLambda minLambda = findFirstLambda(lambdas);
+        List<ResourcePath> lambdaResources = path.links().stream()
+                .map(x -> new ResourcePath(linkKey(x.src(), x.dst())))
+                .map(x -> ResourcePath.child(x, minLambda))
+                .collect(Collectors.toList());
 
-    /**
-     * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links.
-     * @return true if wavelength continuity is met, false otherwise
-     */
-    private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) {
-        if (allocations == null) {
-            return false;
+        List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), lambdaResources);
+        if (allocations.isEmpty()) {
+            log.info("Resource allocation for {} failed (resource request: {})", intent, lambdaResources);
         }
 
-        List<LambdaResource> lambdas = path.links().stream()
-                .flatMap(x -> allocations.getResourceAllocation(x).stream())
-                .filter(x -> x.type() == ResourceType.LAMBDA)
-                .map(x -> ((LambdaResourceAllocation) x).lambda())
-                .collect(Collectors.toList());
+        return minLambda;
+    }
 
-        LambdaResource lambda = null;
-        for (LambdaResource nextLambda: lambdas) {
-            if (nextLambda == null) {
-                return false;
-            }
-            if (lambda == null) {
-                lambda = nextLambda;
-                continue;
-            }
-            if (!lambda.equals(nextLambda)) {
-                return false;
-            }
-        }
+    private Set<IndexedLambda> findCommonLambdasOverLinks(List<Link> links) {
+        return links.stream()
+                .map(x -> new ResourcePath(linkKey(x.src(), x.dst())))
+                .map(resourceService::getAvailableResources)
+                .map(x -> Iterables.filter(x, r -> r.lastComponent() instanceof IndexedLambda))
+                .map(x -> Iterables.transform(x, r -> (IndexedLambda) r.lastComponent()))
+                .map(x -> (Set<IndexedLambda>) ImmutableSet.copyOf(x))
+                .reduce(Sets::intersection)
+                .orElse(Collections.emptySet());
+    }
 
-        return true;
+    private IndexedLambda findFirstLambda(Set<IndexedLambda> lambdas) {
+        return lambdas.stream()
+                .findFirst()
+                .get();
     }
 
     private ConnectPoint staticPort(ConnectPoint connectPoint) {
index 5226967..10fe75e 100644 (file)
@@ -41,7 +41,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 /**
  * An implementation of ResourceService.
  */
-@Component(immediate = true, enabled = false)
+@Component(immediate = true)
 @Service
 @Beta
 public final class ResourceManager implements ResourceService, ResourceAdminService {
@@ -126,6 +126,17 @@ public final class ResourceManager implements ResourceService, ResourceAdminServ
                 .collect(Collectors.toList());
     }
 
+    @Override
+    public Collection<ResourcePath> getAvailableResources(ResourcePath parent) {
+        checkNotNull(parent);
+
+        Collection<ResourcePath> children = store.getChildResources(parent);
+        return children.stream()
+                // We access store twice in this method, then the store may be updated by others
+                .filter(x -> !store.getConsumer(x).isPresent())
+                .collect(Collectors.toList());
+    }
+
     @Override
     public boolean isAvailable(ResourcePath resource) {
         checkNotNull(resource);
index 8b9952e..7eb189e 100644 (file)
@@ -31,7 +31,6 @@ import org.onosproject.net.resource.ResourceType;
 import org.onosproject.net.resource.link.BandwidthResourceAllocation;
 import org.onosproject.net.resource.link.BandwidthResourceRequest;
 import org.onosproject.net.resource.link.DefaultLinkResourceAllocations;
-import org.onosproject.net.resource.link.LambdaResource;
 import org.onosproject.net.resource.link.LambdaResourceAllocation;
 import org.onosproject.net.resource.link.LambdaResourceRequest;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
@@ -46,15 +45,12 @@ import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.link.MplsLabelResourceRequest;
 import org.slf4j.Logger;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.security.AppGuard.checkPermission;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppPermission.Type.*;
@@ -86,67 +82,6 @@ public class LinkResourceManager
         log.info("Stopped");
     }
 
-    /**
-     * Returns available lambdas on specified link.
-     *
-     * @param link the link
-     * @return available lambdas on specified link
-     */
-    private Set<LambdaResource> getAvailableLambdas(Link link) {
-        checkNotNull(link);
-        Set<ResourceAllocation> resAllocs = store.getFreeResources(link);
-        if (resAllocs == null) {
-            return Collections.emptySet();
-        }
-        Set<LambdaResource> lambdas = new HashSet<>();
-        for (ResourceAllocation res : resAllocs) {
-            if (res.type() == ResourceType.LAMBDA) {
-                lambdas.add(((LambdaResourceAllocation) res).lambda());
-            }
-        }
-        return lambdas;
-    }
-
-
-    /**
-     * Returns available lambdas on specified links.
-     *
-     * @param links the links
-     * @return available lambdas on specified links
-     */
-    private Iterable<LambdaResource> getAvailableLambdas(Iterable<Link> links) {
-        checkNotNull(links);
-        Iterator<Link> i = links.iterator();
-        checkArgument(i.hasNext());
-        Set<LambdaResource> lambdas = new HashSet<>(getAvailableLambdas(i.next()));
-        while (i.hasNext()) {
-            lambdas.retainAll(getAvailableLambdas(i.next()));
-        }
-        return lambdas;
-    }
-
-
-    /**
-     * Returns available MPLS label on specified link.
-     *
-     * @param link the link
-     * @return available MPLS labels on specified link
-     */
-    private Iterable<MplsLabel> getAvailableMplsLabels(Link link) {
-        Set<ResourceAllocation> resAllocs = store.getFreeResources(link);
-        if (resAllocs == null) {
-            return Collections.emptySet();
-        }
-        Set<MplsLabel> mplsLabels = new HashSet<>();
-        for (ResourceAllocation res : resAllocs) {
-            if (res.type() == ResourceType.MPLS_LABEL) {
-
-                mplsLabels.add(((MplsLabelResourceAllocation) res).mplsLabel());
-            }
-        }
-
-        return mplsLabels;
-    }
 
     @Override
     public LinkResourceAllocations requestResources(LinkResourceRequest req) {
@@ -164,26 +99,23 @@ public class LinkResourceManager
                 allocs.add(new BandwidthResourceAllocation(br.bandwidth()));
                 break;
             case LAMBDA:
-                Iterator<LambdaResource> lambdaIterator =
-                        getAvailableLambdas(req.links()).iterator();
-                if (lambdaIterator.hasNext()) {
-                    allocs.add(new LambdaResourceAllocation(lambdaIterator.next()));
-                } else {
-                    log.info("Failed to allocate lambda resource.");
-                    return null;
-                }
+                LambdaResourceRequest lr = (LambdaResourceRequest) r;
+                allocs.add(new LambdaResourceAllocation(lr.lambda()));
                 break;
             case MPLS_LABEL:
                 for (Link link : req.links()) {
                     if (allocsPerLink.get(link) == null) {
                         allocsPerLink.put(link, new HashSet<>());
                     }
-                    Iterator<MplsLabel> mplsIter = getAvailableMplsLabels(link)
-                            .iterator();
-                    if (mplsIter.hasNext()) {
-                        allocsPerLink.get(link)
-                                .add(new MplsLabelResourceAllocation(mplsIter
-                                             .next()));
+
+                    Optional<MplsLabel> label = req.resources(link).stream()
+                            .filter(x -> x.type() == ResourceType.MPLS_LABEL)
+                            .map(x -> (MplsLabelResourceRequest) x)
+                            .map(MplsLabelResourceRequest::mplsLabel)
+                            .findFirst();
+
+                    if (label.isPresent()) {
+                        allocsPerLink.get(link).add(new MplsLabelResourceAllocation(label.get()));
                     } else {
                         log.info("Failed to allocate MPLS resource.");
                         break;
@@ -258,10 +190,12 @@ public class LinkResourceManager
                         ((BandwidthResourceAllocation) alloc).bandwidth()));
                 break;
             case LAMBDA:
-                result.add(new LambdaResourceRequest());
+                result.add(new LambdaResourceRequest(
+                        ((LambdaResourceAllocation) alloc).lambda()));
                 break;
             case MPLS_LABEL:
-                result.add(new MplsLabelResourceRequest());
+                result.add(new MplsLabelResourceRequest(
+                        ((MplsLabelResourceAllocation) alloc).mplsLabel()));
                 break;
             default:
                 break;
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java
new file mode 100644 (file)
index 0000000..06b2c81
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.intent.impl.compiler;
+
+import com.google.common.collect.ImmutableList;
+import org.onlab.packet.MplsLabel;
+import org.onosproject.net.newresource.ResourceAllocation;
+import org.onosproject.net.newresource.ResourceConsumer;
+import org.onosproject.net.newresource.ResourcePath;
+import org.onosproject.net.newresource.ResourceService;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+class MockResourceService implements ResourceService {
+
+    private final Map<ResourcePath, ResourceConsumer> assignment = new HashMap<>();
+
+    @Override
+    public List<ResourceAllocation> allocate(ResourceConsumer consumer, List<ResourcePath> resources) {
+        assignment.putAll(
+                resources.stream().collect(Collectors.toMap(x -> x, x -> consumer))
+        );
+
+        return resources.stream()
+                .map(x -> new ResourceAllocation(x, consumer))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public boolean release(List<ResourceAllocation> allocations) {
+        allocations.forEach(x -> assignment.remove(x.resource()));
+
+        return true;
+    }
+
+    @Override
+    public boolean release(ResourceConsumer consumer) {
+        List<ResourcePath> resources = assignment.entrySet().stream()
+                .filter(x -> x.getValue().equals(consumer))
+                .map(Map.Entry::getKey)
+                .collect(Collectors.toList());
+        List<ResourceAllocation> allocations = resources.stream()
+                .map(x -> new ResourceAllocation(x, consumer))
+                .collect(Collectors.toList());
+
+        return release(allocations);
+    }
+
+    @Override
+    public Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource) {
+        return Optional.ofNullable(assignment.get(resource))
+                .map(x -> new ResourceAllocation(resource, x));
+    }
+
+    @Override
+    public <T> Collection<ResourceAllocation> getResourceAllocations(ResourcePath parent, Class<T> cls) {
+        return assignment.entrySet().stream()
+                .filter(x -> x.getKey().parent().isPresent())
+                .filter(x -> x.getKey().parent().get().equals(parent))
+                .map(x -> new ResourceAllocation(x.getKey(), x.getValue()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public Collection<ResourceAllocation> getResourceAllocations(ResourceConsumer consumer) {
+        return assignment.entrySet().stream()
+                .filter(x -> x.getValue().equals(consumer))
+                .map(x -> new ResourceAllocation(x.getKey(), x.getValue()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public Collection<ResourcePath> getAvailableResources(ResourcePath parent) {
+        ResourcePath resource = ResourcePath.child(parent, MplsLabel.mplsLabel(10));
+        return ImmutableList.of(resource);
+    }
+
+    @Override
+    public boolean isAvailable(ResourcePath resource) {
+        return true;
+    }
+}
index 771a988..6cceee1 100644 (file)
@@ -41,10 +41,8 @@ import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.intent.FlowRuleIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentExtensionService;
-import org.onosproject.net.intent.IntentTestsMocks;
 import org.onosproject.net.intent.MockIdGenerator;
 import org.onosproject.net.intent.MplsPathIntent;
-import org.onosproject.store.trivial.SimpleLinkStore;
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
@@ -52,6 +50,7 @@ import static org.easymock.EasyMock.replay;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
 import static org.onosproject.net.Link.Type.DIRECT;
 import static org.onosproject.net.NetTestTools.APP_ID;
 import static org.onosproject.net.NetTestTools.PID;
@@ -61,10 +60,12 @@ public class MplsPathIntentCompilerTest {
 
     private final ApplicationId appId = new TestApplicationId("test");
 
+    private final ConnectPoint d1pi = connectPoint("s1", 100);
     private final ConnectPoint d1p1 = connectPoint("s1", 0);
     private final ConnectPoint d2p0 = connectPoint("s2", 0);
     private final ConnectPoint d2p1 = connectPoint("s2", 1);
     private final ConnectPoint d3p1 = connectPoint("s3", 1);
+    private final ConnectPoint d3pe = connectPoint("s3", 100);
 
     private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
     private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
@@ -75,8 +76,10 @@ public class MplsPathIntentCompilerTest {
             Optional.of(MplsLabel.mplsLabel(20));
 
     private final List<Link> links = Arrays.asList(
+            createEdgeLink(d1pi, true),
             new DefaultLink(PID, d1p1, d2p0, DIRECT),
-            new DefaultLink(PID, d2p1, d3p1, DIRECT)
+            new DefaultLink(PID, d2p1, d3p1, DIRECT),
+            createEdgeLink(d3pe, false)
     );
 
     private IdGenerator idGenerator = new MockIdGenerator();
@@ -92,8 +95,7 @@ public class MplsPathIntentCompilerTest {
         expect(coreService.registerApplication("org.onosproject.net.intent"))
                 .andReturn(appId);
         sut.coreService = coreService;
-        sut.linkStore = new SimpleLinkStore();
-        sut.resourceService = new IntentTestsMocks.MockResourceService();
+        sut.resourceService = new MockResourceService();
 
         Intent.bindIdGenerator(idGenerator);
 
@@ -128,7 +130,7 @@ public class MplsPathIntentCompilerTest {
         assertThat(compiled, hasSize(1));
 
         Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
-        assertThat(rules, hasSize(1));
+        assertThat(rules, hasSize(3));
 
         FlowRule rule = rules.stream()
                 .filter(x -> x.deviceId().equals(d2p0.deviceId()))
@@ -139,4 +141,5 @@ public class MplsPathIntentCompilerTest {
         sut.deactivate();
 
     }
+
 }
index 1a160d9..3e806a7 100644 (file)
@@ -21,11 +21,19 @@ import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPacket;
+import org.onlab.packet.IPv6;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onlab.packet.ndp.NeighborAdvertisement;
+import org.onlab.packet.ndp.NeighborDiscoveryOptions;
+import org.onlab.packet.ndp.NeighborSolicitation;
 import org.onosproject.incubator.net.intf.Interface;
 import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
@@ -66,9 +74,13 @@ import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -83,6 +95,8 @@ public class ProxyArpManagerTest {
 
     private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1");
     private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2");
+    private static final Ip6Address IP3 = Ip6Address.valueOf("1000::1");
+    private static final Ip6Address IP4 = Ip6Address.valueOf("1000::2");
 
     private static final ProviderId PID = new ProviderId("of", "foo");
 
@@ -90,8 +104,14 @@ public class ProxyArpManagerTest {
     private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
     private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
     private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
+    private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03");
+    private static final MacAddress MAC4 = MacAddress.valueOf("00:00:44:00:00:04");
+    private static final MacAddress SOLICITED_MAC3 = MacAddress.valueOf("33:33:FF:00:00:01");
     private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
     private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
+    private static final HostId HID3 = HostId.hostId(MAC3, VLAN1);
+    private static final HostId HID4 = HostId.hostId(MAC4, VLAN1);
+    private static final HostId SOLICITED_HID3 = HostId.hostId(SOLICITED_MAC3, VLAN1);
 
     private static final DeviceId DID1 = getDeviceId(1);
     private static final DeviceId DID2 = getDeviceId(2);
@@ -222,21 +242,29 @@ public class ProxyArpManagerTest {
 
         for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
             ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
-            Ip4Prefix prefix1 =
-                    Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
-            Ip4Address addr1 =
-                    Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1");
+
+            // Interface address for IPv4
+            Ip4Prefix prefix1 = Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
+            Ip4Address addr1 = Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1");
             Ip4Prefix prefix2 = Ip4Prefix.valueOf("10.0." + (2 * i) + ".0/24");
             Ip4Address addr2 = Ip4Address.valueOf("10.0." + (2 * i) + ".1");
             InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
             InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
-            Interface intf1 = new Interface(cp, Sets.newHashSet(ia1),
+
+            // Interface address for IPv6
+            Ip6Prefix prefix3 = Ip6Prefix.valueOf((2 * i - 1) + "000::0/64");
+            Ip6Address addr3 = Ip6Address.valueOf((2 * i - 1) + "000::1");
+            Ip6Prefix prefix4 = Ip6Prefix.valueOf((2 * i) + "000::0/64");
+            Ip6Address addr4 = Ip6Address.valueOf((2 * i) + "000::1");
+            InterfaceIpAddress ia3 = new InterfaceIpAddress(addr3, prefix3);
+            InterfaceIpAddress ia4 = new InterfaceIpAddress(addr4, prefix4);
+
+            Interface intf1 = new Interface(cp, Sets.newHashSet(ia1, ia3),
                     MacAddress.valueOf(2 * i - 1),
                     VlanId.vlanId((short) 1));
-            Interface intf2 = new Interface(cp, Sets.newHashSet(ia2),
+            Interface intf2 = new Interface(cp, Sets.newHashSet(ia2, ia4),
                     MacAddress.valueOf(2 * i),
                     VlanId.NONE);
-
             interfaces.add(intf1);
             interfaces.add(intf2);
 
@@ -319,6 +347,41 @@ public class ProxyArpManagerTest {
         verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0));
     }
 
+    /**
+     * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
+     * destination host is known.
+     * Verifies the correct NDP reply is sent out the correct port.
+     */
+    @Test
+    public void testReplyKnownIpv6() {
+        //Set the return value of isEdgePoint from the edgemanager.
+        isEdgePointReturn = true;
+
+        Host replyer = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(4),
+                                       Collections.singleton(IP3));
+
+        Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5),
+                                         Collections.singleton(IP4));
+
+        expect(hostService.getHostsByIp(IP3))
+                .andReturn(Collections.singleton(replyer));
+        expect(hostService.getHost(HID4)).andReturn(requestor);
+
+        replay(hostService);
+        replay(interfaceService);
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC4, SOLICITED_MAC3,
+                                       IP4, IP3);
+
+        proxyArp.reply(ndpRequest, getLocation(5));
+
+        assertEquals(1, packetService.packets.size());
+        Ethernet ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT,
+                                     MAC3, MAC4, IP3, IP4);
+        verifyPacketOut(ndpReply, getLocation(5), packetService.packets.get(0));
+    }
+
     /**
      * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
      * destination host is not known.
@@ -337,7 +400,6 @@ public class ProxyArpManagerTest {
                 .andReturn(Collections.emptySet());
         expect(hostService.getHost(HID2)).andReturn(requestor);
 
-
         replay(hostService);
         replay(interfaceService);
 
@@ -353,6 +415,41 @@ public class ProxyArpManagerTest {
         verifyFlood(arpRequest);
     }
 
+    /**
+     * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
+     * destination host is not known.
+     * Verifies the NDP request is flooded out the correct edge ports.
+     */
+    @Test
+    public void testReplyUnknownIpv6() {
+        isEdgePointReturn = true;
+
+        Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5),
+                                         Collections.singleton(IP4));
+
+        expect(hostService.getHostsByIp(IP3))
+                .andReturn(Collections.emptySet());
+        expect(interfaceService.getInterfacesByIp(IP4))
+                .andReturn(Collections.emptySet());
+        expect(hostService.getHost(HID4)).andReturn(requestor);
+
+        replay(hostService);
+        replay(interfaceService);
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC4, SOLICITED_MAC3,
+                                       IP4, IP3);
+
+        //Setup the set of edge ports to be used in the reply method
+        getEdgePointsNoArg = Lists.newLinkedList();
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1)));
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1)));
+
+        proxyArp.reply(ndpRequest, getLocation(6));
+
+        verifyFlood(ndpRequest);
+    }
+
     /**
      * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
      * destination host is known for that IP address, but is not on the same
@@ -388,6 +485,46 @@ public class ProxyArpManagerTest {
         verifyFlood(arpRequest);
     }
 
+    /**
+     * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
+     * destination host is known for that IP address, but is not on the same
+     * VLAN as the source host.
+     * Verifies the NDP request is flooded out the correct edge ports.
+     */
+    @Test
+    public void testReplyDifferentVlanIpv6() {
+
+        Host replyer = new DefaultHost(PID, HID3, MAC3, VLAN2, getLocation(4),
+                                       Collections.singleton(IP3));
+
+        Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5),
+                                         Collections.singleton(IP4));
+
+        expect(hostService.getHostsByIp(IP3))
+                .andReturn(Collections.singleton(replyer));
+        expect(interfaceService.getInterfacesByIp(IP4))
+                .andReturn(Collections.emptySet());
+        expect(hostService.getHost(HID4)).andReturn(requestor);
+
+        replay(hostService);
+        replay(interfaceService);
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC4, SOLICITED_MAC3,
+                                       IP4, IP3);
+
+        //Setup for flood test
+        getEdgePointsNoArg = Lists.newLinkedList();
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1)));
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1)));
+        proxyArp.reply(ndpRequest, getLocation(6));
+
+        verifyFlood(ndpRequest);
+    }
+
+    /**
+     * Test ARP request from external network to an internal host.
+     */
     @Test
     public void testReplyToRequestForUs() {
         Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254");
@@ -422,6 +559,63 @@ public class ProxyArpManagerTest {
         verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
     }
 
+    /**
+     * Test NDP request from external network to an internal host.
+     */
+    @Test
+    public void testReplyToRequestForUsIpv6() {
+        Ip6Address theirIp = Ip6Address.valueOf("1000::ffff");
+        Ip6Address ourFirstIp = Ip6Address.valueOf("1000::1");
+        Ip6Address ourSecondIp = Ip6Address.valueOf("2000::1");
+        MacAddress firstMac = MacAddress.valueOf(1L);
+        MacAddress secondMac = MacAddress.valueOf(2L);
+
+        Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
+                                         Collections.singleton(theirIp));
+
+        expect(hostService.getHost(HID2)).andReturn(requestor);
+        expect(hostService.getHostsByIp(ourFirstIp))
+                .andReturn(Collections.singleton(requestor));
+        replay(hostService);
+        replay(interfaceService);
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC2,
+                                       MacAddress.valueOf("33:33:ff:00:00:01"),
+                                       theirIp,
+                                       ourFirstIp);
+        isEdgePointReturn = true;
+        proxyArp.reply(ndpRequest, LOC1);
+        assertEquals(1, packetService.packets.size());
+
+        Ethernet ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT,
+                                     firstMac,
+                                     MAC2,
+                                     ourFirstIp,
+                                     theirIp);
+        verifyPacketOut(ndpReply, LOC1, packetService.packets.get(0));
+
+        // Test a request for the second address on that port
+        packetService.packets.clear();
+        ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                              MAC2,
+                                       MacAddress.valueOf("33:33:ff:00:00:01"),
+                                       theirIp,
+                                       ourSecondIp);
+        proxyArp.reply(ndpRequest, LOC1);
+        assertEquals(1, packetService.packets.size());
+
+        ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT,
+                                     secondMac,
+                                     MAC2,
+                                     ourSecondIp,
+                                     theirIp);
+        verifyPacketOut(ndpReply, LOC1, packetService.packets.get(0));
+    }
+
+    /**
+     * Request for a valid external IPv4 address but coming in the wrong port.
+     */
     @Test
     public void testReplyExternalPortBadRequest() {
         replay(hostService); // no further host service expectations
@@ -442,6 +636,38 @@ public class ProxyArpManagerTest {
         assertEquals(0, packetService.packets.size());
     }
 
+    /**
+     * Request for a valid external IPv6 address but coming in the wrong port.
+     */
+    @Test
+    public void testReplyExternalPortBadRequestIpv6() {
+        replay(hostService); // no further host service expectations
+        replay(interfaceService);
+
+        Ip6Address theirIp = Ip6Address.valueOf("1000::ffff");
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC1,
+                                       MacAddress.valueOf("33:33:ff:00:00:01"),
+                                       theirIp,
+                                       Ip6Address.valueOf("3000::1"));
+        proxyArp.reply(ndpRequest, LOC1);
+        assertEquals(0, packetService.packets.size());
+
+        // Request for a valid internal IP address but coming in an external port
+        packetService.packets.clear();
+        ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC1,
+                                       MacAddress.valueOf("33:33:ff:00:00:01"),
+                                       theirIp,
+                                       IP3);
+        proxyArp.reply(ndpRequest, LOC1);
+        assertEquals(0, packetService.packets.size());
+    }
+
+    /**
+     * Test ARP request from internal network to an external host.
+     */
     @Test
     public void testReplyToRequestFromUs() {
         Ip4Address ourIp = Ip4Address.valueOf("10.0.1.1");
@@ -473,6 +699,48 @@ public class ProxyArpManagerTest {
         assertEquals(0, packetService.packets.size());
     }
 
+    /**
+     * Test NDP request from internal network to an external host.
+     */
+    @Test
+    public void testReplyToRequestFromUsIpv6() {
+        Ip6Address ourIp = Ip6Address.valueOf("1000::1");
+        MacAddress ourMac = MacAddress.valueOf(1L);
+        Ip6Address theirIp = Ip6Address.valueOf("1000::100");
+
+        expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
+        expect(interfaceService.getInterfacesByIp(ourIp))
+                .andReturn(Collections.singleton(new Interface(getLocation(1),
+                        Collections.singleton(new InterfaceIpAddress(
+                                ourIp,
+                                IpPrefix.valueOf("1000::1/64"))),
+                                ourMac,
+                                VLAN1)));
+        expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null);
+        replay(hostService);
+        replay(interfaceService);
+
+        // This is a request from something inside our network (like a BGP
+        // daemon) to an external host.
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       ourMac,
+                                       MacAddress.valueOf("33:33:ff:00:00:01"),
+                                       ourIp,
+                                       theirIp);
+
+        //Ensure the packet is allowed through (it is not to an internal port)
+        isEdgePointReturn = true;
+
+        proxyArp.reply(ndpRequest, getLocation(5));
+        assertEquals(1, packetService.packets.size());
+        verifyPacketOut(ndpRequest, getLocation(1), packetService.packets.get(0));
+
+        // The same request from a random external port should fail
+        packetService.packets.clear();
+        proxyArp.reply(ndpRequest, getLocation(2));
+        assertEquals(0, packetService.packets.size());
+    }
+
     /**
      * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
      * destination host is known.
@@ -500,6 +768,35 @@ public class ProxyArpManagerTest {
         verifyPacketOut(arpRequest, LOC1, packet);
     }
 
+    /**
+     * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
+     * destination host is known.
+     * Verifies the correct ARP request is sent out the correct port.
+     */
+    @Test
+    public void testForwardToHostIpv6() {
+        Host host1 = new DefaultHost(PID, HID3, MAC3, VLAN1, LOC1,
+                                     Collections.singleton(IP3));
+        Host host2 = new DefaultHost(PID, HID4, MAC4, VLAN1, LOC2,
+                                     Collections.singleton(IP4));
+
+        expect(hostService.getHost(SOLICITED_HID3)).andReturn(host1);
+        expect(hostService.getHost(HID4)).andReturn(host2);
+        replay(hostService);
+        replay(interfaceService);
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC4, SOLICITED_MAC3,
+                                       IP4, IP3);
+
+        proxyArp.forward(ndpRequest, LOC2);
+
+        assertEquals(1, packetService.packets.size());
+        OutboundPacket packet = packetService.packets.get(0);
+
+        verifyPacketOut(ndpRequest, LOC1, packet);
+    }
+
     /**
      * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
      * destination host is not known.
@@ -525,6 +822,33 @@ public class ProxyArpManagerTest {
         verifyFlood(arpRequest);
     }
 
+    /**
+     * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
+     * destination host is not known.
+     * Verifies the correct NDP request is flooded out the correct edge ports.
+     */
+    @Test
+    public void testForwardFloodIpv6() {
+        expect(hostService.getHost(SOLICITED_HID3)).andReturn(null);
+        replay(hostService);
+        replay(interfaceService);
+
+        Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION,
+                                       MAC4, SOLICITED_MAC3,
+                                       IP4, IP3);
+
+        //populate the list of edges when so that when forward hits flood in the manager it contains the values
+        //that should continue on
+        getEdgePointsNoArg = Lists.newLinkedList();
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("3"), PortNumber.portNumber(1)));
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1)));
+        getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1)));
+
+        proxyArp.forward(ndpRequest, getLocation(6));
+
+        verifyFlood(ndpRequest);
+    }
+
     /**
      * Verifies that the given packet was flooded out all available edge ports,
      * except for the input port.
@@ -625,6 +949,61 @@ public class ProxyArpManagerTest {
         return eth;
     }
 
+    /**
+     * Builds an NDP packet with the given parameters.
+     *
+     * @param type NeighborSolicitation or NeighborAdvertisement
+     * @param srcMac source MAC address
+     * @param dstMac destination MAC address, or null if this is a request
+     * @param srcIp  source IP address
+     * @param dstIp  destination IP address
+     * @return the NDP packet
+     */
+    private Ethernet buildNDP(byte type, MacAddress srcMac, MacAddress dstMac,
+                              Ip6Address srcIp, Ip6Address dstIp) {
+        assertThat(type, anyOf(
+                is(ICMP6.NEIGHBOR_SOLICITATION),
+                is(ICMP6.NEIGHBOR_ADVERTISEMENT)
+        ));
+        assertNotNull(srcMac);
+        assertNotNull(dstMac);
+        assertNotNull(srcIp);
+        assertNotNull(dstIp);
+
+        IPacket ndp;
+        if (type == ICMP6.NEIGHBOR_SOLICITATION) {
+            ndp = new NeighborSolicitation().setTargetAddress(dstIp.toOctets());
+        } else {
+            ndp = new NeighborAdvertisement()
+                    .setSolicitedFlag((byte) 1)
+                    .setOverrideFlag((byte) 1)
+                    .setTargetAddress(srcIp.toOctets())
+                    .addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
+                       srcMac.toBytes());
+        }
+
+        ICMP6 icmp6 = new ICMP6();
+        icmp6.setIcmpType(type);
+        icmp6.setIcmpCode((byte) 0);
+        icmp6.setPayload(ndp);
+
+        IPv6 ipv6 = new IPv6();
+        ipv6.setDestinationAddress(dstIp.toOctets());
+        ipv6.setSourceAddress(srcIp.toOctets());
+        ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6);
+        ipv6.setHopLimit((byte) 255);
+        ipv6.setPayload(icmp6);
+
+        Ethernet eth = new Ethernet();
+        eth.setDestinationMACAddress(dstMac);
+        eth.setSourceMACAddress(srcMac);
+        eth.setEtherType(Ethernet.TYPE_IPV6);
+        eth.setVlanID(VLAN1.toShort());
+        eth.setPayload(ipv6);
+
+        return eth;
+    }
+
     /**
      * Test PacketService implementation that simply stores OutboundPackets
      * passed to {@link #emit(OutboundPacket)} for later verification.
index cc293da..f2ec2a7 100644 (file)
@@ -71,7 +71,7 @@
         <dependency>
             <groupId>org.mapdb</groupId>
             <artifactId>mapdb</artifactId>
-            <version>1.0.7</version>
+            <version>1.0.8</version>
         </dependency>
 
         <dependency>
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java
deleted file mode 100644 (file)
index 75f05a3..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.store.cluster.impl;
-
-import java.util.Set;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Cluster definition.
- */
-public class ClusterDefinition {
-
-    private Set<NodeInfo> nodes;
-    private String ipPrefix;
-
-    /**
-     * Creates a new cluster definition.
-     * @param nodes cluster nodes information
-     * @param ipPrefix ip prefix common to all cluster nodes
-     * @return cluster definition
-     */
-    public static ClusterDefinition from(Set<NodeInfo> nodes, String ipPrefix) {
-        ClusterDefinition definition = new ClusterDefinition();
-        definition.ipPrefix = ipPrefix;
-        definition.nodes = ImmutableSet.copyOf(nodes);
-        return definition;
-    }
-
-    /**
-     * Returns set of cluster nodes info.
-     * @return cluster nodes info
-     */
-    public Set<NodeInfo> getNodes() {
-        return ImmutableSet.copyOf(nodes);
-    }
-
-    /**
-     * Returns ipPrefix in dotted decimal notion.
-     * @return ip prefix
-     */
-    public String getIpPrefix() {
-        return ipPrefix;
-    }
-}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java
deleted file mode 100644 (file)
index 8b0001d..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.store.cluster.impl;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Service;
-import org.onlab.packet.IpAddress;
-import org.onosproject.cluster.ClusterDefinitionService;
-import org.onosproject.cluster.ControllerNode;
-import org.onosproject.cluster.DefaultControllerNode;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.store.consistent.impl.DatabaseDefinition;
-import org.onosproject.store.consistent.impl.DatabaseDefinitionStore;
-import org.slf4j.Logger;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Enumeration;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static java.net.NetworkInterface.getNetworkInterfaces;
-import static java.util.Collections.list;
-import static org.onosproject.cluster.DefaultControllerNode.DEFAULT_PORT;
-import static org.onosproject.store.consistent.impl.DatabaseManager.PARTITION_DEFINITION_FILE;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Implementation of ClusterDefinitionService.
- */
-@Component(immediate = true)
-@Service
-public class ClusterDefinitionManager implements ClusterDefinitionService {
-
-    public static final String CLUSTER_DEFINITION_FILE = "../config/cluster.json";
-    private static final String ONOS_NIC = "ONOS_NIC";
-    private static final Logger log = getLogger(ClusterDefinitionManager.class);
-    private ControllerNode localNode;
-    private Set<ControllerNode> seedNodes;
-
-    @Activate
-    public void activate() {
-        File clusterDefinitionFile = new File(CLUSTER_DEFINITION_FILE);
-        ClusterDefinitionStore clusterDefinitionStore =
-                new ClusterDefinitionStore(clusterDefinitionFile.getPath());
-
-        if (!clusterDefinitionFile.exists()) {
-            createDefaultClusterDefinition(clusterDefinitionStore);
-        }
-
-        try {
-            ClusterDefinition clusterDefinition = clusterDefinitionStore.read();
-            establishSelfIdentity(clusterDefinition);
-            seedNodes = ImmutableSet
-                    .copyOf(clusterDefinition.getNodes())
-                    .stream()
-                    .filter(n -> !localNode.id().equals(new NodeId(n.getId())))
-                    .map(n -> new DefaultControllerNode(new NodeId(n.getId()),
-                                                        IpAddress.valueOf(n.getIp()),
-                                                        n.getTcpPort()))
-                    .collect(Collectors.toSet());
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to read cluster definition.", e);
-        }
-
-        log.info("Started");
-    }
-
-    @Deactivate
-    public void deactivate() {
-        log.info("Stopped");
-    }
-
-    @Override
-    public ControllerNode localNode() {
-        return localNode;
-    }
-
-    @Override
-    public Set<ControllerNode> seedNodes() {
-        return seedNodes;
-    }
-
-    @Override
-    public void formCluster(Set<ControllerNode> nodes, String ipPrefix) {
-        try {
-            Set<NodeInfo> infos = Sets.newHashSet();
-            nodes.forEach(n -> infos.add(NodeInfo.from(n.id().toString(),
-                                                       n.ip().toString(),
-                                                       n.tcpPort())));
-
-            ClusterDefinition cdef = ClusterDefinition.from(infos, ipPrefix);
-            new ClusterDefinitionStore(CLUSTER_DEFINITION_FILE).write(cdef);
-
-            DatabaseDefinition ddef = DatabaseDefinition.from(infos);
-            new DatabaseDefinitionStore(PARTITION_DEFINITION_FILE).write(ddef);
-        } catch (IOException e) {
-            log.error("Unable to form cluster", e);
-        }
-    }
-
-    private IpAddress findLocalIp(ClusterDefinition clusterDefinition) throws SocketException {
-        Enumeration<NetworkInterface> interfaces =
-                NetworkInterface.getNetworkInterfaces();
-        while (interfaces.hasMoreElements()) {
-            NetworkInterface iface = interfaces.nextElement();
-            Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
-            while (inetAddresses.hasMoreElements()) {
-                IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement());
-                if (clusterDefinition.getNodes().stream()
-                        .map(NodeInfo::getIp)
-                        .map(IpAddress::valueOf)
-                        .anyMatch(nodeIp -> ip.equals(nodeIp))) {
-                    return ip;
-                }
-            }
-        }
-        throw new IllegalStateException("Unable to determine local ip");
-    }
-
-    private void establishSelfIdentity(ClusterDefinition clusterDefinition) {
-        try {
-            IpAddress ip = findLocalIp(clusterDefinition);
-            localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip);
-        } catch (SocketException e) {
-            throw new IllegalStateException("Cannot determine local IP", e);
-        }
-    }
-
-    private void createDefaultClusterDefinition(ClusterDefinitionStore store) {
-        // Assumes IPv4 is returned.
-        String ip = getSiteLocalAddress();
-        String ipPrefix = ip.replaceFirst("\\.[0-9]*$", ".*");
-        NodeInfo node = NodeInfo.from(ip, ip, DEFAULT_PORT);
-        try {
-            store.write(ClusterDefinition.from(ImmutableSet.of(node), ipPrefix));
-        } catch (IOException e) {
-            log.warn("Unable to write default cluster definition", e);
-        }
-    }
-
-    /**
-     * Returns the address that matches the IP prefix given in ONOS_NIC
-     * environment variable if one was specified, or the first site local
-     * address if one can be found or the loopback address otherwise.
-     *
-     * @return site-local address in string form
-     */
-    public static String getSiteLocalAddress() {
-        try {
-            String ipPrefix = System.getenv(ONOS_NIC);
-            for (NetworkInterface nif : list(getNetworkInterfaces())) {
-                for (InetAddress address : list(nif.getInetAddresses())) {
-                    IpAddress ip = IpAddress.valueOf(address);
-                    if (ipPrefix == null && address.isSiteLocalAddress() ||
-                            ipPrefix != null && matchInterface(ip.toString(), ipPrefix)) {
-                        return ip.toString();
-                    }
-                }
-            }
-        } catch (SocketException e) {
-            log.error("Unable to get network interfaces", e);
-        }
-
-        return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
-    }
-
-    // Indicates whether the specified interface address matches the given prefix.
-    // FIXME: Add a facility to IpPrefix to make this more robust
-    private static boolean matchInterface(String ip, String ipPrefix) {
-        String s = ipPrefix.replaceAll("\\.\\*", "");
-        return ip.startsWith(s);
-    }
-}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java
deleted file mode 100644 (file)
index 2a2f4dc..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2014-2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.store.cluster.impl;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.io.Files;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Allows for reading and writing cluster definition as a JSON file.
- */
-public class ClusterDefinitionStore {
-
-    private final File file;
-
-    /**
-     * Creates a reader/writer of the cluster definition file.
-     * @param filePath location of the definition file
-     */
-    public ClusterDefinitionStore(String filePath) {
-        file = new File(filePath);
-    }
-
-    /**
-     * Returns the cluster definition.
-     * @return cluster definition
-     * @throws IOException when I/O exception of some sort has occurred
-     */
-    public ClusterDefinition read() throws IOException {
-        ObjectMapper mapper = new ObjectMapper();
-        return mapper.readValue(file, ClusterDefinition.class);
-    }
-
-    /**
-     * Writes the specified cluster definition to file.
-     * @param definition cluster definition
-     * @throws IOException when I/O exception of some sort has occurred
-     */
-    public void write(ClusterDefinition definition) throws IOException {
-        checkNotNull(definition);
-        // write back to file
-        Files.createParentDirs(file);
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.writeValue(file, definition);
-    }
-}
index 859efeb..3bb6a70 100644 (file)
@@ -27,8 +27,8 @@ import org.apache.felix.scr.annotations.Service;
 import org.joda.time.DateTime;
 import org.onlab.packet.IpAddress;
 import org.onlab.util.KryoNamespace;
-import org.onosproject.cluster.ClusterDefinitionService;
 import org.onosproject.cluster.ClusterEvent;
+import org.onosproject.cluster.ClusterMetadataService;
 import org.onosproject.cluster.ClusterStore;
 import org.onosproject.cluster.ClusterStoreDelegate;
 import org.onosproject.cluster.ControllerNode;
@@ -99,14 +99,14 @@ public class DistributedClusterStore
     private ControllerNode localNode;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ClusterDefinitionService clusterDefinitionService;
+    protected ClusterMetadataService clusterMetadataService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MessagingService messagingService;
 
     @Activate
     public void activate() {
-        localNode = clusterDefinitionService.localNode();
+        localNode = clusterMetadataService.getLocalNode();
 
         messagingService.registerHandler(HEARTBEAT_MESSAGE,
                                          new HeartbeatMessageHandler(), heartBeatMessageHandler);
@@ -116,9 +116,6 @@ public class DistributedClusterStore
         heartBeatSender.scheduleWithFixedDelay(this::heartbeat, 0,
                                                HEARTBEAT_INTERVAL_MS, TimeUnit.MILLISECONDS);
 
-        addNode(localNode);
-        updateState(localNode.id(), State.ACTIVE);
-
         log.info("Started");
     }
 
@@ -188,7 +185,7 @@ public class DistributedClusterStore
 
     private void addNode(ControllerNode node) {
         allNodes.put(node.id(), node);
-        updateState(node.id(), State.INACTIVE);
+        updateState(node.id(), node.equals(localNode) ? State.ACTIVE : State.INACTIVE);
         notifyDelegate(new ClusterEvent(ClusterEvent.Type.INSTANCE_ADDED, node));
     }
 
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java
new file mode 100644 (file)
index 0000000..9f6c413
--- /dev/null
@@ -0,0 +1,221 @@
+package org.onosproject.store.cluster.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.net.NetworkInterface.getNetworkInterfaces;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterMetadata;
+import org.onosproject.cluster.ClusterMetadataEvent;
+import org.onosproject.cluster.ClusterMetadataStore;
+import org.onosproject.cluster.ClusterMetadataStoreDelegate;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.cluster.DefaultControllerNode;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.cluster.Partition;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+/**
+ * ClusterMetadataStore backed by a local file.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class StaticClusterMetadataStore
+    extends AbstractStore<ClusterMetadataEvent, ClusterMetadataStoreDelegate>
+    implements ClusterMetadataStore {
+
+    private final Logger log = getLogger(getClass());
+    private static final String CLUSTER_METADATA_FILE = "../config/cluster.json";
+    private static final int DEFAULT_ONOS_PORT = 9876;
+    private final File metadataFile = new File(CLUSTER_METADATA_FILE);
+    private AtomicReference<ClusterMetadata> metadata = new AtomicReference<>();
+    private ObjectMapper mapper;
+    private long version;
+
+    @Activate
+    public void activate() {
+        mapper = new ObjectMapper();
+        SimpleModule module = new SimpleModule();
+        module.addSerializer(NodeId.class, new NodeIdSerializer());
+        module.addDeserializer(NodeId.class, new NodeIdDeserializer());
+        module.addSerializer(ControllerNode.class, new ControllerNodeSerializer());
+        module.addDeserializer(ControllerNode.class, new ControllerNodeDeserializer());
+        mapper.registerModule(module);
+        File metadataFile = new File(CLUSTER_METADATA_FILE);
+        if (metadataFile.exists()) {
+            try {
+                metadata.set(mapper.readValue(metadataFile, ClusterMetadata.class));
+                version = metadataFile.lastModified();
+            } catch (IOException e) {
+                Throwables.propagate(e);
+            }
+        } else {
+            String localIp = getSiteLocalAddress();
+            ControllerNode localNode =
+                    new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT);
+            metadata.set(ClusterMetadata.builder()
+                    .withName("default")
+                    .withControllerNodes(Arrays.asList(localNode))
+                    .withPartitions(Lists.newArrayList(new Partition("p1", Lists.newArrayList(localNode.id()))))
+                    .build());
+            version = System.currentTimeMillis();
+        }
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public void setDelegate(ClusterMetadataStoreDelegate delegate) {
+        checkNotNull(delegate, "Delegate cannot be null");
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void unsetDelegate(ClusterMetadataStoreDelegate delegate) {
+        this.delegate = null;
+    }
+
+    @Override
+    public boolean hasDelegate() {
+        return this.delegate != null;
+    }
+
+    @Override
+    public Versioned<ClusterMetadata> getClusterMetadata() {
+        return new Versioned<>(metadata.get(), version);
+    }
+
+    @Override
+    public void setClusterMetadata(ClusterMetadata metadata) {
+        checkNotNull(metadata);
+        try {
+            Files.createParentDirs(metadataFile);
+            mapper.writeValue(metadataFile, metadata);
+            this.metadata.set(metadata);
+        } catch (IOException e) {
+            Throwables.propagate(e);
+        }
+    }
+
+    @Override
+    public void setActiveReplica(String partitionId, NodeId nodeId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unsetActiveReplica(String partitionId, NodeId nodeId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection<NodeId> getActiveReplicas(String partitionId) {
+        return metadata.get().getPartitions()
+                       .stream()
+                       .filter(r -> r.getName().equals(partitionId))
+                       .findFirst()
+                       .map(r -> r.getMembers())
+                       .orElse(null);
+    }
+
+    private static class ControllerNodeSerializer extends JsonSerializer<ControllerNode> {
+        @Override
+        public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider)
+          throws IOException, JsonProcessingException {
+            jgen.writeStartObject();
+            jgen.writeStringField("id", node.id().toString());
+            jgen.writeStringField("ip", node.ip().toString());
+            jgen.writeNumberField("port", node.tcpPort());
+            jgen.writeEndObject();
+        }
+    }
+
+    private static class ControllerNodeDeserializer extends JsonDeserializer<ControllerNode> {
+        @Override
+        public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt)
+                throws IOException, JsonProcessingException {
+            JsonNode node = jp.getCodec().readTree(jp);
+            NodeId nodeId = new NodeId(node.get("id").textValue());
+            IpAddress ip = IpAddress.valueOf(node.get("ip").textValue());
+            int port = node.get("port").asInt();
+            return new DefaultControllerNode(nodeId, ip, port);
+        }
+    }
+
+    private static class NodeIdSerializer extends JsonSerializer<NodeId> {
+        @Override
+        public void serialize(NodeId nodeId, JsonGenerator jgen, SerializerProvider provider)
+          throws IOException, JsonProcessingException {
+            jgen.writeString(nodeId.toString());
+        }
+    }
+
+    private class NodeIdDeserializer extends JsonDeserializer<NodeId> {
+        @Override
+        public NodeId deserialize(JsonParser jp, DeserializationContext ctxt)
+          throws IOException, JsonProcessingException {
+            JsonNode node = jp.getCodec().readTree(jp);
+            return new NodeId(node.asText());
+        }
+    }
+
+
+    private static String getSiteLocalAddress() {
+        Function<NetworkInterface, IpAddress> ipLookup = nif -> {
+            for (InetAddress address : Collections.list(nif.getInetAddresses())) {
+                if (address.isSiteLocalAddress()) {
+                    return IpAddress.valueOf(address);
+                }
+            }
+            return null;
+        };
+        try {
+            IpAddress ip = ipLookup.apply(NetworkInterface.getByName("eth0"));
+            if (ip != null) {
+                return ip.toString();
+            }
+            for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) {
+                ip = ipLookup.apply(nif);
+                if (ip != null) {
+                    return ip.toString();
+                }
+            }
+        } catch (Exception e) {
+            throw new IllegalStateException("Unable to get network interfaces", e);
+        }
+        return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
+    }
+}
\ No newline at end of file
index ffdd25f..ddb45f7 100644 (file)
@@ -22,7 +22,7 @@ import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.nio.service.IOLoopMessaging;
-import org.onosproject.cluster.ClusterDefinitionService;
+import org.onosproject.cluster.ClusterMetadataService;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.store.cluster.messaging.Endpoint;
 import org.slf4j.Logger;
@@ -38,11 +38,11 @@ public class IOLoopMessagingManager extends IOLoopMessaging {
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ClusterDefinitionService clusterDefinitionService;
+    protected ClusterMetadataService clusterMetadataService;
 
     @Activate
     public void activate() throws Exception {
-        ControllerNode localNode = clusterDefinitionService.localNode();
+        ControllerNode localNode = clusterMetadataService.getLocalNode();
         super.start(new Endpoint(localNode.ip(), localNode.tcpPort()));
         log.info("Started");
     }
index 9328817..23c8186 100644 (file)
@@ -16,6 +16,7 @@
 package org.onosproject.store.cluster.messaging.impl;
 
 import com.google.common.base.Strings;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -23,7 +24,7 @@ import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.netty.NettyMessaging;
-import org.onosproject.cluster.ClusterDefinitionService;
+import org.onosproject.cluster.ClusterMetadataService;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.store.cluster.messaging.Endpoint;
 import org.slf4j.Logger;
@@ -41,11 +42,11 @@ public class NettyMessagingManager extends NettyMessaging {
     private static final short MIN_KS_LENGTH = 6;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ClusterDefinitionService clusterDefinitionService;
+    protected ClusterMetadataService clusterMetadataService;
 
     @Activate
     public void activate() throws Exception {
-        ControllerNode localNode = clusterDefinitionService.localNode();
+        ControllerNode localNode = clusterMetadataService.getLocalNode();
         getTLSParameters();
         super.start(new Endpoint(localNode.ip(), localNode.tcpPort()));
         log.info("Started");
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java
deleted file mode 100644 (file)
index 11b56c1..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.store.consistent.impl;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import org.onosproject.store.cluster.impl.NodeInfo;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Partitioned database configuration.
- */
-public class DatabaseDefinition {
-    private Map<String, Set<NodeInfo>> partitions;
-    private Set<NodeInfo> nodes;
-
-    /**
-     * Creates a new DatabaseDefinition.
-     *
-     * @param partitions partition map
-     * @param nodes      set of nodes
-     * @return database definition
-     */
-    public static DatabaseDefinition from(Map<String, Set<NodeInfo>> partitions,
-                                          Set<NodeInfo> nodes) {
-        checkNotNull(partitions);
-        checkNotNull(nodes);
-        DatabaseDefinition definition = new DatabaseDefinition();
-        definition.partitions = ImmutableMap.copyOf(partitions);
-        definition.nodes = ImmutableSet.copyOf(nodes);
-        return definition;
-    }
-
-    /**
-     * Creates a new DatabaseDefinition using default partitions.
-     *
-     * @param nodes set of nodes
-     * @return database definition
-     */
-    public static DatabaseDefinition from(Set<NodeInfo> nodes) {
-        return from(generateDefaultPartitions(nodes), nodes);
-    }
-
-    /**
-     * Returns the map of database partitions.
-     *
-     * @return db partition map
-     */
-    public Map<String, Set<NodeInfo>> getPartitions() {
-        return partitions;
-    }
-
-    /**
-     * Returns the set of nodes.
-     *
-     * @return nodes
-     */
-    public Set<NodeInfo> getNodes() {
-        return nodes;
-    }
-
-
-    /**
-     * Generates set of default partitions using permutations of the nodes.
-     *
-     * @param nodes information about cluster nodes
-     * @return default partition map
-     */
-    private static Map<String, Set<NodeInfo>> generateDefaultPartitions(Set<NodeInfo> nodes) {
-        List<NodeInfo> sorted = new ArrayList<>(nodes);
-        Collections.sort(sorted, (o1, o2) -> o1.getId().compareTo(o2.getId()));
-        Map<String, Set<NodeInfo>> partitions = Maps.newHashMap();
-
-        int length = nodes.size();
-        int count = 3;
-        for (int i = 0; i < length; i++) {
-            Set<NodeInfo> set = new HashSet<>(count);
-            for (int j = 0; j < count; j++) {
-                set.add(sorted.get((i + j) % length));
-            }
-            partitions.put("p" + (i + 1), set);
-        }
-        return partitions;
-    }
-
-}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java
deleted file mode 100644 (file)
index b77667b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.store.consistent.impl;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import java.io.File;
-import java.io.IOException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.io.Files;
-
-/**
- * Allows for reading and writing partitioned database definition as a JSON file.
- */
-public class DatabaseDefinitionStore {
-
-    private final File file;
-
-    /**
-     * Creates a reader/writer of the database definition file.
-     *
-     * @param filePath location of the definition file
-     */
-    public DatabaseDefinitionStore(String filePath) {
-        file = new File(checkNotNull(filePath));
-    }
-
-    /**
-     * Creates a reader/writer of the database definition file.
-     *
-     * @param filePath location of the definition file
-     */
-    public DatabaseDefinitionStore(File filePath) {
-        file = checkNotNull(filePath);
-    }
-
-    /**
-     * Returns the database definition.
-     *
-     * @return database definition
-     * @throws IOException when I/O exception of some sort has occurred.
-     */
-    public DatabaseDefinition read() throws IOException {
-        ObjectMapper mapper = new ObjectMapper();
-        return mapper.readValue(file, DatabaseDefinition.class);
-    }
-
-    /**
-     * Writes the specified database definition to file.
-     *
-     * @param definition database definition
-     * @throws IOException when I/O exception of some sort has occurred.
-     */
-    public void write(DatabaseDefinition definition) throws IOException {
-        checkNotNull(definition);
-        // write back to file
-        Files.createParentDirs(file);
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.writeValue(file, definition);
-    }
-}
index 6ea7c22..3e89635 100644 (file)
@@ -18,7 +18,6 @@ package org.onosproject.store.consistent.impl;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
@@ -50,12 +49,12 @@ import org.apache.felix.scr.annotations.Service;
 import org.onosproject.app.ApplicationEvent;
 import org.onosproject.app.ApplicationListener;
 import org.onosproject.app.ApplicationService;
+import org.onosproject.cluster.ClusterMetadataService;
 import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.IdGenerator;
-import org.onosproject.store.cluster.impl.ClusterDefinitionManager;
-import org.onosproject.store.cluster.impl.NodeInfo;
 import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
 import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl;
 import org.onosproject.store.service.AtomicCounterBuilder;
@@ -73,8 +72,6 @@ import org.onosproject.store.service.Transaction;
 import org.onosproject.store.service.TransactionContextBuilder;
 import org.slf4j.Logger;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -99,8 +96,6 @@ public class DatabaseManager implements StorageService, StorageAdminService {
 
     private final Logger log = getLogger(getClass());
 
-    public static final int COPYCAT_TCP_PORT = 9876;
-    public static final String PARTITION_DEFINITION_FILE = "../config/tablets.json";
     public static final String BASE_PARTITION_NAME = "p0";
 
     private static final int RAFT_ELECTION_TIMEOUT_MILLIS = 3000;
@@ -121,6 +116,9 @@ public class DatabaseManager implements StorageService, StorageAdminService {
     private final Multimap<ApplicationId, DefaultAsyncConsistentMap> mapsByApplication =
             Multimaps.synchronizedMultimap(ArrayListMultimap.create());
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterMetadataService clusterMetadataService;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ClusterService clusterService;
 
@@ -130,8 +128,9 @@ public class DatabaseManager implements StorageService, StorageAdminService {
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ClusterCommunicationService clusterCommunicator;
 
-    protected String nodeToUri(NodeInfo node) {
-        return String.format("onos://%s:%d", node.getIp(), node.getTcpPort());
+    protected String nodeIdToUri(NodeId nodeId) {
+        ControllerNode node = clusterService.getNode(nodeId);
+        return String.format("onos://%s:%d", node.ip(), node.tcpPort());
     }
 
     protected void bindApplicationService(ApplicationService service) {
@@ -147,30 +146,22 @@ public class DatabaseManager implements StorageService, StorageAdminService {
     @Activate
     public void activate() {
         localNodeId = clusterService.getLocalNode().id();
-        // load database configuration
-        File databaseDefFile = new File(PARTITION_DEFINITION_FILE);
-        log.info("Loading database definition: {}", databaseDefFile.getAbsolutePath());
 
-        Map<String, Set<NodeInfo>> partitionMap;
-        try {
-            DatabaseDefinitionStore databaseDefStore = new DatabaseDefinitionStore(databaseDefFile);
-            if (!databaseDefFile.exists()) {
-                createDefaultDatabaseDefinition(databaseDefStore);
-            }
-            partitionMap = databaseDefStore.read().getPartitions();
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to load database config", e);
-        }
+        Map<String, Set<NodeId>> partitionMap = Maps.newHashMap();
+        clusterMetadataService.getClusterMetadata().getPartitions().forEach(p -> {
+            partitionMap.put(p.getName(), Sets.newHashSet(p.getMembers()));
+        });
+
 
         String[] activeNodeUris = partitionMap.values()
                     .stream()
                     .reduce((s1, s2) -> Sets.union(s1, s2))
                     .get()
                     .stream()
-                    .map(this::nodeToUri)
+                    .map(this::nodeIdToUri)
                     .toArray(String[]::new);
 
-        String localNodeUri = nodeToUri(NodeInfo.of(clusterService.getLocalNode()));
+        String localNodeUri = nodeIdToUri(clusterMetadataService.getLocalNode().id());
         Protocol protocol = new CopycatCommunicationProtocol(clusterService, clusterCommunicator);
 
         ClusterConfig clusterConfig = new ClusterConfig()
@@ -198,7 +189,7 @@ public class DatabaseManager implements StorageService, StorageAdminService {
         List<Database> partitions = partitionMap.entrySet()
             .stream()
             .map(entry -> {
-                String[] replicas = entry.getValue().stream().map(this::nodeToUri).toArray(String[]::new);
+                String[] replicas = entry.getValue().stream().map(this::nodeIdToUri).toArray(String[]::new);
                 return newDatabaseConfig(entry.getKey(), newPersistentLog(), replicas);
                 })
             .map(config -> {
@@ -229,17 +220,6 @@ public class DatabaseManager implements StorageService, StorageAdminService {
         log.info("Started");
     }
 
-    private void createDefaultDatabaseDefinition(DatabaseDefinitionStore store) {
-        // Assumes IPv4 is returned.
-        String ip = ClusterDefinitionManager.getSiteLocalAddress();
-        NodeInfo node = NodeInfo.from(ip, ip, COPYCAT_TCP_PORT);
-        try {
-            store.write(DatabaseDefinition.from(ImmutableSet.of(node)));
-        } catch (IOException e) {
-            log.warn("Unable to write default cluster definition", e);
-        }
-    }
-
     @Deactivate
     public void deactivate() {
         CompletableFuture.allOf(inMemoryDatabase.close(), partitionedDatabase.close())
index b66f424..7388822 100644 (file)
@@ -86,7 +86,7 @@ public class DefaultTransactionContext implements TransactionContext {
 
     @SuppressWarnings("unchecked")
     @Override
-    public void commit() {
+    public boolean commit() {
         // TODO: rework commit implementation to be more intuitive
         checkState(isOpen, TX_NOT_OPEN_ERROR);
         CommitResponse response = null;
@@ -95,10 +95,11 @@ public class DefaultTransactionContext implements TransactionContext {
             txMaps.values().forEach(m -> updates.addAll(m.prepareDatabaseUpdates()));
             Transaction transaction = new DefaultTransaction(transactionId, updates);
             response = Futures.getUnchecked(database.prepareAndCommit(transaction));
+            return response.success();
+        } catch (Exception e) {
+            abort();
+            return false;
         } finally {
-            if (response != null && !response.success()) {
-                abort();
-            }
             isOpen = false;
         }
     }
index 973db49..687762e 100644 (file)
@@ -427,6 +427,7 @@ public class GossipDeviceStore
 
         // Primary providers can respond to all changes, but ancillary ones
         // should respond only to annotation changes.
+        DeviceEvent event = null;
         if ((providerId.isAncillary() && annotationsChanged) ||
                 (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) {
             boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice);
@@ -436,17 +437,18 @@ public class GossipDeviceStore
                        providerId, oldDevice, devices.get(newDevice.id())
                         , newDevice);
             }
-            if (!providerId.isAncillary()) {
-                boolean wasOnline = availableDevices.contains(newDevice.id());
-                markOnline(newDevice.id(), newTimestamp);
-                if (!wasOnline) {
-                    notifyDelegateIfNotNull(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null));
-                }
-            }
 
-            return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null);
+            event = new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null);
         }
-        return null;
+
+        if (!providerId.isAncillary()) {
+            boolean wasOnline = availableDevices.contains(newDevice.id());
+            markOnline(newDevice.id(), newTimestamp);
+            if (!wasOnline) {
+                notifyDelegateIfNotNull(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null));
+            }
+        }
+        return event;
     }
 
     @Override
index 10f79eb..687576c 100644 (file)
@@ -52,7 +52,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 /**
  * Implementation of ResourceStore using TransactionalMap.
  */
-@Component(immediate = true, enabled = false)
+@Component(immediate = true)
 @Service
 @Beta
 public class ConsistentResourceStore implements ResourceStore {
@@ -238,6 +238,18 @@ public class ConsistentResourceStore implements ResourceStore {
                 .collect(Collectors.toList());
     }
 
+    @Override
+    public Collection<ResourcePath> getChildResources(ResourcePath parent) {
+        checkNotNull(parent);
+
+        Versioned<List<ResourcePath>> children = childMap.get(parent);
+        if (children == null) {
+            return Collections.emptyList();
+        }
+
+        return children.value();
+    }
+
     @Override
     public <T> Collection<ResourcePath> getAllocatedResources(ResourcePath parent, Class<T> cls) {
         checkNotNull(parent);
index 25e23d3..61d1937 100644 (file)
@@ -325,5 +325,11 @@ public class PartitionManagerTest {
 
             return Objects.equals(this.hash(), that.hash());
         }
+
+        @Override
+        public int compareTo(Key o) {
+            Long thisHash = hash();
+            return thisHash.compareTo(o.hash());
+        }
     }
 }
diff --git a/framework/src/onos/core/store/persistence/pom.xml b/framework/src/onos/core/store/persistence/pom.xml
new file mode 100644 (file)
index 0000000..555de11
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <repositories>
+        <repository>
+            <id>repository.springsource.com.release</id>
+            <name>SpringSource OBR - Release</name>
+            <url>http://repository.springsource.com/maven/bundles/release</url>
+        </repository>
+        <repository>
+            <id>repository.springsource.com.external</id>
+            <name>SpringSource OBR - External</name>
+            <url>http://repository.springsource.com/maven/bundles/external</url>
+        </repository>
+    </repositories>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-core-store</artifactId>
+        <version>1.4.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-core-persistence</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>ONOS Core persistent local store subsystem</description>
+
+
+
+    <dependencies>
+        <!--<dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+        </dependency>-->
+           <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mapdb</groupId>
+            <artifactId>mapdb</artifactId>
+            <version>1.0.8</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java
new file mode 100644 (file)
index 0000000..88c7d14
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence.impl;
+
+import org.mapdb.DB;
+import org.onosproject.persistence.PersistentMapBuilder;
+import org.onosproject.store.service.Serializer;
+
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default builder for persistent maps stored in the mapDB local database via the persistence service.
+ */
+public class DefaultPersistentMapBuilder<K, V> implements PersistentMapBuilder<K, V> {
+
+    private final DB localDB;
+
+    private String name = null;
+
+    private Serializer serializer = null;
+
+
+    public DefaultPersistentMapBuilder(DB localDB) {
+        checkNotNull(localDB, "The local database cannot be null.");
+        this.localDB = localDB;
+    }
+
+    public PersistentMapBuilder<K, V> withName(String name) {
+        this.name = PersistenceManager.MAP_PREFIX + checkNotNull(name);
+        return this;
+    }
+
+    public PersistentMapBuilder<K, V> withSerializer(Serializer serializer) {
+        checkArgument(this.serializer == null);
+        checkNotNull(serializer);
+        this.serializer = serializer;
+        return this;
+    }
+
+    public Map<K, V> build() {
+        checkNotNull(name, "The name must be assigned.");
+        checkNotNull(serializer, "The key serializer must be assigned.");
+
+        return new PersistentMap<K, V>(serializer, localDB, name);
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java
new file mode 100644 (file)
index 0000000..e1544fb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence.impl;
+
+import org.mapdb.DB;
+import org.onosproject.persistence.PersistentSetBuilder;
+import org.onosproject.store.service.Serializer;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default builder for persistent sets stored in the mapDB local database via the persistence service..
+ */
+public class DefaultPersistentSetBuilder<E> implements PersistentSetBuilder<E> {
+
+    private final DB localDB;
+
+    private String name = null;
+
+    private Serializer serializer = null;
+
+    public DefaultPersistentSetBuilder(DB localDB) {
+        this.localDB = checkNotNull(localDB, "The local database cannot be null.");
+    }
+
+    public PersistentSetBuilder<E> withName(String name) {
+        this.name = PersistenceManager.SET_PREFIX + checkNotNull(name);
+        return this;
+    }
+
+    public PersistentSetBuilder<E> withSerializer(Serializer serializer) {
+        checkArgument(this.serializer == null);
+        checkNotNull(serializer);
+        this.serializer = serializer;
+        return this;
+    }
+
+    public PersistentSet<E> build() {
+        checkNotNull(name, "The name must be assigned.");
+        checkNotNull(serializer, "The serializer must be assigned.");
+
+        return new PersistentSet<E>(serializer, localDB, name);
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java
new file mode 100644 (file)
index 0000000..f2ba20c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence.impl;
+
+/**
+ * An exception defined for failures of the local persistent store system.
+ */
+
+/**
+ * Throws an exception with the specified message.
+ */
+public class PersistenceException extends RuntimeException {
+    public PersistenceException(String s) {
+        super(s);
+    }
+}
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java
new file mode 100644 (file)
index 0000000..64a8683
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.mapdb.DB;
+import org.mapdb.DBMaker;
+import org.onosproject.persistence.PersistenceService;
+import org.onosproject.persistence.PersistentMapBuilder;
+import org.onosproject.persistence.PersistentSetBuilder;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Service that maintains local disk backed maps and sets.  This implementation automatically deletes empty structures
+ * on shutdown.
+ */
+@Component(immediate = true)
+@Service
+public class PersistenceManager implements PersistenceService {
+
+    private static final String DATABASE_PATH = "../data/localDB";
+
+    private static final String ENCLOSING_FOLDER = "../data";
+
+    static final String MAP_PREFIX = "map:";
+
+    static final String SET_PREFIX = "set:";
+
+    private final Logger log = getLogger(getClass());
+
+    private DB localDB = null;
+
+    private static final int FLUSH_FREQUENCY_MILLIS = 3000;
+
+    private final Timer timer = new Timer();
+
+    private final CommitTask commitTask = new CommitTask();
+
+    @Activate
+    public void activate() {
+        Path dbPath = Paths.get(DATABASE_PATH);
+        Path dbFolderPath = Paths.get(ENCLOSING_FOLDER);
+        //Make sure the directory exists, if it does not, make it.
+        if (!dbFolderPath.toFile().isDirectory()) {
+            log.info("The specified folder location for the database did not exist and will be created.");
+            try {
+                Files.createDirectories(dbFolderPath);
+            } catch (IOException e) {
+                log.error("Could not create the required folder for the database.");
+                throw new PersistenceException("Database folder could not be created.");
+            }
+        }
+        //Notify if the database file does not exist.
+        boolean dbFound = Files.exists(dbPath);
+        if (!dbFound) {
+            log.info("The database file could not be located, a new database will be constructed.");
+
+        } else {
+            log.info("A previous database file has been found.");
+        }
+        localDB = DBMaker.newFileDB(dbPath.toFile())
+                .asyncWriteEnable()
+                .closeOnJvmShutdown()
+                .make();
+        timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+                //This is a map implementation to be handled as such
+            if (value instanceof Map) {
+                Map asMap = (Map) value;
+                if (asMap.isEmpty()) {
+                    //the map is empty and may be deleted
+                    localDB.delete(key);
+                }
+                //This is a set implementation and can be handled as such
+            } else if (value instanceof Set) {
+                Set asSet = (Set) value;
+                if (asSet.isEmpty()) {
+                    //the set is empty and may be deleted
+                    localDB.delete(key);
+                }
+            }
+        }
+        localDB.commit();
+        localDB.close();
+        log.info("Stopped");
+    }
+
+    public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() {
+        return new DefaultPersistentMapBuilder<>(localDB);
+    }
+
+    public <E> PersistentSetBuilder<E> persistentSetBuilder() {
+        return new DefaultPersistentSetBuilder<>(localDB);
+    }
+
+    private class CommitTask extends TimerTask {
+
+        @Override
+        public void run() {
+            localDB.commit();
+        }
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java
new file mode 100644 (file)
index 0000000..4506bbd
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence.impl;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.mapdb.DB;
+import org.mapdb.Hasher;
+import org.onosproject.store.service.Serializer;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * A map implementation that stores and receives all data from a serialized internal map.
+ */
+public class PersistentMap<K, V> implements Map<K, V> {
+
+    private final Serializer serializer;
+
+    private final org.mapdb.DB database;
+
+    private final Map<byte[], byte[]> items;
+
+    private final String name;
+
+    public PersistentMap(Serializer serializer, DB database, String name) {
+        this.serializer = checkNotNull(serializer);
+        this.database = checkNotNull(database);
+        this.name = checkNotNull(name);
+
+        items = database
+                .createHashMap(name)
+                .keySerializer(org.mapdb.Serializer.BYTE_ARRAY)
+                .valueSerializer(org.mapdb.Serializer.BYTE_ARRAY)
+                .hasher(Hasher.BYTE_ARRAY)
+                .makeOrGet();
+    }
+
+    /**
+     * Reads this set in deserialized form into the provided map.
+     *
+     * @param items the map to be populated
+     */
+    public void readInto(Map<K, V> items) {
+        this.items.forEach((keyBytes, valueBytes) ->
+                                   items.put(serializer.decode(keyBytes),
+                                             serializer.decode(valueBytes)));
+    }
+
+    @Override
+    public V remove(Object key) {
+        checkNotNull(key, "Key can not be null.");
+        V removed = get(key);
+        items.remove(serializer.encode(key));
+        return removed;
+    }
+
+    @Override
+    public int size() {
+        return items.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return items.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        checkNotNull(key, "Key cannot be null.");
+        return items.containsKey(serializer.encode(key));
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        checkNotNull(value, "Value cannot be null.");
+        byte[] serialized = serializer.encode(value);
+        for (byte[] compareValue : items.values()) {
+            boolean same = true;
+            if (compareValue == null) {
+                same = false;
+            } else if (compareValue.length != serialized.length) {
+                same = false;
+            } else {
+                for (int i = 0; i < serialized.length; i++) {
+                    if (serialized[i] != compareValue[i]) {
+                        same = false;
+                        break;
+                    }
+                }
+            }
+            if (same) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public V get(Object key) {
+        checkNotNull(key, "Key cannot be null.");
+        return serializer.decode(items.get(serializer.encode(key)));
+    }
+
+    @Override
+    public V put(K key, V value) {
+        checkNotNull(key, "Key cannot be null.");
+        checkNotNull(value, "Value cannot be null.");
+        byte[] prevVal = items.put(serializer.encode(key), serializer.encode(value));
+        if (prevVal == null) {
+            return null;
+        }
+        return serializer.decode(prevVal);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+        checkNotNull(m, "The passed in map cannot be null.");
+        m.forEach((k, v) -> items.put(serializer.encode(k), serializer.encode(v)));
+    }
+
+    @Override
+    public void clear() {
+        items.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+        Set<K> keys = Sets.newHashSet();
+        items.keySet().forEach(k -> keys.add(serializer.decode(k)));
+        return keys;
+    }
+
+    @Override
+    public Collection<V> values() {
+        Collection<V> values = Sets.newHashSet();
+        items.values().forEach(v -> values.add(serializer.decode(v)));
+        return values;
+    }
+
+    @Override
+    public Set<Entry<K, V>> entrySet() {
+        Set<Entry<K, V>> entries = Sets.newHashSet();
+        items.entrySet().
+                forEach(e -> entries.add(Maps.immutableEntry(serializer.decode(e.getKey()),
+                                                             serializer.decode(e.getValue()))));
+        return entries;
+    }
+
+    @Override
+    public boolean equals(Object map) {
+        //This is not threadsafe and on larger maps incurs a significant processing cost
+        if (!(map instanceof Map)) {
+            return false;
+        }
+        Map asMap = (Map) map;
+        if (this.size() != asMap.size()) {
+            return false;
+        }
+        for (Entry entry : this.entrySet()) {
+            Object key = entry.getKey();
+            if (!asMap.containsKey(key) || !asMap.get(key).equals(entry.getValue())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java
new file mode 100644 (file)
index 0000000..26118cf
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.persistence.impl;
+
+import com.google.common.collect.Iterators;
+import org.mapdb.DB;
+import org.mapdb.Hasher;
+import org.mapdb.Serializer;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A set implementation that gets and receives all data from a serialized internal set.
+ */
+//TODO add locking for reads and writes
+public class PersistentSet<E> implements Set<E> {
+
+    private final org.onosproject.store.service.Serializer serializer;
+
+    private final org.mapdb.DB database;
+
+    private final Set<byte[]> items;
+
+    private final String name;
+
+    public PersistentSet(org.onosproject.store.service.Serializer serializer, DB database, String name) {
+        this.serializer = checkNotNull(serializer);
+        this.database = checkNotNull(database);
+        this.name = checkNotNull(name);
+
+        items = database
+                .createHashSet(name)
+                .serializer(Serializer.BYTE_ARRAY)
+                .hasher(Hasher.BYTE_ARRAY)
+                .makeOrGet();
+    }
+
+    public void readInto(Set<E> items) {
+        this.items.forEach(item -> items.add(serializer.decode(item)));
+    }
+
+    @Override
+    public int size() {
+        return items.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return items.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        checkNotNull(o, "The argument cannot be null");
+        return items.contains(serializer.encode(o));
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return Iterators.transform(items.iterator(), serializer::decode);
+    }
+
+    @Override
+    public Object[] toArray() {
+        Object[] retArray = new Object[items.size()];
+        int index = 0;
+        Iterator<byte[]> iterator = items.iterator();
+        while (iterator.hasNext()) {
+            retArray[index] = serializer.decode(iterator.next());
+            index++;
+        }
+        return retArray;
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        checkNotNull(a, "The passed in array cannot be null.");
+        int index = 0;
+        Iterator<byte[]> iterator = items.iterator();
+        T[] retArray;
+        if (a.length >= items.size()) {
+            retArray = a;
+        } else {
+            retArray = (T[]) new Object[items.size()];
+        }
+        while (iterator.hasNext()) {
+            retArray[index++] = serializer.decode(iterator.next());
+        }
+        if (retArray.length > items.size()) {
+            retArray[index] = null;
+        }
+        return retArray;
+    }
+
+    @Override
+    public boolean add(E item) {
+        checkNotNull("Item to be added cannot be null.");
+        return items.add(serializer.encode(item));
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        checkNotNull(o, "Item to be removed cannot be null.");
+        return items.remove(serializer.encode(o));
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        checkNotNull(c, "Collection cannot be internal.");
+        for (Object item : c) {
+            if (!items.contains(serializer.encode(item))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+        checkNotNull(c, "The collection to be added cannot be null.");
+        boolean changed = false;
+        for (Object item : c) {
+            changed = items.add(serializer.encode(item)) || changed;
+        }
+        return changed;
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        boolean changed = false;
+        for (byte[] item : items) {
+            E deserialized = serializer.decode(item);
+            if (!c.contains(deserialized)) {
+                changed = items.remove(item) || changed;
+            }
+        }
+        return changed;
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        boolean changed = false;
+        for (Object item : c) {
+            changed = items.remove(serializer.encode(item)) || changed;
+        }
+        return changed;
+    }
+
+    @Override
+    public void clear() {
+        items.clear();
+    }
+
+    @Override
+    public boolean equals(Object set) {
+        //This is not threadsafe and on larger sets incurs a significant processing cost
+        if (!(set instanceof Set)) {
+            return false;
+        }
+        Set asSet = (Set) set;
+        if (asSet.size() != this.size()) {
+            return false;
+        }
+        for (Object item : this) {
+            if (!asSet.contains(item)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java
new file mode 100644 (file)
index 0000000..968a504
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementations of core persistence classes.
+ */
+package org.onosproject.persistence.impl;
diff --git a/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java
new file mode 100644 (file)
index 0000000..b059f18
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test;
+
+import com.google.common.collect.Maps;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mapdb.DB;
+import org.mapdb.DBMaker;
+import org.onosproject.persistence.impl.PersistentMap;
+import org.onosproject.store.service.Serializer;
+
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test suite for Persistent Map.
+ */
+public class PersistentMapTest {
+
+    private Map<Integer, Integer> map = null;
+    private DB fakeDB = null;
+
+
+    /**
+     * Set up the database, create a map and a direct executor to handle it.
+     *
+     * @throws Exception if instantiation fails
+     */
+    @Before
+    public void setUp() throws Exception {
+        //Creates a db, a map within it and a basic integer serializer (async writing is off)
+        fakeDB = DBMaker
+                .newFileDB(Paths.get("../testDb").toFile())
+                .asyncWriteEnable()
+                .closeOnJvmShutdown()
+                .make();
+        map = new PersistentMap<Integer, Integer>(new Serializer() {
+            @Override
+            public <T> byte[] encode(T object) {
+                if (object == null) {
+                    return null;
+                }
+                int num = (Integer) object;
+                byte[] result = new byte[4];
+
+                result[0] = (byte) (num >> 24);
+                result[1] = (byte) (num >> 16);
+                result[2] = (byte) (num >> 8);
+                result[3] = (byte) num;
+                return result;
+            }
+
+            @Override
+            public <T> T decode(byte[] bytes) {
+                if (bytes == null) {
+                    return null;
+                }
+                int num = 0x00000000;
+
+                num = num | bytes[0] << 24;
+                num = num | bytes[1] << 16;
+                num = num | bytes[2] << 8;
+                num = num | bytes[3];
+
+                return (T) new java.lang.Integer(num);
+            }
+        }, fakeDB, "map");
+    }
+
+    /**
+     * Clears and deletes the map, closes the datbase and deletes the file.
+     *
+     * @throws Exception if shutdown fails
+     */
+    @After
+    public void tearDown() throws Exception {
+        map.clear();
+        fakeDB.delete("map:map");
+        fakeDB.commit();
+        fakeDB.close();
+        //This is key to prevent artifacts persisting between tests.
+        Paths.get("../testDB").toFile().delete();
+
+
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+        //Checks removal and return values
+        fillMap(10);
+        assertEquals(10, map.size());
+        for (int i = 0; i < 10; i++) {
+            assertEquals("The previous value was wrong.", new Integer(i), map.remove(i));
+            assertNull("The previous value was wrong.", map.remove(i));
+            //(i+1) compensates for base zero.
+            assertEquals("The size was wrong.", 10 - (i + 1), map.size());
+        }
+    }
+
+    @Test
+    public void testSize() throws Exception {
+        //Checks size values throughout addition and removal
+        for (int i = 0; i < 10; i++) {
+            map.put(i, i);
+            assertEquals("The map size is wrong.", i + 1, map.size());
+        }
+        for (int i = 0; i < 10; i++) {
+            map.remove(i);
+            assertEquals("The map size is wrong.", 9 - i, map.size());
+        }
+    }
+
+    @Test
+    public void testIsEmpty() throws Exception {
+        //Checks empty condition
+        //asserts that the map starts out empty
+        assertTrue("Map should be empty", map.isEmpty());
+        map.put(1, 1);
+        assertFalse("Map shouldn't be empty.", map.isEmpty());
+        map.remove(1);
+        assertTrue("Map should be empty", map.isEmpty());
+    }
+
+    @Test
+    public void testContains() throws Exception {
+        //Checks both containsKey and containsValue be aware the implementations vary widely (value does not use mapDB
+        //due to object '=='being an insufficient check)
+        for (int i = 0; i < 10; i++) {
+            assertFalse("Map should not contain the key", map.containsKey(i));
+            assertFalse("Map should not contain the value", map.containsValue(i));
+            map.put(i, i);
+            assertTrue("Map should contain the key", map.containsKey(i));
+            assertTrue("Map should contain the value", map.containsValue(i));
+        }
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        //Tests value retrieval and nonexistent key return values
+        for (int i = 0; i < 10; i++) {
+            map.put(i, i);
+            for (int j = 0; j <= i; j++) {
+                assertEquals("The value was wrong.", new Integer(j), map.get(j));
+            }
+        }
+        assertNull("Null return value for nonexistent keys.", map.get(10));
+    }
+
+    @Test
+    public void testPutAll() throws Exception {
+        //Tests adding of an outside map
+        Map<Integer, Integer> testMap = Maps.newHashMap();
+        fillMap(10);
+        map.putAll(testMap);
+        for (int i = 0; i < 10; i++) {
+            assertTrue("The map should contain the current 'i' value.", map.containsKey(i));
+            assertTrue("The map should contain the current 'i' value.", map.containsValue(i));
+        }
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        //Tests clearing the map
+        assertTrue("Map was initialized incorrectly, should be empty.", map.isEmpty());
+        fillMap(10);
+        assertFalse("Map should contain entries now.", map.isEmpty());
+        map.clear();
+        assertTrue("Map should have been cleared of entries.", map.isEmpty());
+
+    }
+
+    @Test
+    public void testKeySet() throws Exception {
+        //Tests key set generation
+        fillMap(10);
+        Set<Integer> keys = map.keySet();
+        for (int i = 0; i < 10; i++) {
+            assertTrue("The key set doesn't contain all keys 0-9", keys.contains(i));
+        }
+        assertEquals("The key set has an incorrect number of entries", 10, keys.size());
+    }
+
+    @Test
+    public void testValues() throws Exception {
+        //Tests value set generation
+        fillMap(10);
+        Set<Integer> values = (Set<Integer>) map.values();
+        for (int i = 0; i < 10; i++) {
+            assertTrue("The key set doesn't contain all keys 0-9", values.contains(i));
+        }
+        assertEquals("The key set has an incorrect number of entries", 10, values.size());
+    }
+
+    @Test
+    public void testEntrySet() throws Exception {
+        //Test entry set generation (violates abstraction by knowing the type of the returned entries)
+        fillMap(10);
+        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
+        for (int i = 0; i < 10; i++) {
+            assertTrue("The key set doesn't contain all keys 0-9", entries.contains(Maps.immutableEntry(i, i)));
+        }
+        assertEquals("The key set has an incorrect number of entries", 10, entries.size());
+    }
+
+    @Test public void testPut() throws Exception {
+        //Tests insertion behavior (particularly the returning of previous value)
+        fillMap(10);
+        for (int i = 0; i < 10; i++) {
+            assertEquals("Put should return the previous value", new Integer(i), map.put(i, i + 1));
+        }
+        assertNull(map.put(11, 11));
+    }
+
+    /**
+     * Populated the map with pairs of integers from (0, 0) up to (numEntries - 1, numEntries -1).
+     * @param numEntries number of entries to add
+     */
+    private void fillMap(int numEntries) {
+        for (int i = 0; i < numEntries; i++) {
+            map.put(i, i);
+        }
+    }
+}
diff --git a/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java
new file mode 100644 (file)
index 0000000..3107ab3
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mapdb.DB;
+import org.mapdb.DBMaker;
+import org.onosproject.persistence.impl.PersistentSet;
+import org.onosproject.store.service.Serializer;
+
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test suite for Persistent Set.
+ */
+public class PersistentSetTest {
+
+    private Set<Integer> set = null;
+    private DB fakeDB = null;
+
+    @Before
+    public void setUp() throws Exception {
+        //Creates a db, a set within it and a basic integer serializer (async writing is off)
+        fakeDB = DBMaker
+                .newFileDB(Paths.get("../testDb").toFile())
+                .asyncWriteEnable()
+                .closeOnJvmShutdown()
+                .make();
+        set = new PersistentSet<Integer>(new Serializer() {
+            @Override
+            public <T> byte[] encode(T object) {
+                if (object == null) {
+                    return null;
+                }
+                int num = (Integer) object;
+                byte[] result = new byte[4];
+
+                result[0] = (byte) (num >> 24);
+                result[1] = (byte) (num >> 16);
+                result[2] = (byte) (num >> 8);
+                result[3] = (byte) num;
+                return result;
+            }
+
+            @Override
+            public <T> T decode(byte[] bytes) {
+                if (bytes == null) {
+                    return null;
+                }
+                int num = 0x00000000;
+
+                num = num | bytes[0] << 24;
+                num = num | bytes[1] << 16;
+                num = num | bytes[2] << 8;
+                num = num | bytes[3];
+
+                return (T) new java.lang.Integer(num);
+            }
+        }, fakeDB, "set");
+
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        set.clear();
+        fakeDB.delete("map:map");
+        fakeDB.commit();
+        fakeDB.close();
+        //This is key to prevent artifacts persisting between tests.
+        Paths.get("../testDB").toFile().delete();
+    }
+
+    @Test
+    public void testSize() throws Exception {
+        //Check correct sizing throughout population
+        for (int i = 0; i < 10; i++) {
+            set.add(i);
+            assertEquals("The set should have i + 1 entries.", i + 1, set.size());
+        }
+    }
+
+    @Test
+    public void testIsEmpty() throws Exception {
+        //test empty condition
+        assertTrue("The set should be initialized empty.", set.isEmpty());
+        fillSet(5, this.set);
+        assertFalse("The set should no longer be empty.", set.isEmpty());
+        set.clear();
+        assertTrue("The set should have been cleared.", set.isEmpty());
+    }
+
+    @Test
+    public void testContains() throws Exception {
+        //Test contains
+        assertFalse("The set should not contain anything", set.contains(1));
+        fillSet(10, this.set);
+        for (int i = 0; i < 10; i++) {
+            assertTrue("The set should contain all values 0-9.", set.contains(i));
+        }
+    }
+
+    @Test
+    public void testIterator() throws Exception {
+        //Test iterator behavior (no order guarantees are made)
+        Set<Integer> validationSet = Sets.newHashSet();
+        fillSet(10, this.set);
+        fillSet(10, validationSet);
+        set.iterator().forEachRemaining(item -> assertTrue("Items were mismatched.", validationSet.remove(item)));
+        //All values should have been seen and removed
+        assertTrue("All entries in the validation set should have been removed.", validationSet.isEmpty());
+    }
+
+    @Test
+    public void testToArray() throws Exception {
+        //Test creation of a new array of the values
+        fillSet(10, set);
+        Object[] arr = set.toArray();
+        assertEquals("The array should be of length 10.", 10, arr.length);
+        for (int i = 0; i < 10; i++) {
+            assertTrue("All elements of the array should be in the set.", set.contains((Integer) arr[i]));
+        }
+    }
+
+    @Test
+    public void testToArray1() throws Exception {
+        //Test creation of a new array with the possibility of populating passed array if space allows
+        Integer[] originalArray = new Integer[9];
+        fillSet(9, set);
+        //Test the case where the array and set match in size
+        Object[] retArray = set.toArray(originalArray);
+        assertEquals("If the set can fit the array should be the one passed in.", originalArray, retArray);
+        //Test the case where the passe array is too small to fit the set
+        set.add(9);
+        assertNotEquals("A new set should be generated if the contents will not fit in the passed set",
+                        set.toArray(originalArray), originalArray);
+        //Now test the case where there should be a null terminator
+        set.clear();
+        fillSet(5, set);
+        assertNull("The character one after last should be null if the array is larger than the set.",
+                   set.toArray(originalArray)[5]);
+    }
+
+    @Test
+    public void testAdd() throws Exception {
+        //Test of add
+        for (int i = 0; i < 10; i++) {
+            assertEquals("The size of the set is wrong.", i, set.size());
+            assertTrue("The first add of an element should be true.", set.add(i));
+            assertFalse("The second add of an element should be false.", set.add(i));
+        }
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+        //Test removal
+        fillSet(10, set);
+        for (int i = 0; i < 10; i++) {
+            assertEquals("The size of the set is wrong.", 10 - i, set.size());
+            assertTrue("The first removal should be true.", set.remove(i));
+            assertFalse("The second removal should be false (item no longer contained).", set.remove(i));
+        }
+        assertTrue("All elements should have been removed.", set.isEmpty());
+    }
+
+    @Test
+    public void testContainsAll() throws Exception {
+        //Test contains with short circuiting
+        Set<Integer> integersToCheck = Sets.newHashSet();
+        fillSet(10, integersToCheck);
+        fillSet(10, set);
+        assertTrue("The sets should be identical so mutual subsets.", set.containsAll(integersToCheck));
+        set.remove(9);
+        assertFalse("The set should contain one fewer value.", set.containsAll(integersToCheck));
+    }
+
+    @Test
+    public void testAddAll() throws Exception {
+        //Test multi-adds with change checking
+        Set<Integer> integersToCheck = Sets.newHashSet();
+        fillSet(10, integersToCheck);
+        assertFalse("Set should be empty and so integers to check should not be a subset.",
+                    set.containsAll(integersToCheck));
+        assertTrue("The set should have changed as a result of add all.", set.addAll(integersToCheck));
+        assertFalse("The set should not have changed as a result of add all a second time.",
+                    set.addAll(integersToCheck));
+        assertTrue("The sets should now be equivalent.", set.containsAll(integersToCheck));
+        assertTrue("The sets should now be equivalent.", integersToCheck.containsAll(set));
+    }
+
+    @Test
+    public void testRetainAll() throws Exception {
+        //Test ability to generate the intersection set
+        Set<Integer> retainSet = Sets.newHashSet();
+        fillSet(10, set);
+        assertTrue("The set should have changed.", set.retainAll(retainSet));
+        assertTrue("The set should have been emptied.", set.isEmpty());
+        fillSet(10, set);
+        fillSet(10, retainSet);
+        Set<Integer> duplicateSet = new HashSet<>(set);
+        assertFalse("The set should not have changed.", set.retainAll(retainSet));
+        assertEquals("The set should be the same as the duplicate.", duplicateSet, set);
+        retainSet.remove(9);
+        assertTrue("The set should have changed.", set.retainAll(retainSet));
+        duplicateSet.remove(9);
+        assertEquals("The set should have had the nine element removed.", duplicateSet, set);
+    }
+
+    @Test
+    public void testRemoveAll() throws Exception {
+        //Test for mass removal and change checking
+        Set<Integer> removeSet = Sets.newHashSet();
+        fillSet(10, set);
+        Set<Integer> duplicateSet = Sets.newHashSet(set);
+        assertFalse("No elements should change.", set.removeAll(removeSet));
+        assertEquals("Set should not have diverged from the duplicate.", duplicateSet, set);
+        fillSet(5, removeSet);
+        assertTrue("Elements should have been removed.", set.removeAll(removeSet));
+        assertNotEquals("Duplicate set should no longer be equivalent.", duplicateSet, set);
+        assertEquals("Five elements should have been removed from set.", 5, set.size());
+        for (Integer item : removeSet) {
+            assertFalse("No element of remove set should remain.", set.contains(item));
+        }
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        //Test set emptying
+        assertTrue("The set should be initialized empty.", set.isEmpty());
+        set.clear();
+        assertTrue("Clear should have no effect on an empty set.", set.isEmpty());
+        fillSet(10, set);
+        assertFalse("The set should no longer be empty.", set.isEmpty());
+        set.clear();
+        assertTrue("The set should be empty after clear.", set.isEmpty());
+    }
+
+    /**
+     * Populated the map with integers from (0) up to (numEntries - 1).
+     *
+     * @param numEntries number of entries to add
+     */
+    private void fillSet(int numEntries, Set<Integer> set) {
+        checkNotNull(set);
+        for (int i = 0; i < numEntries; i++) {
+            set.add(i);
+        }
+    }
+}
index 2b246b8..219ae5d 100644 (file)
@@ -33,7 +33,8 @@
 
     <modules>
         <module>dist</module>
-        <module>serializers</module>
+        <module>persistence</module>
+       <module>serializers</module>
     </modules>
 
     <dependencies>
diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java
new file mode 100644 (file)
index 0000000..6b12df9
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.store.serializers;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ExtensionResolver;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.onosproject.net.flow.instructions.Instructions;
+
+/**
+ * Created by jono on 10/29/15.
+ */
+public class ExtensionInstructionSerializer extends
+        Serializer<Instructions.ExtensionInstructionWrapper> {
+
+    public ExtensionInstructionSerializer() {
+        super(false, true);
+    }
+
+    @Override
+    public void write(Kryo kryo, Output output, Instructions.ExtensionInstructionWrapper object) {
+        kryo.writeClassAndObject(output, object.extensionInstruction().type());
+        kryo.writeClassAndObject(output, object.deviceId());
+
+        kryo.writeClassAndObject(output, object.extensionInstruction().serialize());
+
+    }
+
+    @Override
+    public Instructions.ExtensionInstructionWrapper read(Kryo kryo, Input input,
+                                                         Class<Instructions.ExtensionInstructionWrapper> type) {
+        ExtensionType exType = (ExtensionType) kryo.readClassAndObject(input);
+        DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
+
+        DriverService driverService = DefaultServiceDirectory.getService(DriverService.class);
+        DriverHandler handler = new DefaultDriverHandler(
+                new DefaultDriverData(driverService.getDriver(deviceId), deviceId));
+
+        ExtensionResolver resolver = handler.behaviour(ExtensionResolver.class);
+
+        ExtensionInstruction instruction = resolver.getExtensionInstruction(exType);
+
+        byte[] bytes = (byte[]) kryo.readClassAndObject(input);
+
+        instruction.deserialize(bytes);
+
+        return Instructions.extension(instruction, deviceId);
+    }
+}
index 5b5056c..0312baf 100644 (file)
@@ -70,6 +70,7 @@ import org.onosproject.net.OchPort;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OchSignalType;
 import org.onosproject.net.OduCltPort;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.OmsPort;
 import org.onosproject.net.Port;
@@ -118,6 +119,8 @@ import org.onosproject.net.flow.criteria.MetadataCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.OchSignalCriterion;
 import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
+import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
+import org.onosproject.net.flow.criteria.OduSignalTypeCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
@@ -125,8 +128,10 @@ import org.onosproject.net.flow.criteria.TunnelIdCriterion;
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
+import org.onosproject.net.flow.instructions.ExtensionType;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
@@ -337,6 +342,8 @@ public final class KryoNamespaces {
                     IndexedLambdaCriterion.class,
                     OchSignalCriterion.class,
                     OchSignalTypeCriterion.class,
+                    OduSignalIdCriterion.class,
+                    OduSignalTypeCriterion.class,
                     Criterion.class,
                     Criterion.Type.class,
                     DefaultTrafficTreatment.class,
@@ -349,6 +356,9 @@ public final class KryoNamespaces {
                     L0ModificationInstruction.L0SubType.class,
                     L0ModificationInstruction.ModLambdaInstruction.class,
                     L0ModificationInstruction.ModOchSignalInstruction.class,
+                    L1ModificationInstruction.class,
+                    L1ModificationInstruction.L1SubType.class,
+                    L1ModificationInstruction.ModOduSignalIdInstruction.class,
                     L2ModificationInstruction.class,
                     L2ModificationInstruction.L2SubType.class,
                     L2ModificationInstruction.ModEtherInstruction.class,
@@ -441,6 +451,8 @@ public final class KryoNamespaces {
             .register(new HostLocationSerializer(), HostLocation.class)
             .register(new DefaultOutboundPacketSerializer(), DefaultOutboundPacket.class)
             .register(new AnnotationsSerializer(), DefaultAnnotations.class)
+            .register(new ExtensionInstructionSerializer(), Instructions.ExtensionInstructionWrapper.class)
+            .register(ExtensionType.class)
             .register(Versioned.class)
             .register(MapEvent.class)
             .register(MapEvent.Type.class)
@@ -458,6 +470,7 @@ public final class KryoNamespaces {
             .register(OduCltPort.SignalType.class)
             .register(IndexedLambda.class)
             .register(OchSignal.class)
+            .register(OduSignalId.class)
             .register(OduCltPortDescription.class)
             .register(OchPortDescription.class)
             .register(OmsPortDescription.class)
diff --git a/framework/src/onos/docs/internal-bgpls b/framework/src/onos/docs/internal-bgpls
new file mode 100644 (file)
index 0000000..f264c7d
--- /dev/null
@@ -0,0 +1,2 @@
+org.onosproject.bgp.controller*
+org.onosproject.bgpio*
index de9c1c6..602479e 100644 (file)
                             <title>PCEP Providers</title>
                             <packages>@internal-pcep</packages>
                         </group>
+                        <group>
+                            <title>BGP-LS Providers</title>
+                            <packages>@internal-bgpls</packages>
+                        </group>
                         <group>
                             <title>Other Providers</title>
                             <packages>@internal-providers</packages>
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java
new file mode 100644 (file)
index 0000000..082c5a6
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.driver.extensions;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.net.behaviour.ExtensionResolver;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.onosproject.openflow.controller.ExtensionInterpreter;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst;
+import org.projectfloodlight.openflow.types.IPv4Address;
+
+/**
+ * Interpreter for Nicira OpenFlow extensions.
+ */
+public class NiciraExtensionInterpreter extends AbstractHandlerBehaviour
+        implements ExtensionInterpreter, ExtensionResolver {
+
+    @Override
+    public boolean supported(ExtensionType extensionType) {
+        if (extensionType.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction) {
+        ExtensionType type = extensionInstruction.type();
+        if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) {
+            NiciraSetTunnelDst tunnelDst = (NiciraSetTunnelDst) extensionInstruction;
+            return factory.actions().setField(factory.oxms().tunnelIpv4Dst(
+                    IPv4Address.of(tunnelDst.tunnelDst().toInt())));
+        }
+        return null;
+    }
+
+    @Override
+    public ExtensionInstruction mapAction(OFAction action) {
+        if (action.getType().equals(OFActionType.SET_FIELD)) {
+            OFActionSetField setFieldAction = (OFActionSetField) action;
+            OFOxm<?> oxm = setFieldAction.getField();
+            switch (oxm.getMatchField().id) {
+            case TUNNEL_IPV4_DST:
+                OFOxmTunnelIpv4Dst tunnelIpv4Dst = (OFOxmTunnelIpv4Dst) oxm;
+                return new NiciraSetTunnelDst(Ip4Address.valueOf(tunnelIpv4Dst.getValue().getInt()));
+            default:
+                throw new UnsupportedOperationException(
+                        "Driver does not support extension type " + oxm.getMatchField().id);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ExtensionInstruction getExtensionInstruction(ExtensionType type) {
+        if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) {
+            return new NiciraSetTunnelDst();
+        }
+        throw new UnsupportedOperationException(
+                "Driver does not support extension type " + type.toString());
+    }
+}
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java
new file mode 100644 (file)
index 0000000..16aa1b0
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.driver.extensions;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.Ip4Address;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.net.flow.instructions.AbstractExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.onosproject.store.serializers.Ip4AddressSerializer;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Nicira set tunnel destination extension instruction.
+ */
+public class NiciraSetTunnelDst extends AbstractExtensionInstruction {
+
+    private Ip4Address tunnelDst;
+
+    private final KryoNamespace appKryo = new KryoNamespace.Builder()
+            .register(new Ip4AddressSerializer(), Ip4Address.class)
+            .register(byte[].class)
+            .build();
+
+    /**
+     * Creates a new set tunnel destination instruction.
+     */
+    NiciraSetTunnelDst() {
+        tunnelDst = null;
+    }
+
+    /**
+     * Creates a new set tunnel destination instruction with a particular IPv4
+     * address.
+     */
+    NiciraSetTunnelDst(Ip4Address tunnelDst) {
+        checkNotNull(tunnelDst);
+        this.tunnelDst = tunnelDst;
+    }
+
+    /**
+     * Gets the tunnel destination IPv4 address.
+     *
+     * @return tunnel destination IPv4 address
+     */
+    public Ip4Address tunnelDst() {
+        return tunnelDst;
+    }
+
+    @Override
+    public ExtensionType type() {
+        return ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type();
+    }
+
+    @Override
+    public void deserialize(byte[] data) {
+        tunnelDst = appKryo.deserialize(data);
+    }
+
+    @Override
+    public byte[] serialize() {
+        return appKryo.serialize(tunnelDst);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(tunnelDst);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof NiciraSetTunnelDst) {
+            NiciraSetTunnelDst that = (NiciraSetTunnelDst) obj;
+            return Objects.equals(tunnelDst, that.tunnelDst);
+
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("tunnelDst", tunnelDst)
+                .toString();
+    }
+}
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java
new file mode 100644 (file)
index 0000000..d9d2460
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Processing of Nicira extensions.
+ */
+package org.onosproject.driver.extensions;
index 524163a..77b4829 100644 (file)
@@ -22,11 +22,13 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.onlab.packet.IpAddress;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.BridgeConfig;
 import org.onosproject.net.behaviour.BridgeDescription;
 import org.onosproject.net.behaviour.BridgeName;
+import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.net.behaviour.DefaultBridgeDescription;
 import org.onosproject.net.device.DefaultPortDescription;
 import org.onosproject.net.device.PortDescription;
@@ -51,6 +53,13 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour
         clientService.createBridge(bridgeName.name());
     }
 
+    @Override
+    public boolean addBridge(BridgeName bridgeName, String dpid, List<ControllerInfo> controllers) {
+        DriverHandler handler = handler();
+        OvsdbClientService clientService = getOvsdbClientService(handler);
+        return clientService.createBridge(bridgeName.name(), dpid, controllers);
+    }
+
     @Override
     public void deleteBridge(BridgeName bridgeName) {
         DriverHandler handler = handler();
@@ -108,22 +117,22 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour
         return ports.stream()
                 .map(x -> new DefaultPortDescription(
                                 PortNumber.portNumber(x.portNumber().value()),
-                                true
-                        )
-                )
+                                true,
+                                DefaultAnnotations.builder()
+                                        .set("portName", x.portName().value())
+                                        .build()))
                 .collect(Collectors.toSet());
     }
 
-    // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port)
+    // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP)
     // is used in the core. So DeviceId need be changed to OvsdbNodeId.
     private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) {
-        int lastColon = deviceId.toString().lastIndexOf(":");
-        int fistColon = deviceId.toString().indexOf(":");
-        String ip = deviceId.toString().substring(fistColon + 1, lastColon);
-        String port = deviceId.toString().substring(lastColon + 1);
-        IpAddress ipAddress = IpAddress.valueOf(ip);
-        long portL = Long.parseLong(port);
-        return new OvsdbNodeId(ipAddress, portL);
+        String[] splits = deviceId.toString().split(":");
+        if (splits == null || splits.length < 1) {
+            return null;
+        }
+        IpAddress ipAddress = IpAddress.valueOf(splits[1]);
+        return new OvsdbNodeId(ipAddress, 0);
     }
 
     // Used for getting OvsdbClientService.
index d32fb6b..a32553a 100644 (file)
 package org.onosproject.driver.ovsdb;
 
 import java.util.Collection;
-
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.onlab.packet.IpAddress;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.BridgeName;
 import org.onosproject.net.behaviour.DefaultTunnelDescription;
 import org.onosproject.net.behaviour.IpTunnelEndPoint;
 import org.onosproject.net.behaviour.TunnelConfig;
@@ -41,6 +43,8 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour
         implements TunnelConfig {
 
     private static final String DEFAULT_ADDRESS = "0.0.0.0";
+    private static final String OPTION_LOCAL_IP = "local_ip";
+    private static final String OPTION_REMOTE_IP = "remote_ip";
 
     @Override
     public void createTunnel(TunnelDescription tunnel) {
@@ -60,6 +64,22 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour
         ovsdbNode.createTunnel(ipSrc.ip(), ipDst.ip());
     }
 
+    @Override
+    public boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel) {
+        Map<String, String> options = ((DefaultAnnotations) tunnel.annotations()).asMap();
+        if (tunnel.src() != null) {
+            options.put(OPTION_LOCAL_IP, tunnel.src().toString());
+        }
+        if (tunnel.dst() != null) {
+            options.put(OPTION_REMOTE_IP, tunnel.dst().toString());
+        }
+
+        DriverHandler handler = handler();
+        OvsdbClientService ovsdbClient = getOvsdbNode(handler);
+        return ovsdbClient.createTunnel(bridgeName.name(), tunnel.tunnelName().toString(),
+                                        tunnel.type().toString().toLowerCase(), options);
+    }
+
     @Override
     public void removeTunnel(TunnelDescription tunnel) {
         DriverHandler handler = handler();
@@ -102,16 +122,15 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour
                 .collect(Collectors.toSet());
     }
 
-    // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port)
+    // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP)
     // is used in the core. So DeviceId need be changed to OvsdbNodeId.
     private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) {
-        int lastColon = deviceId.toString().lastIndexOf(":");
-        int fistColon = deviceId.toString().indexOf(":");
-        String ip = deviceId.toString().substring(fistColon + 1, lastColon);
-        String port = deviceId.toString().substring(lastColon + 1);
-        IpAddress ipAddress = IpAddress.valueOf(ip);
-        long portL = Long.parseLong(port);
-        return new OvsdbNodeId(ipAddress, portL);
+        String[] splits = deviceId.toString().split(":");
+        if (splits == null || splits.length < 1) {
+            return null;
+        }
+        IpAddress ipAddress = IpAddress.valueOf(splits[1]);
+        return new OvsdbNodeId(ipAddress, 0);
     }
 
     private OvsdbClientService getOvsdbNode(DriverHandler handler) {
@@ -29,22 +29,23 @@ import org.slf4j.Logger;
 
 
 /**
- * Driver for software switch emulation of the OFDPA 1.0 pipeline.
+ * Driver for software switch emulation of the OFDPA 2.0 pipeline.
  * The software switch is the CPqD OF 1.3 switch.
  */
-public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline {
+public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
 
     private final Logger log = getLogger(getClass());
 
     @Override
     protected void initializePipeline() {
         processPortTable();
-        //processVlanTable();
         processTmacTable();
         processIpTable();
-        //processMcastTable();
         processBridgingTable();
         processAclTable();
+        // XXX implement table miss entries and default groups
+        //processVlanTable();
+        //processMPLSTable();
         //processGroupTable();
     }
 
@@ -169,6 +170,7 @@ public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline {
         }));
     }
 
+    @Override
     protected void processAclTable() {
         //table miss entry - catch all to executed action-set
         FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
@@ -18,6 +18,7 @@ package org.onosproject.driver.pipeline;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -30,18 +31,26 @@ import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.Data;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MPLS;
+import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
+import org.onlab.packet.UDP;
 import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.DefaultGroupId;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.NextGroup;
 import org.onosproject.net.behaviour.Pipeliner;
 import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -81,6 +90,11 @@ import org.onosproject.net.group.GroupEvent;
 import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.group.GroupListener;
 import org.onosproject.net.group.GroupService;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.slf4j.Logger;
 
@@ -90,19 +104,22 @@ import com.google.common.cache.RemovalCause;
 import com.google.common.cache.RemovalNotification;
 
 /**
- * Driver for Broadcom's OF-DPA v1.0 TTP.
+ * Driver for Broadcom's OF-DPA v2.0 TTP.
  *
  */
-public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
+public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
 
     protected static final int PORT_TABLE = 0;
     protected static final int VLAN_TABLE = 10;
     protected static final int TMAC_TABLE = 20;
     protected static final int UNICAST_ROUTING_TABLE = 30;
     protected static final int MULTICAST_ROUTING_TABLE = 40;
+    protected static final int MPLS_TABLE_0 = 23;
+    protected static final int MPLS_TABLE_1 = 24;
     protected static final int BRIDGING_TABLE = 50;
     protected static final int ACL_TABLE = 60;
     protected static final int MAC_LEARNING_TABLE = 254;
+    protected static final long OFPP_MAX = 0xffffff00L;
 
     private static final int HIGHEST_PRIORITY = 0xffff;
     private static final int DEFAULT_PRIORITY = 0x8000;
@@ -128,6 +145,8 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
      */
     private static final int L2INTERFACEMASK = 0x0;
     private static final int L3UNICASTMASK = 0x20000000;
+    //private static final int MPLSINTERFACEMASK = 0x90000000;
+    private static final int L3ECMPMASK = 0x70000000;
 
     private final Logger log = getLogger(getClass());
     private ServiceDirectory serviceDirectory;
@@ -137,7 +156,9 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
     private FlowObjectiveStore flowObjectiveStore;
     protected DeviceId deviceId;
     protected ApplicationId driverId;
-
+    protected PacketService packetService;
+    protected DeviceService deviceService;
+    private InternalPacketProcessor processor = new InternalPacketProcessor();
     private KryoNamespace appKryo = new KryoNamespace.Builder()
         .register(KryoNamespaces.API)
         .register(GroupKey.class)
@@ -151,7 +172,9 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
 
     private ScheduledExecutorService groupChecker =
             Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
-                                                               "ofdpa1-%d"));
+                                                               "ofdpa2-%d"));
+    private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
+                                               new ConcurrentHashMap<IPCriterion, Boolean>());
 
     @Override
     public void init(DeviceId deviceId, PipelinerContext context) {
@@ -174,16 +197,29 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
         flowRuleService = serviceDirectory.get(FlowRuleService.class);
         groupService = serviceDirectory.get(GroupService.class);
         flowObjectiveStore = context.store();
-
+        packetService = serviceDirectory.get(PacketService.class);
+        deviceService = serviceDirectory.get(DeviceService.class);
+        packetService.addProcessor(processor, PacketProcessor.director(2));
         groupService.addListener(new InnerGroupListener());
 
         driverId = coreService.registerApplication(
-                "org.onosproject.driver.OFDPA1Pipeline");
+                "org.onosproject.driver.OFDPA2Pipeline");
 
+        // OF-DPA does not require initializing the pipeline as it puts default
+        // rules automatically in the hardware. However emulation of OFDPA in
+        // software switches does require table-miss-entries.
         initializePipeline();
 
     }
 
+    protected void initializePipeline() {
+
+    }
+
+    //////////////////////////////////////
+    //  Flow Objectives
+    //////////////////////////////////////
+
     @Override
     public void filter(FilteringObjective filteringObjective) {
         if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
@@ -191,6 +227,11 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
                           filteringObjective.op() == Objective.Operation.ADD,
                           filteringObjective.appId());
         } else {
+            // Note that packets that don't match the PERMIT filter are
+            // automatically denied. The DENY filter is used to deny packets
+            // that are otherwise permitted by the PERMIT filter.
+            // Use ACL table flow rules here for DENY filtering objectives
+            log.debug("filter objective other than PERMIT currently not supported");
             fail(filteringObjective, ObjectiveError.UNSUPPORTED);
         }
     }
@@ -257,25 +298,31 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
         }
     }
 
+    //////////////////////////////////////
+    //  Flow handling
+    //////////////////////////////////////
+
     /**
-     * As per OFDPA 1.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
+     * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
      * and IP addresses configured on switch ports happen in different tables.
      * Note that IP filtering rules need to be added to the ACL table, as there
      * is no mechanism to send to controller via IP table.
      *
-     * @param filt
-     * @param install
-     * @param applicationId
+     * @param filt      the filtering objective
+     * @param install   indicates whether to add or remove the objective
+     * @param applicationId     the application that sent this objective
      */
     private void processFilter(FilteringObjective filt,
                                boolean install, ApplicationId applicationId) {
         // This driver only processes filtering criteria defined with switch
         // ports as the key
-        PortCriterion p = null; EthCriterion e = null; VlanIdCriterion v = null;
+        PortCriterion portCriterion = null;
+        EthCriterion ethCriterion = null;
+        VlanIdCriterion vidCriterion = null;
         Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
         if (!filt.key().equals(Criteria.dummy()) &&
                 filt.key().type() == Criterion.Type.IN_PORT) {
-            p = (PortCriterion) filt.key();
+            portCriterion = (PortCriterion) filt.key();
         } else {
             log.warn("No key defined in filtering objective from app: {}. Not"
                     + "processing filtering objective", applicationId);
@@ -284,199 +331,238 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
         }
         // convert filtering conditions for switch-intfs into flowrules
         FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-        for (Criterion c : filt.conditions()) {
-            if (c.type() == Criterion.Type.ETH_DST) {
-                e = (EthCriterion) c;
-            } else if (c.type() == Criterion.Type.VLAN_VID) {
-                v = (VlanIdCriterion) c;
-            } else if (c.type() == Criterion.Type.IPV4_DST) {
-                ips.add((IPCriterion) c);
+        for (Criterion criterion : filt.conditions()) {
+            if (criterion.type() == Criterion.Type.ETH_DST) {
+                ethCriterion = (EthCriterion) criterion;
+            } else if (criterion.type() == Criterion.Type.VLAN_VID) {
+                vidCriterion = (VlanIdCriterion) criterion;
+            } else if (criterion.type() == Criterion.Type.IPV4_DST) {
+                ips.add((IPCriterion) criterion);
             } else {
-                log.error("Unsupported filter {}", c);
+                log.error("Unsupported filter {}", criterion);
                 fail(filt, ObjectiveError.UNSUPPORTED);
                 return;
             }
         }
 
-        log.debug("adding VLAN filtering rule in VLAN table: {}", e.mac());
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        selector.matchInPort(p.port());
-        selector.matchVlanId(v.vlanId());
-        treatment.transition(TMAC_TABLE);
-        FlowRule rule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DEFAULT_PRIORITY)
-                .fromApp(applicationId)
-                .makePermanent()
-                .forTable(VLAN_TABLE).build();
-        ops =  ops.add(rule);
+        VlanId assignedVlan = null;
+        if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) {
+            // untagged packets are assigned vlans in OF-DPA
+            if (filt.meta() == null) {
+                log.error("Missing metadata in filtering objective required "
+                        + "for vlan assignment in dev {}", deviceId);
+                fail(filt, ObjectiveError.BADPARAMS);
+                return;
+            }
+            for (Instruction i : filt.meta().allInstructions()) {
+                if (i instanceof ModVlanIdInstruction) {
+                    assignedVlan = ((ModVlanIdInstruction) i).vlanId();
+                }
+            }
+            if (assignedVlan == null) {
+                log.error("Driver requires an assigned vlan-id to tag incoming "
+                        + "untagged packets. Not processing vlan filters on "
+                        + "device {}", deviceId);
+                fail(filt, ObjectiveError.BADPARAMS);
+                return;
+            }
+        }
 
-        log.debug("adding MAC filtering rules in TMAC table: {}", e.mac());
-        selector = DefaultTrafficSelector.builder();
-        treatment = DefaultTrafficTreatment.builder();
-        selector.matchInPort(p.port());
-        selector.matchVlanId(v.vlanId());
-        selector.matchEthType(Ethernet.TYPE_IPV4);
-        selector.matchEthDst(e.mac());
-        treatment.transition(UNICAST_ROUTING_TABLE);
-        rule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DEFAULT_PRIORITY)
-                .fromApp(applicationId)
-                .makePermanent()
-                .forTable(TMAC_TABLE).build();
-        ops = ops.add(rule);
+        if (ethCriterion == null) {
+            log.debug("filtering objective missing dstMac, cannot program TMAC table");
+        } else {
+            for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
+                                                         vidCriterion, assignedVlan,
+                                                         applicationId)) {
+                log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
+                          tmacRule, deviceId);
+                ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
+            }
+        }
+
+        if (ethCriterion == null || vidCriterion == null) {
+            log.debug("filtering objective missing dstMac or vlan, cannot program"
+                    + "Vlan Table");
+        } else {
+            for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion,
+                                                         assignedVlan,
+                                                         applicationId)) {
+                log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
+                          vlanRule, deviceId);
+                ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
+            }
+        }
 
-        log.debug("adding IP filtering rules in ACL table");
         for (IPCriterion ipaddr : ips) {
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-            selector.matchEthType(Ethernet.TYPE_IPV4);
-            selector.matchIPDst(ipaddr.ip());
-            treatment.setOutput(PortNumber.CONTROLLER);
-            rule = DefaultFlowRule.builder()
-                    .forDevice(deviceId)
-                    .withSelector(selector.build())
-                    .withTreatment(treatment.build())
-                    .withPriority(HIGHEST_PRIORITY)
-                    .fromApp(applicationId)
-                    .makePermanent()
-                    .forTable(ACL_TABLE).build();
-            ops =  ops.add(rule);
+            // since we ignore port information for IP rules, and the same (gateway) IP
+            // can be configured on multiple ports, we make sure that we send
+            // only a single rule to the switch.
+            if (!sentIpFilters.contains(ipaddr)) {
+                sentIpFilters.add(ipaddr);
+                log.debug("adding IP filtering rules in ACL table {} for dev: {}",
+                          ipaddr, deviceId);
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchEthType(Ethernet.TYPE_IPV4);
+                selector.matchIPDst(ipaddr.ip());
+                treatment.setOutput(PortNumber.CONTROLLER);
+                FlowRule rule = DefaultFlowRule.builder()
+                        .forDevice(deviceId)
+                        .withSelector(selector.build())
+                        .withTreatment(treatment.build())
+                        .withPriority(HIGHEST_PRIORITY)
+                        .fromApp(applicationId)
+                        .makePermanent()
+                        .forTable(ACL_TABLE).build();
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            }
         }
 
-        ops = install ? ops.add(rule) : ops.remove(rule);
         // apply filtering flow rules
         flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
             @Override
             public void onSuccess(FlowRuleOperations ops) {
-                log.info("Applied filtering rules");
+                log.info("Applied {} filtering rules in device {}",
+                         ops.stages().get(0).size(), deviceId);
                 pass(filt);
             }
 
             @Override
             public void onError(FlowRuleOperations ops) {
-                log.info("Failed to apply filtering rules");
+                log.info("Failed to apply all filtering rules in dev {}", deviceId);
                 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
             }
         }));
 
     }
 
-
     /**
-     * As per the OFDPA 1.0 TTP, packets are sent out of ports by using
-     * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface
-     * Group which in turns points to an output port. The Next Objective passed
-     * in by the application has to be broken up into a group chain
-     * to satisfy this TTP.
+     * Allows untagged packets into pipeline by assigning a vlan id.
+     * Vlan assignment is done by the application.
+     * Allows tagged packets into pipeline as per configured port-vlan info.
      *
-     * @param nextObj  the nextObjective of type SIMPLE
+     * @param portCriterion   port on device for which this filter is programmed
+     * @param vidCriterion   vlan assigned to port, or NONE for untagged
+     * @param assignedVlan   assigned vlan-id for untagged packets
+     * @param applicationId  for application programming this filter
+     * @return list of FlowRule for port-vlan filters
      */
-    private void processSimpleNextObjective(NextObjective nextObj) {
-        // break up simple next objective to GroupChain objects
-        TrafficTreatment treatment = nextObj.next().iterator().next();
-        // for the l2interface group, get vlan and port info
-        // for the l3unicast group, get the src/dst mac and vlan info
-        TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder();
-        TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder();
-        VlanId vlanid = null;
-        long portNum = 0;
-        for (Instruction ins : treatment.allInstructions()) {
-            if (ins.type() == Instruction.Type.L2MODIFICATION) {
-                L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
-                switch (l2ins.subtype()) {
-                case ETH_DST:
-                    l3utt.setEthDst(((ModEtherInstruction) l2ins).mac());
-                    break;
-                case ETH_SRC:
-                    l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac());
-                    break;
-                case VLAN_ID:
-                    vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
-                    l3utt.setVlanId(vlanid);
-                    break;
-                case DEC_MPLS_TTL:
-                case MPLS_LABEL:
-                case MPLS_POP:
-                case MPLS_PUSH:
-                case VLAN_PCP:
-                case VLAN_POP:
-                case VLAN_PUSH:
-                default:
-                    break;
+    protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
+                                                 VlanIdCriterion vidCriterion,
+                                                 VlanId assignedVlan,
+                                                 ApplicationId applicationId) {
+        List<FlowRule> rules = new ArrayList<FlowRule>();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector.matchVlanId(vidCriterion.vlanId());
+        if (vidCriterion.vlanId() == VlanId.NONE) {
+            // untagged packets are assigned vlans
+            treatment.pushVlan().setVlanId(assignedVlan);
+            // XXX ofdpa may require an additional vlan match on the assigned vlan
+            // and it may not require the push.
+        }
+        treatment.transition(TMAC_TABLE);
+
+        // ofdpa cannot match on ALL portnumber, so we need to use separate
+        // rules for each port.
+        List<PortNumber> portnums = new ArrayList<PortNumber>();
+        if (portCriterion.port() == PortNumber.ALL) {
+            for (Port port : deviceService.getPorts(deviceId)) {
+                if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
+                    portnums.add(port.number());
                 }
-            } else if (ins.type() == Instruction.Type.OUTPUT) {
-                portNum = ((OutputInstruction) ins).port().toLong();
-                l2itt.add(ins);
-            } else {
-                log.warn("Driver does not handle this type of TrafficTreatment"
-                        + " instruction in nextObjectives:  {}", ins.type());
             }
+        } else {
+            portnums.add(portCriterion.port());
         }
-
-        // assemble information for ofdpa l2interface group
-        int l2gk = nextObj.id() | GROUP1MASK;
-        final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
-        Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
-
-        // assemble information for ofdpa l3unicast group
-        int l3gk = nextObj.id() | GROUP0MASK;
-        final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk));
-        Integer l3groupId = L3UNICASTMASK | (int) portNum;
-        l3utt.group(new DefaultGroupId(l2groupId));
-        GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId,
-                                                l3utt.build(), nextObj.appId());
-
-        // create object for local and distributed storage
-        List<GroupKey> gkeys = new ArrayList<GroupKey>();
-        gkeys.add(l3groupkey); // group0 in chain
-        gkeys.add(l2groupkey); // group1 in chain
-        OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj);
-
-        // store l2groupkey with the groupChainElem for the l3group that depends on it
-        pendingGroups.put(l2groupkey, gce);
-
-        // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it
-        pendingNextObjectives.put(l3groupkey, ofdpaGrp);
-
-        // create group description for the ofdpa l2interfacegroup and send to groupservice
-        GroupBucket bucket =
-                DefaultGroupBucket.createIndirectGroupBucket(l2itt.build());
-        GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
-                             GroupDescription.Type.INDIRECT,
-                             new GroupBuckets(Collections.singletonList(bucket)),
-                             l2groupkey,
-                             l2groupId,
-                             nextObj.appId());
-        groupService.addGroup(groupDescription);
+        for (PortNumber pnum : portnums) {
+            selector.matchInPort(pnum);
+            FlowRule rule = DefaultFlowRule.builder()
+                    .forDevice(deviceId)
+                    .withSelector(selector.build())
+                    .withTreatment(treatment.build())
+                    .withPriority(DEFAULT_PRIORITY)
+                    .fromApp(applicationId)
+                    .makePermanent()
+                    .forTable(VLAN_TABLE).build();
+            rules.add(rule);
+        }
+        return rules;
     }
 
     /**
-     * Processes next element of a group chain. Assumption is that if this
-     * group points to another group, the latter has already been created
-     * and this driver has received notification for it. A second assumption is
-     * that if there is another group waiting for this group then the appropriate
-     * stores already have the information to act upon the notification for the
-     * creating of this group.
+     * Allows routed packets with correct destination MAC to be directed
+     * to unicast-IP routing table or MPLS forwarding table.
+     * XXX need to add rule for multicast routing.
      *
-     * @param gce the group chain element to be processed next
+     * @param portCriterion  port on device for which this filter is programmed
+     * @param ethCriterion   dstMac of device for which is filter is programmed
+     * @param vidCriterion   vlan assigned to port, or NONE for untagged
+     * @param assignedVlan   assigned vlan-id for untagged packets
+     * @param applicationId  for application programming this filter
+     * @return list of FlowRule for port-vlan filters
+
      */
-    private void processGroupChain(GroupChainElem gce) {
-        GroupBucket bucket = DefaultGroupBucket
-                .createIndirectGroupBucket(gce.getBucketActions());
-        GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
-                             GroupDescription.Type.INDIRECT,
-                             new GroupBuckets(Collections.singletonList(bucket)),
-                             gce.getGkey(),
-                             gce.getGivenGroupId(),
-                             gce.getAppId());
-        groupService.addGroup(groupDesc);
+    protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
+                                                 EthCriterion ethCriterion,
+                                                 VlanIdCriterion vidCriterion,
+                                                 VlanId assignedVlan,
+                                                 ApplicationId applicationId) {
+        //handling untagged packets via assigned VLAN
+        if (vidCriterion.vlanId() == VlanId.NONE) {
+            vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
+        }
+        // ofdpa cannot match on ALL portnumber, so we need to use separate
+        // rules for each port.
+        List<PortNumber> portnums = new ArrayList<PortNumber>();
+        if (portCriterion.port() == PortNumber.ALL) {
+            for (Port port : deviceService.getPorts(deviceId)) {
+                if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
+                    portnums.add(port.number());
+                }
+            }
+        } else {
+            portnums.add(portCriterion.port());
+        }
+
+        List<FlowRule> rules = new ArrayList<FlowRule>();
+        for (PortNumber pnum : portnums) {
+            // for unicast IP packets
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            selector.matchInPort(pnum);
+            selector.matchVlanId(vidCriterion.vlanId());
+            selector.matchEthType(Ethernet.TYPE_IPV4);
+            selector.matchEthDst(ethCriterion.mac());
+            treatment.transition(UNICAST_ROUTING_TABLE);
+            FlowRule rule = DefaultFlowRule.builder()
+                    .forDevice(deviceId)
+                    .withSelector(selector.build())
+                    .withTreatment(treatment.build())
+                    .withPriority(DEFAULT_PRIORITY)
+                    .fromApp(applicationId)
+                    .makePermanent()
+                    .forTable(TMAC_TABLE).build();
+            rules.add(rule);
+            //for MPLS packets
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+            selector.matchInPort(pnum);
+            selector.matchVlanId(vidCriterion.vlanId());
+            selector.matchEthType(Ethernet.MPLS_UNICAST);
+            selector.matchEthDst(ethCriterion.mac());
+            treatment.transition(MPLS_TABLE_0);
+            rule = DefaultFlowRule.builder()
+                    .forDevice(deviceId)
+                    .withSelector(selector.build())
+                    .withTreatment(treatment.build())
+                    .withPriority(DEFAULT_PRIORITY)
+                    .fromApp(applicationId)
+                    .makePermanent()
+                    .forTable(TMAC_TABLE).build();
+            rules.add(rule);
+        }
+        return rules;
     }
 
     private Collection<FlowRule> processForward(ForwardingObjective fwd) {
@@ -493,7 +579,7 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
     }
 
     /**
-     * In the OF-DPA 1.0 pipeline, versatile forwarding objectives go to the
+     * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
      * ACL table.
      * @param fwd  the forwarding objective of type 'versatile'
      * @return     a collection of flow rules to be sent to the switch. An empty
@@ -508,37 +594,46 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
         if (ethType == null) {
             log.error("Versatile forwarding objective must include ethType");
-            fail(fwd, ObjectiveError.UNKNOWN);
+            fail(fwd, ObjectiveError.BADPARAMS);
             return Collections.emptySet();
         }
-        if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
-            log.warn("Installing ARP rule to table 60");
-
-            // currently need to punt from ACL table should use:
-            // OF apply-actions-instruction
-            // To use OF write-actions-instruction
-            /*TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
-            fwd.treatment().allInstructions().stream()
-                .forEach(ti -> tb.deferred().add(ti));*/
-
-            FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
-                    .fromApp(fwd.appId())
-                    .withPriority(fwd.priority())
-                    .forDevice(deviceId)
-                    .withSelector(fwd.selector())
-                    .withTreatment(fwd.treatment())
-                    .makePermanent()
-                    .forTable(ACL_TABLE);
-
-            return Collections.singletonList(ruleBuilder.build());
+        if (fwd.nextId() == null && fwd.treatment() == null) {
+            log.error("Forwarding objective {} from {} must contain "
+                    + "nextId or Treatment", fwd.selector(), fwd.appId());
+            return Collections.emptySet();
+        }
+        // XXX driver does not currently do type checking as per Tables 65-67 in
+        // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
+        if (fwd.treatment() != null &&
+                fwd.treatment().allInstructions().size() == 1 &&
+                fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
+            OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
+            if (o.port() == PortNumber.CONTROLLER) {
+                FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                        .fromApp(fwd.appId())
+                        .withPriority(fwd.priority())
+                        .forDevice(deviceId)
+                        .withSelector(fwd.selector())
+                        .withTreatment(fwd.treatment())
+                        .makePermanent()
+                        .forTable(ACL_TABLE);
+                return Collections.singletonList(ruleBuilder.build());
+            } else {
+                log.warn("Only allowed treatments in versatile forwarding "
+                        + "objectives are punts to the controller");
+                return Collections.emptySet();
+            }
         }
 
-        // XXX not handling other versatile flows yet
+        if (fwd.nextId() != null) {
+            // XXX overide case
+            log.warn("versatile objective --> next Id not yet implemeted");
+        }
         return Collections.emptySet();
     }
 
     /**
-     * In the OF-DPA 1.0 pipeline, specific forwarding refers to the IP table
+     * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
      * (unicast or multicast) or the L2 table (mac + vlan).
      *
      * @param fwd the forwarding objective of type 'specific'
@@ -602,151 +697,126 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
         }
     }
 
-
     private void fail(Objective obj, ObjectiveError error) {
         if (obj.context().isPresent()) {
             obj.context().get().onError(obj, error);
         }
     }
 
+    //////////////////////////////////////
+    //  Group handling
+    //////////////////////////////////////
 
-    protected void initializePipeline() {
-        processPortTable();
-        processVlanTable();
-        processTmacTable();
-        processIpTable();
-        //processMcastTable();
-        //processBridgingTable();
-        //processAclTable();
-        //processGroupTable();
-        //processMplsTable();
-    }
+    /**
+     * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
+     * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface
+     * Group which in turns points to an output port. The Next Objective passed
+     * in by the application has to be broken up into a group chain
+     * to satisfy this TTP.
+     *
+     * @param nextObj  the nextObjective of type SIMPLE
+     */
+    private void processSimpleNextObjective(NextObjective nextObj) {
+        // break up simple next objective to GroupChain objects
+        TrafficTreatment treatment = nextObj.next().iterator().next();
+        // for the l2interface group, get vlan and port info
+        // for the l3unicast group, get the src/dst mac and vlan info
+        TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder();
+        TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder();
+        VlanId vlanid = null;
+        long portNum = 0;
+        for (Instruction ins : treatment.allInstructions()) {
+            if (ins.type() == Instruction.Type.L2MODIFICATION) {
+                L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
+                switch (l2ins.subtype()) {
+                case ETH_DST:
+                    l3utt.setEthDst(((ModEtherInstruction) l2ins).mac());
+                    break;
+                case ETH_SRC:
+                    l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac());
+                    break;
+                case VLAN_ID:
+                    vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
+                    l3utt.setVlanId(vlanid);
+                    break;
+                case DEC_MPLS_TTL:
+                case MPLS_LABEL:
+                case MPLS_POP:
+                case MPLS_PUSH:
+                case VLAN_PCP:
+                case VLAN_POP:
+                case VLAN_PUSH:
+                default:
+                    break;
+                }
+            } else if (ins.type() == Instruction.Type.OUTPUT) {
+                portNum = ((OutputInstruction) ins).port().toLong();
+                l2itt.add(ins);
+            } else {
+                log.warn("Driver does not handle this type of TrafficTreatment"
+                        + " instruction in nextObjectives:  {}", ins.type());
+            }
+        }
 
-    protected void processMplsTable() {
-        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        selector.matchEthType(Ethernet.MPLS_UNICAST);
-        selector.matchMplsLabel(MplsLabel.mplsLabel(0xff));
-        selector.matchMplsBos(true);
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        treatment.popMpls(Ethernet.TYPE_IPV4);
-        treatment.transition(ACL_TABLE);
-        FlowRule test = DefaultFlowRule.builder().forDevice(deviceId)
-                .withSelector(selector.build()).withTreatment(treatment.build())
-                .withPriority(LOWEST_PRIORITY).fromApp(driverId).makePermanent()
-                .forTable(25).build();
-        ops = ops.add(test);
-
-        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
-            @Override
-            public void onSuccess(FlowRuleOperations ops) {
-                log.info("Initialized mpls table");
-            }
-
-            @Override
-            public void onError(FlowRuleOperations ops) {
-                log.info("Failed to initialize mpls table");
-            }
-        }));
-
-    }
+        // assemble information for ofdpa l2interface group
+        int l2gk = nextObj.id() | GROUP1MASK;
+        final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
+        Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
 
-    protected void processPortTable() {
-        //XXX is table miss entry enough or do we need to do the maskable in-port 0?
-        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        treatment.transition(VLAN_TABLE);
-        FlowRule tmisse = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(LOWEST_PRIORITY)
-                .fromApp(driverId)
-                .makePermanent()
-                .forTable(PORT_TABLE).build();
-        /*ops = ops.add(tmisse);
+        // assemble information for ofdpa l3unicast group
+        int l3gk = nextObj.id() | GROUP0MASK;
+        final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk));
+        Integer l3groupId = L3UNICASTMASK | (int) portNum;
+        l3utt.group(new DefaultGroupId(l2groupId));
+        GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId,
+                                                l3utt.build(), nextObj.appId());
 
-        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
-            @Override
-            public void onSuccess(FlowRuleOperations ops) {
-                log.info("Initialized port table");
-            }
+        // create object for local and distributed storage
+        List<GroupKey> gkeys = new ArrayList<GroupKey>();
+        gkeys.add(l3groupkey); // group0 in chain
+        gkeys.add(l2groupkey); // group1 in chain
+        OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj);
 
-            @Override
-            public void onError(FlowRuleOperations ops) {
-                log.info("Failed to initialize port table");
-            }
-        }));*/
+        // store l2groupkey with the groupChainElem for the l3group that depends on it
+        pendingGroups.put(l2groupkey, gce);
 
-    }
+        // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it
+        pendingNextObjectives.put(l3groupkey, ofdpaGrp);
 
-    private void processVlanTable() {
-        // Table miss entry is not required as ofdpa default is to drop
-        // In OF terms, the absence of a t.m.e. also implies drop
+        // create group description for the ofdpa l2interfacegroup and send to groupservice
+        GroupBucket bucket =
+                DefaultGroupBucket.createIndirectGroupBucket(l2itt.build());
+        GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.INDIRECT,
+                             new GroupBuckets(Collections.singletonList(bucket)),
+                             l2groupkey,
+                             l2groupId,
+                             nextObj.appId());
+        groupService.addGroup(groupDescription);
     }
 
-
-    protected void processTmacTable() {
-        //table miss entry
-        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        selector = DefaultTrafficSelector.builder();
-        treatment = DefaultTrafficTreatment.builder();
-        treatment.transition(BRIDGING_TABLE);
-        FlowRule rule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(LOWEST_PRIORITY)
-                .fromApp(driverId)
-                .makePermanent()
-                .forTable(TMAC_TABLE).build();
-        /*ops =  ops.add(rule); // XXX bug in ofdpa
-        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
-            @Override
-            public void onSuccess(FlowRuleOperations ops) {
-                log.info("Initialized tmac table");
-            }
-
-            @Override
-            public void onError(FlowRuleOperations ops) {
-                log.info("Failed to initialize tmac table");
-            }
-        }));*/
+    /**
+     * Processes next element of a group chain. Assumption is that if this
+     * group points to another group, the latter has already been created
+     * and this driver has received notification for it. A second assumption is
+     * that if there is another group waiting for this group then the appropriate
+     * stores already have the information to act upon the notification for the
+     * creating of this group.
+     *
+     * @param gce the group chain element to be processed next
+     */
+    private void processGroupChain(GroupChainElem gce) {
+        GroupBucket bucket = DefaultGroupBucket
+                .createIndirectGroupBucket(gce.getBucketActions());
+        GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.INDIRECT,
+                             new GroupBuckets(Collections.singletonList(bucket)),
+                             gce.getGkey(),
+                             gce.getGivenGroupId(),
+                             gce.getAppId());
+        groupService.addGroup(groupDesc);
     }
 
-    protected void processIpTable() {
-        //table miss entry
-        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        selector = DefaultTrafficSelector.builder();
-        treatment = DefaultTrafficTreatment.builder();
-        treatment.transition(ACL_TABLE);
-        FlowRule rule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(LOWEST_PRIORITY)
-                .fromApp(driverId)
-                .makePermanent()
-                .forTable(UNICAST_ROUTING_TABLE).build();
-        /*ops =  ops.add(rule);
-        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
-            @Override
-            public void onSuccess(FlowRuleOperations ops) {
-                log.info("Initialized IP table");
-            }
-
-            @Override
-            public void onError(FlowRuleOperations ops) {
-                log.info("Failed to initialize unicast IP table");
-            }
-        }));*/
-    }
 
     private class GroupChecker implements Runnable {
         @Override
@@ -884,4 +954,416 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline
         }
 
     }
+
+    //////////////////////////////////////
+    //  Test code to be used for future
+    //  static-flow-pusher app
+    //////////////////////////////////////
+
+    public void processStaticFlows() {
+        //processPortTable();
+        processGroupTable();
+        processVlanTable();
+        processTmacTable();
+        processIpTable();
+        //processMcastTable();
+        //processBridgingTable();
+        processAclTable();
+        sendPackets();
+        processMplsTable();
+    }
+
+    protected void processGroupTable() {
+        TrafficTreatment.Builder act = DefaultTrafficTreatment.builder();
+
+        act.popVlan(); // to send out untagged packets
+        act.setOutput(PortNumber.portNumber(24));
+        GroupBucket bucket =
+                DefaultGroupBucket.createIndirectGroupBucket(act.build());
+        final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500));
+        Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24
+        GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.INDIRECT,
+                             new GroupBuckets(Collections.singletonList(bucket)),
+                             groupkey,
+                             groupId,
+                             driverId);
+        groupService.addGroup(groupDescription);
+
+        TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder();
+        act2.setOutput(PortNumber.portNumber(40));
+        GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build());
+        final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502));
+        Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40
+        GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.INDIRECT,
+                             new GroupBuckets(Collections.singletonList(bucket2)),
+                             groupkey2,
+                             groupId2,
+                             driverId);
+        groupService.addGroup(groupDescription2);
+
+        while (groupService.getGroup(deviceId, groupkey2) == null) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+
+        //Now for L3 Unicast group
+        TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder();
+        act3.setEthDst(MacAddress.valueOf(0x2020));
+        act3.setEthSrc(MacAddress.valueOf(0x1010));
+        act3.setVlanId(VlanId.vlanId((short) 200));
+        act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface
+        // MPLS interface group - does not work for popping single label
+        //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026
+        Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001
+        GroupBucket bucket3 =
+                DefaultGroupBucket.createIndirectGroupBucket(act3.build());
+        final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503));
+        GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.INDIRECT,
+                             new GroupBuckets(Collections.singletonList(bucket3)),
+                             groupkey3,
+                             groupId3,
+                             driverId);
+        groupService.addGroup(groupDescription3);
+
+        //Another L3 Unicast group
+        TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder();
+        act4.setEthDst(MacAddress.valueOf(0x3030));
+        act4.setEthSrc(MacAddress.valueOf(0x1010));
+        act4.setVlanId(VlanId.vlanId((short) 197));
+        act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface
+        Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002
+        GroupBucket bucket4 =
+                DefaultGroupBucket.createIndirectGroupBucket(act4.build());
+        final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504));
+        GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.INDIRECT,
+                             new GroupBuckets(Collections.singletonList(bucket4)),
+                             groupkey4,
+                             groupId4,
+                             driverId);
+        groupService.addGroup(groupDescription4);
+
+        while (groupService.getGroup(deviceId, groupkey4) == null) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+
+        // L3 ecmp group
+        TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder();
+        act5.group(new DefaultGroupId(0x20000001));
+        TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder();
+        act6.group(new DefaultGroupId(0x20000002));
+        GroupBucket buckete1 =
+                DefaultGroupBucket.createSelectGroupBucket(act5.build());
+        GroupBucket buckete2 =
+                DefaultGroupBucket.createSelectGroupBucket(act6.build());
+        List<GroupBucket> bktlist = new ArrayList<GroupBucket>();
+        bktlist.add(buckete1);
+        bktlist.add(buckete2);
+        final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505));
+        Integer groupId5 = L3ECMPMASK | 5; // 0x70000005
+        GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId,
+                             GroupDescription.Type.SELECT,
+                             new GroupBuckets(bktlist),
+                             groupkey5,
+                             groupId5,
+                             driverId);
+        groupService.addGroup(groupDescription5);
+
+
+    }
+
+    @SuppressWarnings("deprecation")
+    protected void processMplsTable() {
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(Ethernet.MPLS_UNICAST);
+        selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255
+        selector.matchMplsBos(true);
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.decMplsTtl(); // nw_ttl does not work
+        treatment.copyTtlIn();
+        treatment.popMpls(Ethernet.TYPE_IPV4);
+        treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast
+        //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP
+        treatment.transition(ACL_TABLE);
+        FlowRule test = DefaultFlowRule.builder().forDevice(deviceId)
+                .withSelector(selector.build()).withTreatment(treatment.build())
+                .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent()
+                .forTable(24).build();
+        ops = ops.add(test);
+
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized mpls table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize mpls table");
+            }
+        }));
+
+    }
+
+    protected void processPortTable() {
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(VLAN_TABLE);
+        FlowRule tmisse = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(LOWEST_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(PORT_TABLE).build();
+        ops = ops.add(tmisse);
+
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized port table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize port table");
+            }
+        }));
+
+    }
+
+    private void processVlanTable() {
+        // Table miss entry is not required as ofdpa default is to drop
+        // In OF terms, the absence of a t.m.e. also implies drop
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector.matchInPort(PortNumber.portNumber(12));
+        selector.matchVlanId(VlanId.vlanId((short) 100));
+        treatment.transition(TMAC_TABLE);
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DEFAULT_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(VLAN_TABLE).build();
+        ops =  ops.add(rule);
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized vlan table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize vlan table");
+            }
+        }));
+    }
+
+    protected void processTmacTable() {
+        //table miss entry
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector.matchInPort(PortNumber.portNumber(12));
+        selector.matchVlanId(VlanId.vlanId((short) 100));
+        selector.matchEthType(Ethernet.TYPE_IPV4);
+        selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
+        treatment.transition(UNICAST_ROUTING_TABLE);
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DEFAULT_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(TMAC_TABLE).build();
+        ops = ops.add(rule);
+
+        selector.matchEthType(Ethernet.MPLS_UNICAST);
+        treatment.transition(MPLS_TABLE_0);
+        FlowRule rulempls = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DEFAULT_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(TMAC_TABLE).build();
+        ops = ops.add(rulempls);
+
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized tmac table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize tmac table");
+            }
+        }));
+    }
+
+    protected void processIpTable() {
+        //table miss entry
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector.matchEthType(Ethernet.TYPE_IPV4);
+        selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16"));
+        treatment.deferred().group(new DefaultGroupId(0x20000001));
+        treatment.transition(ACL_TABLE);
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(30000)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(UNICAST_ROUTING_TABLE).build();
+        ops =  ops.add(rule);
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized IP table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize unicast IP table");
+            }
+        }));
+    }
+
+    protected void processAclTable() {
+        //table miss entry
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
+        treatment.deferred().group(new DefaultGroupId(0x20000001));
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(60000)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(ACL_TABLE).build();
+        ops =  ops.add(rule);
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized Acl table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize Acl table");
+            }
+        }));
+    }
+
+    private void sendPackets() {
+        Ethernet eth = new Ethernet();
+        eth.setDestinationMACAddress("00:00:00:00:00:02");
+        eth.setSourceMACAddress("00:00:00:11:22:33");
+        eth.setVlanID((short) 100);
+        eth.setEtherType(Ethernet.MPLS_UNICAST);
+        MPLS mplsPkt = new MPLS();
+        mplsPkt.setLabel(255);
+        mplsPkt.setTtl((byte) 5);
+
+        IPv4 ipv4 = new IPv4();
+
+        ipv4.setDestinationAddress("4.0.5.6");
+        ipv4.setSourceAddress("1.0.2.3");
+        ipv4.setTtl((byte) 64);
+        ipv4.setChecksum((short) 0);
+
+        UDP udp = new UDP();
+        udp.setDestinationPort(666);
+        udp.setSourcePort(333);
+        udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
+        udp.setChecksum((short) 0);
+
+        ipv4.setPayload(udp);
+        mplsPkt.setPayload(ipv4);
+        eth.setPayload(mplsPkt);
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(24))
+                .build();
+        OutboundPacket packet = new DefaultOutboundPacket(deviceId,
+                                                          treatment,
+                                                          ByteBuffer.wrap(eth.serialize()));
+
+
+        Ethernet eth2 = new Ethernet();
+        eth2.setDestinationMACAddress("00:00:00:00:00:02");
+        eth2.setSourceMACAddress("00:00:00:11:22:33");
+        eth2.setVlanID((short) 100);
+        eth2.setEtherType(Ethernet.TYPE_IPV4);
+
+        IPv4 ipv42 = new IPv4();
+        ipv42.setDestinationAddress("2.0.0.2");
+        ipv42.setSourceAddress("1.0.9.9");
+        ipv42.setTtl((byte) 64);
+        ipv42.setChecksum((short) 0);
+
+        UDP udp2 = new UDP();
+        udp2.setDestinationPort(999);
+        udp2.setSourcePort(333);
+        udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
+        udp2.setChecksum((short) 0);
+
+        ipv42.setPayload(udp2);
+        eth2.setPayload(ipv42);
+
+        TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(26))
+                .build();
+        OutboundPacket packet2 = new DefaultOutboundPacket(deviceId,
+                                                          treatment2,
+                                                          ByteBuffer.wrap(eth2.serialize()));
+
+
+        log.info("Emitting packets now");
+        packetService.emit(packet);
+        packetService.emit(packet);
+        packetService.emit(packet2);
+        packetService.emit(packet);
+        packetService.emit(packet);
+        log.info("Done emitting packets");
+    }
+
+    private class InternalPacketProcessor implements PacketProcessor {
+
+        @Override
+        public void process(PacketContext context) {
+
+
+        }
+    }
+
 }
index c02ba3c..31297ff 100644 (file)
@@ -53,6 +53,7 @@ import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flowobjective.FilteringObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveStore;
 import org.onosproject.net.flowobjective.ForwardingObjective;
@@ -246,6 +247,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
     private void addGroup(NextObjective nextObjective) {
         log.debug("addGroup with type{} for nextObjective id {}",
                   nextObjective.type(), nextObjective.id());
+        List<GroupBucket> buckets;
         switch (nextObjective.type()) {
             case SIMPLE:
                 log.debug("processing SIMPLE next objective");
@@ -273,7 +275,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
                 break;
             case HASHED:
                 log.debug("processing HASHED next objective");
-                List<GroupBucket> buckets = nextObjective
+                buckets = nextObjective
                         .next()
                         .stream()
                         .map((treatment) -> DefaultGroupBucket
@@ -297,8 +299,32 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
                 }
                 break;
             case BROADCAST:
+                log.debug("processing BROADCAST next objective");
+                buckets = nextObjective
+                        .next()
+                        .stream()
+                        .map((treatment) -> DefaultGroupBucket
+                                .createAllGroupBucket(treatment))
+                        .collect(Collectors.toList());
+                if (!buckets.isEmpty()) {
+                    final GroupKey key = new DefaultGroupKey(
+                            appKryo.serialize(nextObjective
+                                                      .id()));
+                    GroupDescription groupDescription = new DefaultGroupDescription(
+                            deviceId,
+                            GroupDescription.Type.ALL,
+                            new GroupBuckets(buckets),
+                            key,
+                            null,
+                            nextObjective.appId());
+                    log.debug("Creating BROADCAST group for next objective id {}",
+                              nextObjective.id());
+                    groupService.addGroup(groupDescription);
+                    pendingGroups.put(key, nextObjective);
+                }
+                break;
             case FAILOVER:
-                log.debug("BROADCAST and FAILOVER next objectives not supported");
+                log.debug("FAILOVER next objectives not supported");
                 fail(nextObjective, ObjectiveError.UNSUPPORTED);
                 log.warn("Unsupported next objective type {}", nextObjective.type());
                 break;
@@ -326,6 +352,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
             bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
         } else if (group.type() == GroupDescription.Type.SELECT) {
             bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
+        } else if (group.type() == GroupDescription.Type.ALL) {
+            bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
         } else {
             log.warn("Unsupported Group type {}", group.type());
             return;
@@ -356,6 +384,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
                 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
             } else if (group.type() == GroupDescription.Type.SELECT) {
                 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
+            } else if (group.type() == GroupDescription.Type.ALL) {
+                bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
             } else {
                 log.warn("Unsupported Group type {}", group.type());
                 return;
@@ -383,7 +413,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
     private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
         log.debug("Processing versatile forwarding objective");
         TrafficSelector selector = fwd.selector();
-
+        TrafficTreatment treatment = null;
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
         if (ethType == null) {
@@ -410,15 +440,26 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
                     return Collections.emptySet();
                 }
                 treatmentBuilder.deferred().group(group.id());
+                treatment = treatmentBuilder.build();
                 log.debug("Adding OUTGROUP action");
             }
+        } else if (fwd.treatment() != null) {
+            if (fwd.treatment().allInstructions().size() == 1 &&
+                    fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
+                OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
+                if (o.port() == PortNumber.CONTROLLER) {
+                    log.warn("Punts to the controller are handled by misses in"
+                            + " the TMAC, IP and MPLS tables.");
+                    return Collections.emptySet();
+                }
+            }
+            treatment = fwd.treatment();
         } else {
-            log.warn("VERSATILE forwarding objective need next objective ID.");
+            log.warn("VERSATILE forwarding objective needs next objective ID "
+                    + "or treatment.");
             return Collections.emptySet();
         }
 
-        TrafficTreatment treatment = treatmentBuilder.build();
-
         FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
                 .fromApp(fwd.appId()).withPriority(fwd.priority())
                 .forDevice(deviceId).withSelector(fwd.selector())
@@ -527,7 +568,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
     protected List<FlowRule> processEthDstFilter(Criterion c,
                                        FilteringObjective filt,
                                        ApplicationId applicationId) {
-        List<FlowRule> rules = new ArrayList<FlowRule>();
+        List<FlowRule> rules = new ArrayList<>();
         EthCriterion e = (EthCriterion) c;
         TrafficSelector.Builder selectorIp = DefaultTrafficSelector
                 .builder();
@@ -565,7 +606,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
     protected List<FlowRule> processVlanIdFilter(Criterion c,
                                                  FilteringObjective filt,
                                                  ApplicationId applicationId) {
-        List<FlowRule> rules = new ArrayList<FlowRule>();
+        List<FlowRule> rules = new ArrayList<>();
         VlanIdCriterion v = (VlanIdCriterion) c;
         log.debug("adding rule for VLAN: {}", v.vlanId());
         TrafficSelector.Builder selector = DefaultTrafficSelector
@@ -616,21 +657,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
                     ops = install ? ops.add(rule) : ops.remove(rule);
                 }
             } else if (c.type() == Criterion.Type.IPV4_DST) {
-                IPCriterion ip = (IPCriterion) c;
-                log.debug("adding rule for IP: {}", ip.ip());
-                TrafficSelector.Builder selector = DefaultTrafficSelector
-                        .builder();
-                TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                        .builder();
-                selector.matchEthType(Ethernet.TYPE_IPV4);
-                selector.matchIPDst(ip.ip());
-                treatment.transition(aclTableId);
-                FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
-                        .withSelector(selector.build())
-                        .withTreatment(treatment.build())
-                        .withPriority(filt.priority()).fromApp(applicationId)
-                        .makePermanent().forTable(ipv4UnicastTableId).build();
-                ops = install ? ops.add(rule) : ops.remove(rule);
+                log.debug("driver does not process IP filtering rules as it " +
+                        "sends all misses in the IP table to the controller");
             } else {
                 log.warn("Driver does not currently process filtering condition"
                                  + " of type: {}", c.type());
@@ -762,6 +790,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
             this.key = key;
         }
 
+        @SuppressWarnings("unused")
         public GroupKey key() {
             return key;
         }
index 5059d4b..af49883 100644 (file)
                    impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
         <behaviour api="org.onosproject.net.behaviour.ControllerConfig"
                    impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/>
+        <behaviour api="org.onosproject.openflow.controller.ExtensionInterpreter"
+                   impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
+        <behaviour api="org.onosproject.net.behaviour.ExtensionResolver"
+                   impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
     </driver>
     <driver name="ovs-corsa" extends="ovs"
             manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.driver.pipeline.OVSCorsaPipeline"/>
     </driver>
+    <!--  Emulation of the spring-open pipeline using a CPqD OF 1.3 software switch.
+       ~  This driver is the default driver assigned to the CPqD switch.
+      -->
     <driver name="spring-open-cpqd" extends="default"
             manufacturer="Stanford University, Ericsson Research and CPqD Research"
             hwVersion="OpenFlow 1.3 Reference Userspace Switch" swVersion=".*">
@@ -66,7 +73,7 @@
     <driver name="ofdpa" extends="default"
             manufacturer="Broadcom Corp." hwVersion="OF-DPA.*" swVersion="OF-DPA.*">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.OFDPA1Pipeline"/>
+                   impl="org.onosproject.driver.pipeline.OFDPA2Pipeline"/>
     </driver>
     <driver name="pmc-olt" extends="default"
             manufacturer="Big Switch Networks" hwVersion="ivs 0.5" swVersion="ivs 0.5">
             manufacturer="ONF"
             hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.CpqdOFDPA1Pipeline"/>
+                   impl="org.onosproject.driver.pipeline.CpqdOFDPA2Pipeline"/>
     </driver>
     <driver name="calient" extends="default"
             manufacturer="calient inc" hwVersion="calient hardware"
index dec0299..1aae0f3 100644 (file)
@@ -96,6 +96,7 @@
         <bundle>mvn:org.onosproject/onos-core-net/@ONOS-VERSION</bundle>
         <bundle>mvn:org.onosproject/onos-core-common/@ONOS-VERSION</bundle>
         <bundle>mvn:org.onosproject/onos-core-dist/@ONOS-VERSION</bundle>
+        <bundle>mvn:org.onosproject/onos-core-persistence/@ONOS-VERSION</bundle>
         <bundle>mvn:org.onosproject/onos-core-serializers/@ONOS-VERSION</bundle>
         <bundle>mvn:org.onosproject/onlab-netty/@ONOS-VERSION</bundle>
     </feature>
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java
new file mode 100644 (file)
index 0000000..6cea24d
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Interface Service.
+ */
+package org.onosproject.incubator.net.intf;
diff --git a/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java b/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java
new file mode 100644 (file)
index 0000000..5562bd3
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Created by ray on 10/30/15.
+ */
+package org.onosproject.netconf;
diff --git a/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java b/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java
new file mode 100644 (file)
index 0000000..84992bf
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Created by ray on 10/30/15.
+ */
+package org.onosproject.netconf.ctl;
diff --git a/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java b/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java
new file mode 100644 (file)
index 0000000..616a7ce
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Created by ray on 10/30/15.
+ */
+package org.onosproject.netconf.rfc;
diff --git a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java
new file mode 100644 (file)
index 0000000..44b121a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.openflow.controller;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+
+/**
+ * Interprets extension instructions and converts them to/from OpenFlow objects.
+ */
+@Beta
+public interface ExtensionInterpreter extends HandlerBehaviour {
+
+    /**
+     * Returns true if the given extension instruction is supported by this
+     * driver.
+     *
+     * @param extensionType extension instruction type
+     * @return true if the instruction is supported, otherwise false
+     */
+    boolean supported(ExtensionType extensionType);
+
+    /**
+     * Maps an extension instruction to an OpenFlow action.
+     *
+     * @param factory OpenFlow factory
+     * @param extensionInstruction extension instruction
+     * @return OpenFlow action
+     */
+    OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction);
+
+    /**
+     * Maps an OpenFlow action to an extension instruction.
+     *
+     * @param action OpenFlow action
+     * @return extension instruction
+     */
+    ExtensionInstruction mapAction(OFAction action);
+
+}
index 6a06724..d8aaef6 100644 (file)
@@ -16,8 +16,7 @@
 package org.onosproject.ovsdb.controller;
 
 /**
- * Represents for a entity that carry important information for listener.
+ * Representation for an entity that carries important information for a listener.
  */
 public interface EventSubject {
-
 }
index 1ee0a36..18c59e1 100644 (file)
@@ -21,7 +21,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.Objects;
 
 /**
- * The class representing a ovsdb bridge. This class is immutable.
+ * The class representing an ovsdb bridge.
+ * This class is immutable.
  */
 public final class OvsdbBridge {
 
@@ -29,7 +30,7 @@ public final class OvsdbBridge {
     private final OvsdbDatapathId datapathId;
 
     /**
-     * Constructor from a OvsdbBridgeName bridgeName and a OvsdbDatapathId
+     * Constructor from an OvsdbBridgeName bridgeName and an OvsdbDatapathId
      * datapathId.
      *
      * @param bridgeName the bridgeName to use
@@ -43,16 +44,16 @@ public final class OvsdbBridge {
     }
 
     /**
-     * Gets the bridge name of the bridge.
+     * Gets the bridge name of bridge.
      *
-     * @return the bridge name of the bridge
+     * @return the bridge name of bridge
      */
     public OvsdbBridgeName bridgeName() {
         return bridgeName;
     }
 
     /**
-     * Gets the datapathId of the bridge.
+     * Gets the datapathId of bridge.
      *
      * @return datapathId the datapathId to use
      */
index daedff5..899799f 100644 (file)
@@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.Objects;
 
 /**
- * The class representing a bridge name. This class is immutable.
+ * The class representing a bridge name.
+ * This class is immutable.
  */
 public final class OvsdbBridgeName {
 
     private final String value;
 
     /**
-     * Constructor from a String bridge name.
+     * Constructor from a String.
      *
      * @param value the bridge name to use
      */
@@ -38,7 +39,7 @@ public final class OvsdbBridgeName {
     }
 
     /**
-     * Gets the value of the bridge name.
+     * Gets the value of bridge name.
      *
      * @return the value of the bridge name
      */
index e619f8e..edd25ac 100644 (file)
@@ -43,7 +43,7 @@ public interface OvsdbClientService extends OvsdbRPC {
     OvsdbNodeId nodeId();
 
     /**
-     * Creates the configuration for the tunnel.
+     * Creates the configuration for tunnel.
      *
      * @param srcIp source IP address
      * @param dstIp destination IP address
@@ -62,7 +62,7 @@ public interface OvsdbClientService extends OvsdbRPC {
     boolean createTunnel(String bridgeName, String portName, String tunnelType, Map<String, String> options);
 
     /**
-     * Drops the configuration for the tunnel.
+     * Drops the configuration for tunnel.
      *
      * @param srcIp source IP address
      * @param dstIp destination IP address
@@ -70,7 +70,7 @@ public interface OvsdbClientService extends OvsdbRPC {
     void dropTunnel(IpAddress srcIp, IpAddress dstIp);
 
     /**
-     * Gets tunnels of the node.
+     * Gets tunnels of node.
      *
      * @return set of tunnels; empty if no tunnel is find
      */
@@ -102,14 +102,14 @@ public interface OvsdbClientService extends OvsdbRPC {
     void dropBridge(String bridgeName);
 
     /**
-     * Gets bridges of the node.
+     * Gets bridges of node.
      *
      * @return set of bridges; empty if no bridge is find
      */
     Set<OvsdbBridge> getBridges();
 
     /**
-     * Gets controllers of the node.
+     * Gets controllers of node.
      *
      * @param openflowDeviceId target device id
      * @return set of controllers; empty if no controller is find
@@ -155,7 +155,7 @@ public interface OvsdbClientService extends OvsdbRPC {
     void dropPort(String bridgeName, String portName);
 
     /**
-     * Gets ports of the bridge.
+     * Gets ports of bridge.
      *
      * @return set of ports; empty if no ports is find
      */
@@ -247,7 +247,7 @@ public interface OvsdbClientService extends OvsdbRPC {
     DatabaseSchema getDatabaseSchema(String dbName);
 
     /**
-     * Gets the ovsdb row from the local ovsdb store.
+     * Gets the ovsdb row from local ovsdb store.
      *
      * @param dbName    database name
      * @param tableName table name
@@ -257,7 +257,7 @@ public interface OvsdbClientService extends OvsdbRPC {
     Row getRow(String dbName, String tableName, String uuid);
 
     /**
-     * Removes the ovsdb row from the local ovsdb store.
+     * Removes the ovsdb row from local ovsdb store.
      *
      * @param dbName    database name
      * @param tableName table name
index 24bfeae..f22a578 100644 (file)
@@ -21,7 +21,7 @@ import org.onlab.packet.TpPort;
 import java.util.List;
 
 /**
- * Abstraction of an ovsdb controller. Serves as a one stop shop for obtaining
+ * Abstraction of an ovsdb controller. Serves as an one stop shop for obtaining
  * OvsdbNode and (un)register listeners on ovsdb events and ovsdb node events.
  */
 public interface OvsdbController {
@@ -62,7 +62,7 @@ public interface OvsdbController {
     List<OvsdbNodeId> getNodeIds();
 
     /**
-     * Gets a ovsdb client by node identifier.
+     * Gets an ovsdb client by node identifier.
      *
      * @param nodeId node identifier
      * @return OvsdbClient ovsdb node information
index 1a2d836..8ccf45f 100644 (file)
@@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.Objects;
 
 /**
- * The class representing a datapathid. This class is immutable.
+ * The class representing a datapathid.
+ * This class is immutable.
  */
 public final class OvsdbDatapathId {
     private final String value;
 
     /**
-     * Constructor from a String datapathid.
+     * Constructor from a String.
      *
      * @param value the datapathid to use
      */
@@ -36,9 +37,9 @@ public final class OvsdbDatapathId {
     }
 
     /**
-     * Gets the value of the datapathid.
+     * Gets the value of datapathid.
      *
-     * @return the value of the datapathid
+     * @return the value of datapathid
      */
     public String value() {
         return value;
index 263027f..226a26e 100644 (file)
@@ -21,7 +21,7 @@ import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 
 /**
- * Represents for a entity that carry important information for listener.
+ * Represents for an entity that carry important information for listener.
  */
 public interface OvsdbEventSubject extends EventSubject {
     /**
index b0535d2..10ba80b 100644 (file)
@@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.Objects;
 
 /**
- * The class representing a ifaceid. This class is immutable.
+ * The class representing an ifaceid.
+ * This class is immutable.
  */
 public class OvsdbIfaceId {
     private final String value;
 
     /**
-     * Constructor from a String ifaceid.
+     * Constructor from a String.
      *
      * @param value the ifaceid to use
      */
@@ -36,9 +37,9 @@ public class OvsdbIfaceId {
     }
 
     /**
-     * Gets the value of the ifaceid.
+     * Gets the value of ifaceid.
      *
-     * @return the value of the ifaceid
+     * @return the value of ifaceid
      */
     public String value() {
         return value;
index 2c1a440..f3bba4b 100644 (file)
@@ -39,7 +39,7 @@ public final class OvsdbNodeId {
     public OvsdbNodeId(IpAddress ipAddress, long port) {
         checkNotNull(ipAddress, "ipAddress is not null");
         this.ipAddress = ipAddress.toString();
-        this.nodeId = ipAddress + ":" + port;
+        this.nodeId = ipAddress.toString();
     }
 
     @Override
index 3c04f6a..deea42d 100644 (file)
@@ -29,7 +29,7 @@ public final class OvsdbPort {
     private final OvsdbPortName portName;
 
     /**
-     * Constructor from a OvsdbPortNumber portNumber, OvsdbPortName portName.
+     * Constructor from  OvsdbPortNumber portNumber, OvsdbPortName portName.
      *
      * @param portNumber the portNumber to use
      * @param portName the portName to use
@@ -42,18 +42,18 @@ public final class OvsdbPort {
     }
 
     /**
-     * Gets the port number of the port.
+     * Gets the port number of port.
      *
-     * @return the port number of the port
+     * @return the port number of port
      */
     public OvsdbPortNumber portNumber() {
         return portNumber;
     }
 
     /**
-     * Gets the port name of the port.
+     * Gets the port name of port.
      *
-     * @return the port name of the port
+     * @return the port name of port
      */
     public OvsdbPortName portName() {
         return portName;
index aa0f55b..d9c7c2d 100644 (file)
@@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.Objects;
 
 /**
- * The class representing a port number. This class is immutable.
+ * The class representing a port number.
+ * This class is immutable.
  */
 public final class OvsdbPortName {
 
     private final String value;
 
     /**
-     * Constructor from a String port name.
+     * Constructor from a String.
      *
      * @param value the port name to use
      */
@@ -38,9 +39,9 @@ public final class OvsdbPortName {
     }
 
     /**
-     * Gets the value of the port name.
+     * Gets the value of port name.
      *
-     * @return the value of the port name
+     * @return the value of port name
      */
     public String value() {
         return value;
index 9c57b5d..bd094d0 100644 (file)
@@ -20,14 +20,15 @@ import static com.google.common.base.MoreObjects.toStringHelper;
 import java.util.Objects;
 
 /**
- * The class representing a port number. This class is immutable.
+ * The class representing a port number.
+ * This class is immutable.
  */
 public final class OvsdbPortNumber {
 
     private final long value;
 
     /**
-     * Constructor from a long port number.
+     * Constructor from a long value.
      *
      * @param value the port number to use
      */
@@ -36,9 +37,9 @@ public final class OvsdbPortNumber {
     }
 
     /**
-     * Gets the value of the port number.
+     * Gets the value of port number.
      *
-     * @return the value of the port number
+     * @return the value of port number
      */
     public long value() {
         return value;
index 1d9146e..72b64f3 100644 (file)
@@ -29,18 +29,18 @@ public class OvsdbTableStore {
     /**
      * Gets the ovsdbRowStore.
      *
-     * @param tableName a ovsdb table name
-     * @return OvsdbRowStore the data of the table
+     * @param tableName an ovsdb table name
+     * @return OvsdbRowStore the data of table
      */
     public OvsdbRowStore getRows(String tableName) {
         return tableStore.get(tableName);
     }
 
     /**
-     * Create or update a value to tableStore.
+     * Creates or updates a value to tableStore.
      *
-     * @param tableName key of the tableName
-     * @param rowStore a row of the table
+     * @param tableName key of tableName
+     * @param rowStore a row of table
      */
     public void createOrUpdateTable(String tableName, OvsdbRowStore rowStore) {
         tableStore.put(tableName, rowStore);
@@ -49,14 +49,14 @@ public class OvsdbTableStore {
     /**
      * Drops a value to table data.
      *
-     * @param tableName key of the tableName
+     * @param tableName key of tableName
      */
     public void dropTable(String tableName) {
         tableStore.remove(tableName);
     }
 
     /**
-     * Gets the tableStore.
+     * Gets tableStore.
      *
      * @return tableStore
      */
index e1c5c7f..8c857da 100644 (file)
@@ -23,7 +23,8 @@ import java.util.Objects;
 import org.onlab.packet.IpAddress;
 
 /**
- * The class representing a ovsdb tunnel. This class is immutable.
+ * The class representing an ovsdb tunnel.
+ * This class is immutable.
  */
 public final class OvsdbTunnel {
 
@@ -38,7 +39,7 @@ public final class OvsdbTunnel {
     private final OvsdbTunnelName tunnelName;
 
     /**
-     * Constructor from a IpAddress localIp, IpAddress remoteIp Type tunnelType,
+     * Constructor from an IpAddress localIp, IpAddress remoteIp Type tunnelType,
      * OvsdbTunnelName tunnelName.
      *
      * @param localIp the localIp to use
@@ -58,36 +59,36 @@ public final class OvsdbTunnel {
     }
 
     /**
-     * Gets the local IP of the tunnel.
+     * Gets the local IP of tunnel.
      *
-     * @return the local IP of the tunnel
+     * @return the local IP of tunnel
      */
     public IpAddress localIp() {
         return localIp;
     }
 
     /**
-     * Gets the remote IP of the tunnel.
+     * Gets the remote IP of tunnel.
      *
-     * @return the remote IP of the tunnel
+     * @return the remote IP of tunnel
      */
     public IpAddress remoteIp() {
         return remoteIp;
     }
 
     /**
-     * Gets the tunnel type of the tunnel.
+     * Gets the tunnel type of tunnel.
      *
-     * @return the tunnel type of the tunnel
+     * @return the tunnel type of tunnel
      */
     public Type tunnelType() {
         return tunnelType;
     }
 
     /**
-     * Gets the tunnel name of the tunnel.
+     * Gets the tunnel name of tunnel.
      *
-     * @return the tunnel name of the tunnel
+     * @return the tunnel name of tunnel
      */
     public OvsdbTunnelName tunnelName() {
         return tunnelName;
index 116f621..80befab 100644 (file)
@@ -21,13 +21,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.Objects;
 
 /**
- * The class representing a tunnel name. This class is immutable.
+ * The class representing a tunnel name.
+ * This class is immutable.
  */
 public final class OvsdbTunnelName {
     private final String value;
 
     /**
-     * Constructor from a String tunnel name.
+     * Constructor from a String.
      *
      * @param value the tunnel name to use
      */
@@ -37,9 +38,9 @@ public final class OvsdbTunnelName {
     }
 
     /**
-     * Gets the value of the tunnel name.
+     * Gets the value of tunnel name.
      *
-     * @return the value of the tunnel name
+     * @return the value of tunnel name
      */
     public String value() {
         return value;
index b9fdfe2..4686e3f 100644 (file)
@@ -58,6 +58,7 @@
 
         <module>tools/package/archetypes</module>
         <module>tools/package/branding</module>
+        <module>tools/build/conf</module>
         <module>bgp</module>
     </modules>
 
@@ -79,7 +80,7 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <onos-build-conf.version>1.0</onos-build-conf.version>
+        <onos-build-conf.version>1.1-SNAPSHOT</onos-build-conf.version>
         <netty4.version>4.0.23.Final</netty4.version>
         <copycat.version>0.5.0.onos</copycat.version>
         <openflowj.version>0.9.0.onos</openflowj.version>
index a840f85..9844203 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.Ethernet;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cluster.ClusterService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.mastership.MastershipEvent;
@@ -37,6 +38,7 @@ import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.LinkKey;
 import org.onosproject.net.Port;
+import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
@@ -60,6 +62,7 @@ import java.io.IOException;
 import java.util.Dictionary;
 import java.util.EnumSet;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ScheduledExecutorService;
@@ -86,6 +89,10 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
             "Settings: enabled={}, useBDDP={}, probeRate={}, " +
                     "staleLinkAge={}, lldpSuppression={}";
 
+    // When a Device/Port has this annotation, do not send out LLDP/BDDP
+    public static final String NO_LLDP = "no-lldp";
+
+
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -109,6 +116,12 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentConfigService cfgService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterService clusterService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry cfgRegistry;
+
     private LinkProviderService providerService;
 
     private ScheduledExecutorService executor;
@@ -207,7 +220,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
             newLldpSuppression = isNullOrEmpty(s) ? DEFAULT_LLDP_SUPPRESSION_CONFIG : s;
 
         } catch (NumberFormatException e) {
-            log.warn(e.getMessage());
+            log.warn("Component configuration had invalid values", e);
             newEnabled = enabled;
             newUseBddp = useBDDP;
             newProbeRate = probeRate;
@@ -227,6 +240,14 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
             enable();
         } else if (wasEnabled && !enabled) {
             disable();
+        } else {
+            // reflect changes in suppression rules to discovery helpers
+            // FIXME: After migrating to Network Configuration Subsystem,
+            //        it should be possible to update only changed subset
+            if (enabled) {
+                // update all discovery helper state
+                loadDevices();
+            }
         }
 
         log.info(FORMAT, enabled, useBDDP, probeRate, staleLinkAge, lldpSuppression);
@@ -277,31 +298,96 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
      * Loads available devices and registers their ports to be probed.
      */
     private void loadDevices() {
-        for (Device device : deviceService.getAvailableDevices()) {
-            if (rules.isSuppressed(device)) {
-                log.debug("LinkDiscovery from {} disabled by configuration", device.id());
-                continue;
-            }
-            LinkDiscovery ld = new LinkDiscovery(device, context);
-            discoverers.put(device.id(), ld);
-            addPorts(ld, device.id());
+        deviceService.getAvailableDevices()
+                .forEach(d -> updateDevice(d)
+                               .ifPresent(ld -> updatePorts(ld, d.id())));
+    }
+
+    /**
+     * Updates discovery helper for specified device.
+     *
+     * Adds and starts a discovery helper for specified device if enabled,
+     * calls {@link #removeDevice(DeviceId)} otherwise.
+     *
+     * @param device device to add
+     * @return discovery helper if discovery is enabled for the device
+     */
+    private Optional<LinkDiscovery> updateDevice(Device device) {
+        if (rules.isSuppressed(device)) {
+            log.trace("LinkDiscovery from {} disabled by configuration", device.id());
+            removeDevice(device.id());
+            return Optional.empty();
+        }
+        LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
+                                     did -> new LinkDiscovery(device, context));
+        if (ld.isStopped()) {
+            ld.start();
         }
+        return Optional.of(ld);
     }
 
     /**
-     * Adds ports of the specified device to the specified discovery helper.
+     * Removes after stopping discovery helper for specified device.
+     * @param deviceId device to remove
      */
-    private void addPorts(LinkDiscovery discoverer, DeviceId deviceId) {
-        for (Port p : deviceService.getPorts(deviceId)) {
-            if (rules.isSuppressed(p)) {
-                continue;
-            }
-            if (!p.number().isLogical()) {
-                discoverer.addPort(p);
-            }
+    private void removeDevice(final DeviceId deviceId) {
+        discoverers.computeIfPresent(deviceId, (did, ld) -> {
+            ld.stop();
+            providerService.linksVanished(deviceId);
+            return null;
+        });
+
+    }
+
+    /**
+     * Updates ports of the specified device to the specified discovery helper.
+     */
+    private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
+        deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
+    }
+
+    /**
+     * Updates discovery helper state of the specified port.
+     *
+     * Adds a port to the discovery helper if up and discovery is enabled,
+     * or calls {@link #removePort(Port)} otherwise.
+     */
+    private void updatePort(LinkDiscovery discoverer, Port port) {
+        if (rules.isSuppressed(port)) {
+            log.trace("LinkDiscovery from {} disabled by configuration", port);
+            removePort(port);
+            return;
+        }
+
+        // check if enabled and turn off discovery?
+        if (!port.isEnabled()) {
+            removePort(port);
+            return;
+        }
+
+        if (!port.number().isLogical()) {
+            discoverer.addPort(port);
         }
     }
 
+    /**
+     * Removes a port from the specified discovery helper.
+     * @param port the port
+     */
+    private void removePort(Port port) {
+        if (port.element() instanceof Device) {
+            Device d = (Device) port.element();
+            LinkDiscovery ld = discoverers.get(d.id());
+            if (ld != null) {
+                ld.removePort(port.number());
+            }
+
+            ConnectPoint point = new ConnectPoint(d.id(), port.number());
+            providerService.linksVanished(point);
+        } else {
+            log.warn("Attempted to remove non-Device port", port);
+        }
+    }
 
     /**
      * Loads LLDP suppression rules.
@@ -317,7 +403,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
             // default rule to suppress ROADM to maintain compatibility
             rules = new SuppressionRules(ImmutableSet.of(),
                                          EnumSet.of(Device.Type.ROADM),
-                                         ImmutableMap.of());
+                                         ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
         }
 
         // should refresh discoverers when we need dynamic reconfiguration
@@ -367,10 +453,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
                 log.debug("Device {} doesn't exist, or isn't there yet", deviceId);
                 return;
             }
-            if (rules.isSuppressed(device)) {
-                return;
+            if (clusterService.getLocalNode().id().equals(event.roleInfo().master())) {
+                updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id()));
             }
-            discoverers.computeIfAbsent(deviceId, k -> new LinkDiscovery(device, context));
         }
 
     }
@@ -381,7 +466,6 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
     private class InternalDeviceListener implements DeviceListener {
         @Override
         public void event(DeviceEvent event) {
-            LinkDiscovery ld;
             Device device = event.subject();
             Port port = event.port();
             if (device == null) {
@@ -393,73 +477,33 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
             switch (event.type()) {
                 case DEVICE_ADDED:
                 case DEVICE_UPDATED:
-                    synchronized (discoverers) {
-                        ld = discoverers.get(deviceId);
-                        if (ld == null) {
-                            if (rules != null && rules.isSuppressed(device)) {
-                                log.debug("LinkDiscovery from {} disabled by configuration", device.id());
-                                return;
-                            }
-                            log.debug("Device added ({}) {}", event.type(), deviceId);
-                            discoverers.put(deviceId, new LinkDiscovery(device, context));
-                        } else {
-                            if (ld.isStopped()) {
-                                log.debug("Device restarted ({}) {}", event.type(), deviceId);
-                                ld.start();
-                            }
-                        }
-                    }
+                    updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
                     break;
                 case PORT_ADDED:
                 case PORT_UPDATED:
                     if (port.isEnabled()) {
-                        ld = discoverers.get(deviceId);
-                        if (ld == null) {
-                            return;
-                        }
-                        if (rules.isSuppressed(port)) {
-                            log.debug("LinkDiscovery from {}@{} disabled by configuration",
-                                      port.number(), device.id());
-                            return;
-                        }
-                        if (!port.number().isLogical()) {
-                            log.debug("Port added {}", port);
-                            ld.addPort(port);
-                        }
+                        updateDevice(device).ifPresent(ld -> updatePort(ld, port));
                     } else {
                         log.debug("Port down {}", port);
-                        ConnectPoint point = new ConnectPoint(deviceId, port.number());
-                        providerService.linksVanished(point);
+                        removePort(port);
                     }
                     break;
                 case PORT_REMOVED:
                     log.debug("Port removed {}", port);
-                    ConnectPoint point = new ConnectPoint(deviceId, port.number());
-                    providerService.linksVanished(point);
-
+                    removePort(port);
                     break;
                 case DEVICE_REMOVED:
                 case DEVICE_SUSPENDED:
                     log.debug("Device removed {}", deviceId);
-                    ld = discoverers.get(deviceId);
-                    if (ld == null) {
-                        return;
-                    }
-                    ld.stop();
-                    providerService.linksVanished(deviceId);
+                    removeDevice(deviceId);
                     break;
                 case DEVICE_AVAILABILITY_CHANGED:
-                    ld = discoverers.get(deviceId);
-                    if (ld == null) {
-                        return;
-                    }
                     if (deviceService.isAvailable(deviceId)) {
                         log.debug("Device up {}", deviceId);
-                        ld.start();
+                        updateDevice(device);
                     } else {
-                        providerService.linksVanished(deviceId);
                         log.debug("Device down {}", deviceId);
-                        ld.stop();
+                        removeDevice(deviceId);
                     }
                     break;
                 case PORT_STATS_UPDATED:
@@ -508,17 +552,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
             }
             // check what deviceService sees, to see if we are missing anything
             try {
-                for (Device dev : deviceService.getDevices()) {
-                    if (rules.isSuppressed(dev)) {
-                        continue;
-                    }
-                    DeviceId did = dev.id();
-                    synchronized (discoverers) {
-                        LinkDiscovery ld = discoverers
-                                .computeIfAbsent(did, k -> new LinkDiscovery(dev, context));
-                        addPorts(ld, did);
-                    }
-                }
+                loadDevices();
             } catch (Exception e) {
                 // Catch all exceptions to avoid task being suppressed
                 log.error("Exception thrown during synchronization process", e);
index 8cdfd50..7dc9aed 100644 (file)
@@ -61,7 +61,7 @@ class LinkDiscovery implements TimerTask {
 
     private final ONOSLLDP lldpPacket;
     private final Ethernet ethPacket;
-    private Ethernet bddpEth;
+    private final Ethernet bddpEth;
 
     private Timeout timeout;
     private volatile boolean isStopped;
@@ -126,7 +126,7 @@ class LinkDiscovery implements TimerTask {
     }
 
     /**
-     * Add physical port port to discovery process.
+     * Add physical port to discovery process.
      * Send out initial LLDP and label it as slow port.
      *
      * @param port the port
@@ -140,6 +140,14 @@ class LinkDiscovery implements TimerTask {
         }
     }
 
+    /**
+     * removed physical port from discovery process.
+     * @param port the port number
+     */
+    void removePort(PortNumber port) {
+        ports.remove(port.toLong());
+    }
+
     /**
      * Handles an incoming LLDP packet. Creates link in topology and adds the
      * link for staleness tracking.
index b4b7b7b..6070b85 100644 (file)
@@ -16,6 +16,7 @@
 package org.onosproject.provider.lldp.impl;
 
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.junit.After;
@@ -32,7 +33,9 @@ import org.onosproject.core.CoreService;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Annotations;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.DefaultPort;
 import org.onosproject.net.Device;
@@ -73,6 +76,7 @@ public class LLDPLinkProviderTest {
 
     private static final DeviceId DID1 = DeviceId.deviceId("of:0000000000000001");
     private static final DeviceId DID2 = DeviceId.deviceId("of:0000000000000002");
+    private static final DeviceId DID3 = DeviceId.deviceId("of:0000000000000003");
 
     private static Port pd1;
     private static Port pd2;
@@ -133,10 +137,35 @@ public class LLDPLinkProviderTest {
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_REMOVED, DID1));
 
-        assertTrue("Discoverer is not gone", provider.discoverers.get(DID1).isStopped());
+        final LinkDiscovery linkDiscovery = provider.discoverers.get(DID1);
+        if (linkDiscovery != null) {
+            // If LinkDiscovery helper is there after DEVICE_REMOVED,
+            // it should be stopped
+            assertTrue("Discoverer is not stopped", linkDiscovery.isStopped());
+        }
         assertTrue("Device is not gone.", vanishedDpid(DID1));
     }
 
+    /**
+     * Checks that links on a reconfigured switch are properly removed.
+     */
+    @Test
+    public void switchSuppressed() {
+        // add device to stub DeviceService
+        deviceService.putDevice(device(DID3));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
+
+        assertFalse("Device not added", provider.discoverers.isEmpty());
+
+        // update device in stub DeviceService with suppression config
+        deviceService.putDevice(device(DID3, DefaultAnnotations.builder()
+                                              .set(LLDPLinkProvider.NO_LLDP, "true")
+                                              .build()));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
+
+        assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3));
+    }
+
     @Test
     public void portUp() {
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
@@ -152,27 +181,101 @@ public class LLDPLinkProviderTest {
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
         deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 1, false)));
 
-
-
         assertFalse("Port added to discoverer",
                     provider.discoverers.get(DID1).containsPort(1L));
         assertTrue("Port is not gone.", vanishedPort(1L));
     }
 
+    @Test
+    public void portRemoved() {
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true)));
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_REMOVED, DID1, port(DID1, 3, true)));
+
+        assertTrue("Port is not gone.", vanishedPort(3L));
+        assertFalse("Port was not removed from discoverer",
+                   provider.discoverers.get(DID1).containsPort(3L));
+    }
+
+    /**
+     * Checks that discovery on reconfigured switch are properly restarted.
+     */
+    @Test
+    public void portSuppressedByDeviceConfig() {
+
+        /// When Device is configured with suppression:ON, Port also is same
+
+        // add device in stub DeviceService with suppression configured
+        deviceService.putDevice(device(DID3, DefaultAnnotations.builder()
+                                              .set(LLDPLinkProvider.NO_LLDP, "true")
+                                              .build()));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
+
+        // non-suppressed port added to suppressed device
+        final long portno3 = 3L;
+        deviceService.putPorts(DID3, port(DID3, portno3, true));
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true)));
+
+        // discovery on device is expected to be stopped
+        LinkDiscovery linkDiscovery = provider.discoverers.get(DID3);
+        if (linkDiscovery != null) {
+            assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
+        }
+
+        /// When Device is reconfigured without suppression:OFF,
+        /// Port should be included for discovery
+
+        // update device in stub DeviceService without suppression configured
+        deviceService.putDevice(device(DID3));
+        // update the Port in stub DeviceService. (Port has reference to Device)
+        deviceService.putPorts(DID3, port(DID3, portno3, true));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
+
+        // discovery should come back on
+        assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped());
+        assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3));
+    }
+
+    /**
+     * Checks that discovery on reconfigured port are properly restarted.
+     */
+    @Test
+    public void portSuppressedByPortConfig() {
+        // add device in stub DeviceService without suppression configured
+        deviceService.putDevice(device(DID3));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
+
+        // suppressed port added to non-suppressed device
+        final long portno3 = 3L;
+        final Port port3 = port(DID3, portno3, true,
+                                          DefaultAnnotations.builder()
+                                          .set(LLDPLinkProvider.NO_LLDP, "true")
+                                          .build());
+        deviceService.putPorts(DID3, port3);
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port3));
+
+        // discovery helper should be there turned on
+        assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped());
+        assertFalse("Discoverer should not contain the port there",
+                    provider.discoverers.get(DID3).containsPort(portno3));
+    }
+
     @Test
     public void portUnknown() {
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
-        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID2, port(DID2, 1, false)));
+        // Note: DID3 hasn't been added to TestDeviceService, but only port is added
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, 1, false)));
 
 
         assertNull("DeviceId exists",
-                   provider.discoverers.get(DID2));
+                   provider.discoverers.get(DID3));
     }
 
     @Test
     public void unknownPktCtx() {
 
-        PacketContext pktCtx = new TestPacketContext(deviceService.getDevice(DID2));
+        // Note: DID3 hasn't been added to TestDeviceService
+        PacketContext pktCtx = new TestPacketContext(device(DID3));
 
         testProcessor.process(pktCtx);
         assertFalse("Context should still be free", pktCtx.isHandled());
@@ -206,6 +309,16 @@ public class LLDPLinkProviderTest {
 
     }
 
+    private DefaultDevice device(DeviceId did) {
+        return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
+                             "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
+    }
+
+    private DefaultDevice device(DeviceId did, Annotations annotations) {
+        return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
+                             "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations);
+    }
+
     @SuppressWarnings(value = { "unused" })
     private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, PortNumber port) {
         return new  DeviceEvent(type, deviceService.getDevice(did),
@@ -221,6 +334,10 @@ public class LLDPLinkProviderTest {
                                PortNumber.portNumber(port), enabled);
     }
 
+    private Port port(DeviceId did, long port, boolean enabled, Annotations annotations) {
+        return new DefaultPort(deviceService.getDevice(did),
+                               PortNumber.portNumber(port), enabled, annotations);
+    }
 
     private boolean vanishedDpid(DeviceId... dids) {
         for (int i = 0; i < dids.length; i++) {
@@ -384,10 +501,9 @@ public class LLDPLinkProviderTest {
 
     private class TestDeviceService extends DeviceServiceAdapter {
 
-        private Map<DeviceId, Device> devices = new HashMap<>();
+        private final Map<DeviceId, Device> devices = new HashMap<>();
         private final ArrayListMultimap<DeviceId, Port> ports =
                 ArrayListMultimap.create();
-
         public TestDeviceService() {
             Device d1 = new DefaultDevice(ProviderId.NONE, DID1, Device.Type.SWITCH,
                                           "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
@@ -395,7 +511,6 @@ public class LLDPLinkProviderTest {
                                           "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
             devices.put(DID1, d1);
             devices.put(DID2, d2);
-
             pd1 = new DefaultPort(d1, PortNumber.portNumber(1), true);
             pd2 = new DefaultPort(d1, PortNumber.portNumber(2), true);
             pd3 = new DefaultPort(d2, PortNumber.portNumber(1), true);
@@ -405,6 +520,15 @@ public class LLDPLinkProviderTest {
             ports.putAll(DID2, Lists.newArrayList(pd3, pd4));
         }
 
+        private void putDevice(Device device) {
+            DeviceId deviceId = device.id();
+            devices.put(deviceId, device);
+        }
+
+        private void putPorts(DeviceId did, Port...ports) {
+            this.ports.putAll(did, Lists.newArrayList(ports));
+        }
+
         @Override
         public int getDeviceCount() {
             return devices.values().size();
@@ -412,7 +536,7 @@ public class LLDPLinkProviderTest {
 
         @Override
         public Iterable<Device> getDevices() {
-            return Collections.emptyList();
+            return ImmutableList.copyOf(devices.values());
         }
 
         @Override
index 1039d04..4d5b6b2 100644 (file)
  */
 package org.onosproject.provider.of.flow.impl;
 
-import static org.onosproject.net.flow.criteria.Criteria.matchLambda;
-import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType;
-import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing;
-import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType;
-import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.List;
-
+import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
@@ -36,6 +28,11 @@ import org.onosproject.core.DefaultGroupId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.DefaultFlowEntry;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -47,6 +44,7 @@ import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.ExtensionInterpreter;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
@@ -55,13 +53,13 @@ import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
 import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter;
 import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue;
 import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
@@ -75,7 +73,6 @@ import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
 import org.projectfloodlight.openflow.protocol.ver13.OFFactoryVer13;
 import org.projectfloodlight.openflow.types.CircuitSignalID;
-import org.projectfloodlight.openflow.types.EthType;
 import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IPv6Address;
 import org.projectfloodlight.openflow.types.Masked;
@@ -87,7 +84,14 @@ import org.projectfloodlight.openflow.types.U8;
 import org.projectfloodlight.openflow.types.VlanPcp;
 import org.slf4j.Logger;
 
-import com.google.common.collect.Lists;
+import java.util.List;
+
+import static org.onosproject.net.flow.criteria.Criteria.matchLambda;
+import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType;
+import static org.slf4j.LoggerFactory.getLogger;
 
 public class FlowEntryBuilder {
     private final Logger log = getLogger(getClass());
@@ -108,7 +112,9 @@ public class FlowEntryBuilder {
 
     private final FlowType type;
 
-    public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) {
+    private final DriverService driverService;
+
+    public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry, DriverService driverService) {
         this.stat = entry;
         this.match = entry.getMatch();
         this.instructions = getInstructions(entry);
@@ -116,9 +122,10 @@ public class FlowEntryBuilder {
         this.removed = null;
         this.flowMod = null;
         this.type = FlowType.STAT;
+        this.driverService = driverService;
     }
 
-    public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) {
+    public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed, DriverService driverService) {
         this.match = removed.getMatch();
         this.removed = removed;
 
@@ -127,10 +134,10 @@ public class FlowEntryBuilder {
         this.stat = null;
         this.flowMod = null;
         this.type = FlowType.REMOVED;
-
+        this.driverService = driverService;
     }
 
-    public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) {
+    public FlowEntryBuilder(Dpid dpid, OFFlowMod fm, DriverService driverService) {
         this.match = fm.getMatch();
         this.dpid = dpid;
         this.instructions = getInstructions(fm);
@@ -138,6 +145,7 @@ public class FlowEntryBuilder {
         this.flowMod = fm;
         this.stat = null;
         this.removed = null;
+        this.driverService = driverService;
     }
 
     public FlowEntry build(FlowEntryState... state) {
@@ -309,7 +317,7 @@ public class FlowEntryBuilder {
                     break;
                 case SET_FIELD:
                     OFActionSetField setField = (OFActionSetField) act;
-                    handleSetField(builder, setField.getField());
+                    handleSetField(builder, setField);
                     break;
                 case POP_MPLS:
                     OFActionPopMpls popMpls = (OFActionPopMpls) act;
@@ -365,7 +373,8 @@ public class FlowEntryBuilder {
     }
 
 
-    private void handleSetField(TrafficTreatment.Builder builder, OFOxm<?> oxm) {
+    private void handleSetField(TrafficTreatment.Builder builder, OFActionSetField action) {
+        OFOxm<?> oxm = action.getField();
         switch (oxm.getMatchField().id) {
         case VLAN_PCP:
             @SuppressWarnings("unchecked")
@@ -434,6 +443,13 @@ public class FlowEntryBuilder {
             OFOxm<TransportPort> udpsrc = (OFOxm<TransportPort>) oxm;
             builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort()));
             break;
+        case TUNNEL_IPV4_DST:
+            DriverHandler driver = getDriver(dpid);
+            ExtensionInterpreter interpreter = driver.behaviour(ExtensionInterpreter.class);
+            if (interpreter != null) {
+                builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid)));
+            }
+            break;
         case ARP_OP:
         case ARP_SHA:
         case ARP_SPA:
@@ -520,11 +536,7 @@ public class FlowEntryBuilder {
                 break;
             case ETH_TYPE:
                 int ethType = match.get(MatchField.ETH_TYPE).getValue();
-                if (ethType == EthType.VLAN_FRAME.getValue()) {
-                    builder.matchVlanId(VlanId.ANY);
-                } else {
-                    builder.matchEthType((short) ethType);
-                }
+                builder.matchEthType((short) ethType);
                 break;
             case VLAN_VID:
                 VlanId vlanId = null;
@@ -703,4 +715,11 @@ public class FlowEntryBuilder {
         }
         return builder.build();
     }
+
+    private DriverHandler getDriver(Dpid dpid) {
+        DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
+        Driver driver = driverService.getDriver(deviceId);
+        DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
+        return handler;
+    }
 }
index e050524..7eca492 100644 (file)
  */
 package org.onosproject.provider.of.flow.impl;
 
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Optional;
-
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.Ip6Prefix;
 import org.onlab.packet.VlanId;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -85,6 +82,10 @@ import org.projectfloodlight.openflow.types.VlanPcp;
 import org.projectfloodlight.openflow.types.VlanVid;
 import org.slf4j.Logger;
 
+import java.util.Optional;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Builder for OpenFlow flow mods based on FlowRules.
  */
@@ -96,6 +97,7 @@ public abstract class FlowModBuilder {
     private final FlowRule flowRule;
     private final TrafficSelector selector;
     protected final Long xid;
+    protected final Optional<DriverService> driverService;
 
     /**
      * Creates a new flow mod builder.
@@ -107,12 +109,13 @@ public abstract class FlowModBuilder {
      */
     public static FlowModBuilder builder(FlowRule flowRule,
                                          OFFactory factory,
-                                         Optional<Long> xid) {
+                                         Optional<Long> xid,
+                                         Optional<DriverService> driverService) {
         switch (factory.getVersion()) {
         case OF_10:
-            return new FlowModBuilderVer10(flowRule, factory, xid);
+            return new FlowModBuilderVer10(flowRule, factory, xid, driverService);
         case OF_13:
-            return new FlowModBuilderVer13(flowRule, factory, xid);
+            return new FlowModBuilderVer13(flowRule, factory, xid, driverService);
         default:
             throw new UnsupportedOperationException(
                     "No flow mod builder for protocol version " + factory.getVersion());
@@ -126,12 +129,13 @@ public abstract class FlowModBuilder {
      * @param factory the OpenFlow factory to use to build the flow mod
      * @param xid the transaction ID
      */
-    protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
+    protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid,
+                             Optional<DriverService> driverService) {
         this.factory = factory;
         this.flowRule = flowRule;
         this.selector = flowRule.selector();
         this.xid = xid.orElse(0L);
-
+        this.driverService = driverService;
     }
 
     /**
index f77819d..c789841 100644 (file)
@@ -17,6 +17,7 @@ package org.onosproject.provider.of.flow.impl;
 
 import org.onlab.packet.Ip4Address;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instruction;
@@ -68,8 +69,9 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
      * @param xid the transaction ID
      */
     protected FlowModBuilderVer10(FlowRule flowRule,
-                                  OFFactory factory, Optional<Long> xid) {
-        super(flowRule, factory, xid);
+                                  OFFactory factory, Optional<Long> xid,
+                                  Optional<DriverService> driverService) {
+        super(flowRule, factory, xid, driverService);
 
         this.treatment = flowRule.treatment();
     }
index 64b4360..a99aa81 100644 (file)
@@ -18,10 +18,16 @@ package org.onosproject.provider.of.flow.impl;
 import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip6Address;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
@@ -34,15 +40,16 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
+import org.onosproject.openflow.controller.ExtensionInterpreter;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
 import org.projectfloodlight.openflow.protocol.OFFlowDelete;
@@ -88,6 +95,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
     private static final int OFPCML_NO_BUFFER = 0xffff;
 
     private final TrafficTreatment treatment;
+    private final DeviceId deviceId;
 
     /**
      * Constructor for a flow mod builder for OpenFlow 1.3.
@@ -96,10 +104,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
      * @param factory the OpenFlow factory to use to build the flow mod
      * @param xid the transaction ID
      */
-    protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
-        super(flowRule, factory, xid);
+    protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid,
+                                  Optional<DriverService> driverService) {
+        super(flowRule, factory, xid, driverService);
 
         this.treatment = flowRule.treatment();
+        this.deviceId = flowRule.deviceId();
     }
 
     @Override
@@ -256,6 +266,10 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
                     //FIXME: should not occur here.
                     tableFound = true;
                     break;
+                case EXTENSION:
+                    actions.add(buildExtensionAction(((Instructions.ExtensionInstructionWrapper) i)
+                            .extensionInstruction()));
+                    break;
                 default:
                     log.warn("Instruction type {} not yet implemented.", i.type());
             }
@@ -467,4 +481,20 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
         return null;
     }
 
+    private OFAction buildExtensionAction(ExtensionInstruction i) {
+        if (!driverService.isPresent()) {
+            log.error("No driver service present");
+            return null;
+        }
+        Driver driver = driverService.get().getDriver(deviceId);
+        if (driver.hasBehaviour(ExtensionInterpreter.class)) {
+            DefaultDriverHandler handler =
+                    new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
+            ExtensionInterpreter interpreter = handler.behaviour(ExtensionInterpreter.class);
+            return interpreter.mapInstruction(factory(), i);
+        }
+
+        return null;
+    }
+
 }
index 487cae9..d5186fa 100644 (file)
 \r
 package org.onosproject.provider.of.flow.impl;\r
 \r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Optional;\r
-import java.util.Set;\r
-import java.util.concurrent.TimeUnit;\r
-import java.util.concurrent.ScheduledFuture;\r
-import java.util.concurrent.Executors;\r
-import java.util.concurrent.ScheduledExecutorService;\r
-\r
 import com.google.common.base.Objects;\r
 import com.google.common.collect.ImmutableSet;\r
 import com.google.common.collect.Maps;\r
 import com.google.common.collect.Sets;\r
-\r
 import org.onosproject.net.flow.DefaultTypedFlowEntry;\r
 import org.onosproject.net.flow.FlowEntry;\r
 import org.onosproject.net.flow.FlowId;\r
@@ -47,9 +36,19 @@ import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.TableId;\r
 import org.slf4j.Logger;\r
 \r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Optional;\r
+import java.util.Set;\r
+import java.util.concurrent.Executors;\r
+import java.util.concurrent.ScheduledExecutorService;\r
+import java.util.concurrent.ScheduledFuture;\r
+import java.util.concurrent.TimeUnit;\r
+\r
 import static com.google.common.base.Preconditions.checkNotNull;\r
 import static org.onlab.util.Tools.groupedThreads;\r
-import static org.onosproject.net.flow.TypedStoredFlowEntry.*;\r
+import static org.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType;\r
 import static org.slf4j.LoggerFactory.getLogger;\r
 \r
 /**\r
@@ -232,7 +231,8 @@ public class NewAdaptiveFlowStatsCollector {
     // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw\r
     private void ofFlowStatsRequestFlowSend(FlowEntry fe) {\r
         // set find match\r
-        Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty()).buildMatch();\r
+        Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(),\r
+                Optional.empty()).buildMatch();\r
         // set find tableId\r
         TableId tableId = TableId.of(fe.tableId());\r
         // set output port\r
index 6374ca5..b37cb42 100644 (file)
@@ -21,7 +21,6 @@ import com.google.common.cache.RemovalCause;
 import com.google.common.cache.RemovalNotification;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -32,6 +31,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultTableStatisticsEntry;
 import org.onosproject.net.flow.FlowEntry;
@@ -61,12 +61,12 @@ import org.projectfloodlight.openflow.protocol.OFErrorType;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
-import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
-import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
 import org.slf4j.Logger;
@@ -106,6 +106,9 @@ public class OpenFlowRuleProvider extends AbstractProvider
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentConfigService cfgService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DriverService driverService;
+
     private static final int DEFAULT_POLL_FREQUENCY = 5;
     @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
             label = "Frequency (in seconds) for polling flow statistics")
@@ -269,7 +272,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
             return;
         }
         sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
-                                          Optional.empty()).buildFlowAdd());
+                Optional.empty(), Optional.of(driverService)).buildFlowAdd());
 
         if (adaptiveFlowSampling) {
             // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
@@ -298,7 +301,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
             return;
         }
         sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
-                                          Optional.empty()).buildFlowDel());
+                                          Optional.empty(), Optional.of(driverService)).buildFlowDel());
 
         if (adaptiveFlowSampling) {
             // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
@@ -334,7 +337,8 @@ public class OpenFlowRuleProvider extends AbstractProvider
                 continue;
             }
             FlowModBuilder builder =
-                    FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id()));
+                    FlowModBuilder.builder(fbe.target(), sw.factory(),
+                            Optional.of(batch.id()), Optional.of(driverService));
             NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
             switch (fbe.operator()) {
                 case ADD:
@@ -423,7 +427,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
                 case FLOW_REMOVED:
                     OFFlowRemoved removed = (OFFlowRemoved) msg;
 
-                    FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
+                    FlowEntry fr = new FlowEntryBuilder(dpid, removed, driverService).build();
                     providerService.flowRemoved(fr);
 
                     if (adaptiveFlowSampling) {
@@ -474,7 +478,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
                             InternalCacheEntry entry =
                                     pendingBatches.getIfPresent(msg.getXid());
                             if (entry != null) {
-                                entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
+                                entry.appendFailure(new FlowEntryBuilder(dpid, fm, driverService).build());
                             } else {
                                 log.error("No matching batch for this error: {}", error);
                             }
@@ -501,7 +505,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
             DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
 
             List<FlowEntry> flowEntries = replies.getEntries().stream()
-                    .map(entry -> new FlowEntryBuilder(dpid, entry).build())
+                    .map(entry -> new FlowEntryBuilder(dpid, entry, driverService).build())
                     .collect(Collectors.toList());
 
             if (adaptiveFlowSampling)  {
index b9de7c0..d3a2378 100644 (file)
@@ -115,6 +115,10 @@ public class GroupBucketEntryBuilder {
                             DefaultGroupBucket.createFailoverGroupBucket(treatment,
                                     port, groupId);
                     break;
+                case ALL:
+                    groupBucket =
+                            DefaultGroupBucket.createAllGroupBucket(treatment);
+                    break;
                 default:
                     log.error("Unsupported Group type : {}", type);
             }
index 8acf08e..5783c84 100644 (file)
@@ -252,7 +252,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
     private GroupDescription.Type getGroupType(OFGroupType type) {
         switch (type) {
             case ALL:
-                return  GroupDescription.Type.ALL;
+                return GroupDescription.Type.ALL;
             case INDIRECT:
                 return GroupDescription.Type.INDIRECT;
             case SELECT:
index 0e3e156..031fda7 100644 (file)
@@ -111,7 +111,7 @@ public class OvsdbHostProvider extends AbstractProvider implements HostProvider
             }
             switch (event.type()) {
             case PORT_ADDED:
-                HostId hostId = HostId.hostId(subject.hwAddress(), null);
+                HostId hostId = HostId.hostId(subject.hwAddress(), VlanId.vlanId());
                 DeviceId deviceId = DeviceId.deviceId(uri(subject.dpid().value()));
                 PortNumber portNumber = PortNumber.portNumber(subject
                         .portNumber().value(), subject.portName().value());
@@ -127,7 +127,7 @@ public class OvsdbHostProvider extends AbstractProvider implements HostProvider
                 providerService.hostDetected(hostId, hostDescription);
                 break;
             case PORT_REMOVED:
-                HostId host = HostId.hostId(subject.hwAddress(), null);
+                HostId host = HostId.hostId(subject.hwAddress(), VlanId.vlanId());
                 providerService.hostVanished(host);
                 break;
             default:
index 29e4dea..d56168f 100644 (file)
@@ -27,7 +27,7 @@
 
     <groupId>org.onosproject</groupId>
     <artifactId>onos-build-conf</artifactId>
-    <version>1.1</version>
+    <version>1.1-SNAPSHOT</version>
     <description>Various ONOS build settings</description>
 
     <properties>
index 1bb3b0b..e04479c 100644 (file)
@@ -67,9 +67,7 @@
     -->
     <!-- Checks that a package-info.java file exists for each package.     -->
     <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->
-    <!-- ONOS does not currently supply package level Javadoc information
-         in package-info files -->
-    <!-- <module name="JavadocPackage"/> -->
+    <module name="JavadocPackage"/>
 
     <!-- Checks whether files end with a new line.                        -->
     <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
index a71d941..6d8f198 100644 (file)
     <suppress files=".*" checks="HiddenField"/>
     <suppress files=".java" checks="NewlineAtEndOfFile"/>
 
+    <!-- Suppressions for unit testing code -->
+    <suppress checks="JavadocPackage"
+              files=".*/src/test/.*.java"
+            />
+
+    <suppress checks="JavadocPackage"
+              files=".*/thirdparty/.*.java"/>
+
 </suppressions>
index ac2dec8..351c53a 100755 (executable)
@@ -15,9 +15,11 @@ if [ -n "$projects" ]; then
     # Ascertain artifact IDs of the projects to be rebuilt
     modulesERE=""
     for pd in ${projects//,/ }; do
-        artifactId=$(grep -E "^    <artifactId>.*</artifactId>$" ${pd}/pom.xml | \
-                        sed 's/.[^>]*>//;s/<.*//')
-        modulesERE="$modulesERE|$artifactId"
+        if [ -f ${pd}/pom.xml ]; then
+            artifactId=$(grep -E "^    <artifactId>.*</artifactId>$" ${pd}/pom.xml | \
+                            sed 's/.[^>]*>//;s/<.*//')
+            modulesERE="$modulesERE|$artifactId"
+        fi
     done
     modulesERE=${modulesERE#|*}
 
index 1265494..487f848 100644 (file)
@@ -6,4 +6,5 @@
 .*/cord-gui/.*
 .*/jdvue/.*
 .*/ovsdb/api/.*
-.*/netconf/flow/.*
\ No newline at end of file
+.*/netconf/flow/.*
+.*/vtn/sfcmgr/.*
\ No newline at end of file
index 3323d9d..cbe6225 100755 (executable)
@@ -97,13 +97,11 @@ fi
 echo "Creating local cluster configs for IP $IP..."
 [ -d $STAGE/config ] || mkdir -p $STAGE/config
 cat > $STAGE/config/cluster.json <<EOF
-    { "ipPrefix": "$SUBNET.*",
-      "nodes":[ { "id": "$IP", "ip": "$IP", "tcpPort": 9876 }]}
-EOF
-
-cat > $STAGE/config/tablets.json <<EOF
-    { "nodes": [ { "ip": "$IP", "id": "$IP", "tcpPort": 9876 }],
-      "partitions": { "p1": [ { "ip": "$IP", "id": "$IP", "tcpPort": 9876 }]}}
+{
+  "name": "default",
+  "nodes": [ {"id": "$IP", "ip": "$IP", "port": 9876 } ],
+  "partitions": [ { "name": "p1", "members": [ "$IP" ] } ]
+}
 EOF
 
 if [ "$CLEAN" = "true" ]; then
index 7c35cc5..65e3489 100644 (file)
@@ -33,7 +33,10 @@ import org.onosproject.net.link.LinkService;
 import org.onosproject.ui.RequestHandler;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.topo.DeviceHighlight;
 import org.onosproject.ui.topo.Highlights;
+import org.onosproject.ui.topo.NodeBadge;
+import org.onosproject.ui.topo.NodeBadge.Status;
 import org.onosproject.ui.topo.TopoJson;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -224,11 +227,26 @@ public class AppUiTopovMessageHandler extends UiMessageHandler {
         if (elementOfNote != null && elementOfNote instanceof Device) {
             DeviceId devId = (DeviceId) elementOfNote.id();
             Set<Link> links = linkService.getDeviceEgressLinks(devId);
-            sendHighlights(fromLinks(links, devId));
+            Highlights highlights = fromLinks(links, devId);
+            addDeviceBadge(highlights, devId, links.size());
+            sendHighlights(highlights);
         }
         // Note: could also process Host, if available
     }
 
+    private void addDeviceBadge(Highlights h, DeviceId devId, int n) {
+        DeviceHighlight dh = new DeviceHighlight(devId.toString());
+        dh.setBadge(createBadge(n));
+        h.add(dh);
+    }
+
+    private NodeBadge createBadge(int n) {
+        Status status = n > 3 ? Status.ERROR : Status.WARN;
+        String noun = n > 3 ? "(critical)" : "(problematic)";
+        String msg = "Egress links: " + n + " " + noun;
+        return NodeBadge.number(status, n, msg);
+    }
+
     private Highlights fromLinks(Set<Link> links, DeviceId devId) {
         DemoLinkMap linkMap = new DemoLinkMap();
         if (links != null) {
index 9899982..48e75a5 100644 (file)
  */
 package ${package};
 
+import org.onosproject.net.DeviceId;
 import org.onosproject.ui.UiTopoOverlay;
 import org.onosproject.ui.topo.ButtonId;
 import org.onosproject.ui.topo.PropertyPanel;
 import org.onosproject.ui.topo.TopoConstants.CoreButtons;
 import org.onosproject.ui.topo.TopoConstants.Glyphs;
 
-import static org.onosproject.ui.topo.TopoConstants.Properties.*;
+import static org.onosproject.ui.topo.TopoConstants.Properties.FLOWS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.INTENTS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.LATITUDE;
+import static org.onosproject.ui.topo.TopoConstants.Properties.LONGITUDE;
+import static org.onosproject.ui.topo.TopoConstants.Properties.TOPOLOGY_SSCS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.TUNNELS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.VERSION;
 
 /**
  * Our topology overlay.
@@ -61,7 +68,7 @@ public class AppUiTopovOverlay extends UiTopoOverlay {
     }
 
     @Override
-    public void modifyDeviceDetails(PropertyPanel pp) {
+    public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) {
         pp.title(MY_DEVICE_TITLE);
         pp.removeProps(LATITUDE, LONGITUDE);
 
index 348cb83..e37dc3b 100755 (executable)
@@ -37,17 +37,6 @@ export ONOS_BOOT_FEATURES="${ONOS_BOOT_FEATURES:-webconsole,onos-api,onos-core,o
 # ONOS builtin apps and providers ignited by default
 export ONOS_APPS="${ONOS_APPS:-drivers,openflow}"
 
-# Generate a cluster.json from the ON* environment variables
-CDEF_FILE=/tmp/${remote}.cluster.json
-echo "{ \"ipPrefix\": \"$ONOS_NIC\"," > $CDEF_FILE
-echo "  \"nodes\":[" >> $CDEF_FILE
-for node in $(env | sort | egrep "OC[2-9]+" | cut -d= -f2); do
-    echo "  { \"id\": \"$node\", \"ip\": \"$node\", \"tcpPort\": 9876 }," >> $CDEF_FILE
-done
-echo "  { \"id\": \"$OC1\", \"ip\": \"$OC1\", \"tcpPort\": 9876 }" >> $CDEF_FILE
-echo "]}" >> $CDEF_FILE
-scp -q $CDEF_FILE $remote:$ONOS_INSTALL_DIR/config/cluster.json
-
 ssh $remote "
     echo \"onos.ip = \$(sudo ifconfig | grep $ONOS_NIC | cut -d: -f2 | cut -d\\  -f1)\" \
         >> $ONOS_INSTALL_DIR/$KARAF_DIST/etc/system.properties
@@ -66,10 +55,10 @@ ssh $remote "
     done
 "
 
-# Generate a default tablets.json from the ON* environment variables
-TDEF_FILE=/tmp/${remote}.tablets.json
-onos-gen-partitions $TDEF_FILE
-scp -q $TDEF_FILE $remote:$ONOS_INSTALL_DIR/config/tablets.json
+# Generate a default cluster.json from the ON* environment variables
+CDEF_FILE=/tmp/${remote}.cluster.json
+onos-gen-partitions $CDEF_FILE
+scp -q $CDEF_FILE $remote:$ONOS_INSTALL_DIR/config/cluster.json
 
 # Copy tools/package/config/ to remote
 scp -qr ${ONOS_ROOT}/tools/package/config/ $remote:$ONOS_INSTALL_DIR/
diff --git a/framework/src/onos/tools/test/bin/onos-execute-expect b/framework/src/onos/tools/test/bin/onos-execute-expect
new file mode 100755 (executable)
index 0000000..6ad9569
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Executes a command on the given ONOS instance and matches the output
+# to the passed one.
+# First argument is the IP address of the machine to run the command on,
+# then you pass the command and it's arguments if needed, then --expect and
+# after it the string of what the output should be.
+# Example:
+# onos-execute-expect 1.1.1.1 fooCommand fooParamenter --expect fooOutputString
+# -----------------------------------------------------------------------------
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+
+aux=/tmp/stc-$$.log
+trap "rm -f $aux 2>/dev/null" EXIT
+ip=$1
+cmd=""
+for a in ${*:2}; do shift; if [ "$a" = "--expect" ]; then break; fi; cmd="$cmd $a"; done
+expect="${@: -1}"
+onos $ip $cmd > $aux
+cat $aux
+grep -q $expect $aux && echo "expected value found" && exit 0
+exit 1
+
+
index a255839..35195b0 100755 (executable)
@@ -23,22 +23,27 @@ def get_OC_vars():
   return sorted(vars, key=alphanum_key)
 
 def get_nodes(vars, port=9876):
-  node = lambda k: { 'id': k, 'ip': k, 'tcpPort': port }
+  node = lambda k: { 'id': k, 'ip': k, 'port': port }
   return [ node(environ[v]) for v in vars ]
 
 def generate_permutations(nodes, k):
   l = deque(nodes)
-  perms = {}
+  perms = []
   for i in range(1, len(nodes)+1):
-    perms['p%d' % i] = list(l)[:k]
+    part = {
+             'name': 'p%d' % i,
+             'members': list(l)[:k]
+           }
+    perms.append(part)
     l.rotate(-1)
-  return OrderedDict(sorted(perms.iteritems(), key=lambda (k, v): alphanum_key(k)))
+  return perms
 
 if __name__ == '__main__':
   vars = get_OC_vars()
   nodes = get_nodes(vars)
-  partitions = generate_permutations(nodes, 3)
-  data = { 
+  partitions = generate_permutations([v.get('id') for v in nodes], 3)
+  data = {
+           'name': 'default',
            'nodes': nodes,
            'partitions': partitions 
          }
index a3980e1..6d898ee 100755 (executable)
@@ -10,7 +10,8 @@ nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2)
 
 for node in $nodes; do
     # Prune the node entry from the known hosts file since server key changes
-    ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101
+    ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101 || 
+        ( echo "Failed to remove key from known_hosts" >&2 && exit 1 )
 
     # Setup passwordless login for the local user on the remote node
     ssh $ONOS_USER@$node "
index 8737cf3..60a1720 100755 (executable)
@@ -20,6 +20,7 @@ scenario=${1:-smoke}
 
 # If stcColor is not set, we will enable color if this is an interactive session
 [ -t 1 ] && interactive=true || interactive=false
+[ -t 1 ] && notInteractive=false || notInteractive=true
 
 # stc requires that ONOS_USE_SSH=true, but we will store the old value and reset it after
 sshSet=$([ -z ${ONOS_USE_SSH+x} ]) && oldSSH=$ONOS_USE_SSH
@@ -27,7 +28,8 @@ export ONOS_USE_SSH=true
 
 # Run stc
 [ -z "$stcDebug" ] && DEBUG_OPTS=""
-stcColor=${stcColor:-$interactive} java $DEBUG_OPTS -jar $JAR $scenario "$@"
+stcColor=${stcColor:-$interactive} stcDumpLogs=${stcDumpLogs:-$notInteractive} \
+    java $DEBUG_OPTS -jar $JAR $scenario "$@"
 
 # Reset the old value of ONOS_USE_SSH
 [ $sshSet ] && export ONOS_USE_SSH=oldSSH || unset ONOS_USE_SSH
diff --git a/framework/src/onos/tools/test/scenarios/dist-test-seq.xml b/framework/src/onos/tools/test/scenarios/dist-test-seq.xml
new file mode 100644 (file)
index 0000000..2e99fa2
--- /dev/null
@@ -0,0 +1,67 @@
+<!--
+  ~ Copyright 20${OCI}5 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<scenario name="dist-test"
+          description="ONOS distributed primitives setup">
+    <group name="Distributed-Primitives">
+        <!--<import file="${ONOS_SCENARIOS}/prerequisites.xml"/>-->
+
+        <!--<import file="${ONOS_SCENARIOS}/setup.xml"/>
+        <dependency name="Setup" requires="Prerequisites"/>-->
+
+        <sequential var="${OC#}" starts="Distributed-App-${#}" ends="Check-Distributed-Exceptions-${#-1}">
+            <step name="Distributed-App-${#}"
+                  requires="Setup"
+                  exec="onos ${OC#} app activate org.onosproject.distributedprimitives"/>
+
+            <step name="Test-Counter-Increment-${#}"
+                  requires="Distributed-App-${#}"
+                  exec="onos-execute-expect ${OC#} counter-test-increment fooCounter 5 --expect updated"/>
+
+            <step name="Test-Add-${#}"
+                  requires="Distributed-App-${#}"
+                  exec="onos-execute-expect ${OC#} set-test-add fooSet foo --expect added"/>
+
+            <step name="Test-Get-${#}"
+                  requires="Test-Add-${#}"
+                  exec="onos-execute-expect ${OC#} set-test-get fooSet foo --expect contains"/>
+
+            <step name="Test-Remove-${#}"
+                  requires="Test-Get-${#}"
+                  exec="onos-execute-expect ${OC#} set-test-remove fooSet foo --expect removed"/>
+
+            <step name="Test-Add-Multiple-${#}"
+                  requires="Test-Remove-${#}"
+                  exec="onos-execute-expect ${OC#} set-test-add fooSet foo foo2 foo3 --expect added"/>
+
+            <step name="Test-Get-Multiple-${#}"
+                  requires="Test-Add-Multiple-${#}"
+                  exec="onos-execute-expect ${OC#} set-test-get fooSet foo foo2 foo3 --expect contains"/>
+
+            <step name="Test-Remove-Multiple-${#}"
+                  requires="Test-Get-Multiple-${#}"
+                  exec="onos-execute-expect ${OC#} set-test-remove fooSet foo foo2 foo3 --expect removed"/>
+
+            <step name="Sleep-${#}"
+                  exec="sleep 2"
+                  requires="Test-Remove-Multiple-${#}"/>
+            <!--Check with check logs-->
+            <step name="Check-Distributed-Exceptions-${#}"
+                  exec="onos-check-logs ${OC#}"
+                  requires="Sleep-${#}"/>
+        </sequential>
+    </group>
+</scenario>
\ No newline at end of file
diff --git a/framework/src/onos/tools/test/scenarios/dist-test.xml b/framework/src/onos/tools/test/scenarios/dist-test.xml
new file mode 100644 (file)
index 0000000..5e7dab0
--- /dev/null
@@ -0,0 +1,70 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+-->
+
+<scenario name="dist-test"
+          description="ONOS distributed primitives setup">
+    <group name="Distributed-Primitives">
+
+        <!--<import file="${ONOS_SCENARIOS}/setup.xml"/>
+        <dependency name="Setup" requires="Prerequisites"/>-->
+
+        <step name="Distributed-App"
+              requires="Setup"
+              exec="onos ${OCI} app activate org.onosproject.distributedprimitives"/>
+
+        <step name="Test-Counter-Increment"
+              requires="Distributed-App"
+              exec="onos-execute-expect ${OCI} counter-test-increment fooCounter 5 --expect updated"/>
+
+        <step name="Test-Add"
+              requires="Distributed-App"
+              exec="onos-execute-expect ${OCI} set-test-add fooSet foo --expect added"/>
+
+        <step name="Test-Get"
+              requires="Test-Add"
+              exec="onos-execute-expect ${OCI} set-test-get fooSet foo --expect contains"/>
+
+        <step name="Test-Remove"
+              requires="Test-Get"
+              exec="onos-execute-expect ${OCI} set-test-remove fooSet foo --expect removed"/>
+
+        <step name="Test-Add-Multiple"
+              requires="Test-Remove"
+              exec="onos-execute-expect ${OCI} set-test-add fooSet foo foo2 foo3 --expect added"/>
+
+        <step name="Test-Get-Multiple"
+              requires="Test-Add-Multiple"
+              exec="onos-execute-expect ${OCI} set-test-get fooSet foo foo2 foo3 --expect contains"/>
+
+        <step name="Test-Remove-Multiple"
+              requires="Test-Get-Multiple"
+              exec="onos-execute-expect ${OCI} set-test-remove fooSet foo foo2 foo3 --expect removed"/>
+
+        <step name="Test-Map-Put"
+              requires="Distributed-App"
+              exec="onos-execute-expect ${OCI} transactional-map-test-put 1 foo --expect Created"/>
+
+        <step name="Test-Map-Get"
+              requires="Test-Map-Put"
+              exec="onos-execute-expect ${OCI} transactional-map-test-get Key1 --expect Key-value"/>
+
+        <!--Check with check logs-->
+        <step name="Check-Distributed-Exceptions"
+              exec="onos-check-logs ${OCI}"
+              requires="Test-Map-Get"/>
+    </group>
+</scenario>
+
index a1ae834..5d955e5 100644 (file)
@@ -344,7 +344,10 @@ class LINCSwitch(OpticalSwitch):
                 continue
             portDict = {}
             portDict[ 'port' ] = port
-            portDict[ 'type' ] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER'
+            portType = 'COPPER'
+            if isinstance(intf.link, LINCLink):
+                portType = 'OCH' if intf.link.isCrossConnect else 'OMS'
+            portDict[ 'type' ] = portType
             intfList = [ intf.link.intf1, intf.link.intf2 ]
             intfList.remove(intf)
             portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance(intf.link, LINCLink) else 0
@@ -787,7 +790,10 @@ class LINCIntf(OpticalIntf):
         configDict = {}
         configDict[ 'port' ] = self.port
         configDict[ 'speed' ] = self.speed
-        configDict[ 'type' ] = 'FIBER'
+        portType = 'COPPER'
+        if isinstance(self.link, LINCLink):
+            portType = 'OCH' if self.link.isCrossConnect else 'OMS'
+        configDict[ 'type' ] = portType
         return configDict
 
     def config(self, *args, **kwargs):
index 003c177..9ab5cab 100644 (file)
 
 package org.onlab.packet;
 
+import org.onlab.packet.ndp.NeighborAdvertisement;
+import org.onlab.packet.ndp.NeighborSolicitation;
+import org.onlab.packet.ndp.Redirect;
+import org.onlab.packet.ndp.RouterAdvertisement;
+import org.onlab.packet.ndp.RouterSolicitation;
+
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -531,27 +537,114 @@ public class Ethernet extends BasePacket {
             sb.append("\nnw_proto: ");
             sb.append(p.getProtocol());
 
-            if (pkt instanceof TCP) {
-                sb.append("\ntp_src: ");
-                sb.append(((TCP) pkt).getSourcePort());
-                sb.append("\ntp_dst: ");
-                sb.append(((TCP) pkt).getDestinationPort());
-
-            } else if (pkt instanceof UDP) {
-                sb.append("\ntp_src: ");
-                sb.append(((UDP) pkt).getSourcePort());
-                sb.append("\ntp_dst: ");
-                sb.append(((UDP) pkt).getDestinationPort());
+            IPacket payload = pkt.getPayload();
+            if (payload != null) {
+                if (payload instanceof TCP) {
+                    sb.append("\ntp_src: ");
+                    sb.append(((TCP) payload).getSourcePort());
+                    sb.append("\ntp_dst: ");
+                    sb.append(((TCP) payload).getDestinationPort());
+
+                } else if (payload instanceof UDP) {
+                    sb.append("\ntp_src: ");
+                    sb.append(((UDP) payload).getSourcePort());
+                    sb.append("\ntp_dst: ");
+                    sb.append(((UDP) payload).getDestinationPort());
+                } else if (payload instanceof ICMP) {
+                    final ICMP icmp = (ICMP) payload;
+                    sb.append("\nicmp_type: ");
+                    sb.append(icmp.getIcmpType());
+                    sb.append("\nicmp_code: ");
+                    sb.append(icmp.getIcmpCode());
+                }
             }
-
-            if (pkt instanceof ICMP) {
-                final ICMP icmp = (ICMP) pkt;
-                sb.append("\nicmp_type: ");
-                sb.append(icmp.getIcmpType());
-                sb.append("\nicmp_code: ");
-                sb.append(icmp.getIcmpCode());
+        } else if (pkt instanceof IPv6) {
+            final IPv6 ipv6 = (IPv6) pkt;
+            sb.append("\nipv6_src: ");
+            sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
+            sb.append("\nipv6_dst: ");
+            sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
+            sb.append("\nipv6_proto: ");
+            sb.append(ipv6.getNextHeader());
+
+            IPacket payload = pkt.getPayload();
+            if (payload != null && payload instanceof ICMP6) {
+                final ICMP6 icmp6 = (ICMP6) payload;
+                sb.append("\nicmp6_type: ");
+                sb.append(icmp6.getIcmpType());
+                sb.append("\nicmp6_code: ");
+                sb.append(icmp6.getIcmpCode());
+
+                payload = payload.getPayload();
+                if (payload != null) {
+                    if (payload instanceof NeighborSolicitation) {
+                        final NeighborSolicitation ns = (NeighborSolicitation) payload;
+                        sb.append("\nns_target_addr: ");
+                        sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
+                        ns.getOptions().forEach(option -> {
+                            sb.append("\noption_type: ");
+                            sb.append(option.type());
+                            sb.append("\noption_data: ");
+                            sb.append(bytesToHex(option.data()));
+                        });
+                    } else if (payload instanceof NeighborAdvertisement) {
+                        final NeighborAdvertisement na = (NeighborAdvertisement) payload;
+                        sb.append("\nna_target_addr: ");
+                        sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
+                        sb.append("\nna_solicited_flag: ");
+                        sb.append(na.getSolicitedFlag());
+                        sb.append("\nna_router_flag: ");
+                        sb.append(na.getRouterFlag());
+                        sb.append("\nna_override_flag: ");
+                        sb.append(na.getOverrideFlag());
+                        na.getOptions().forEach(option -> {
+                            sb.append("\noption_type: ");
+                            sb.append(option.type());
+                            sb.append("\noption_data: ");
+                            sb.append(bytesToHex(option.data()));
+                        });
+                    } else if (payload instanceof RouterSolicitation) {
+                        final RouterSolicitation rs = (RouterSolicitation) payload;
+                        sb.append("\nrs");
+                        rs.getOptions().forEach(option -> {
+                            sb.append("\noption_type: ");
+                            sb.append(option.type());
+                            sb.append("\noption_data: ");
+                            sb.append(bytesToHex(option.data()));
+                        });
+                    } else if (payload instanceof RouterAdvertisement) {
+                        final RouterAdvertisement ra = (RouterAdvertisement) payload;
+                        sb.append("\nra_hop_limit: ");
+                        sb.append(ra.getCurrentHopLimit());
+                        sb.append("\nra_mflag: ");
+                        sb.append(ra.getMFlag());
+                        sb.append("\nra_oflag: ");
+                        sb.append(ra.getOFlag());
+                        sb.append("\nra_reachable_time: ");
+                        sb.append(ra.getReachableTime());
+                        sb.append("\nra_retransmit_time: ");
+                        sb.append(ra.getRetransmitTimer());
+                        sb.append("\nra_router_lifetime: ");
+                        sb.append(ra.getRouterLifetime());
+                        ra.getOptions().forEach(option -> {
+                            sb.append("\noption_type: ");
+                            sb.append(option.type());
+                            sb.append("\noption_data: ");
+                            sb.append(bytesToHex(option.data()));
+                        });
+                    } else if (payload instanceof Redirect) {
+                        final Redirect rd = (Redirect) payload;
+                        sb.append("\nrd_target_addr: ");
+                        sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
+                        rd.getOptions().forEach(option -> {
+                            sb.append("\noption_type: ");
+                            sb.append(option.type());
+                            sb.append("\noption_data: ");
+                            sb.append(bytesToHex(option.data()));
+                        });
+                    }
+                }
             }
-
         } else if (pkt instanceof DHCP) {
             sb.append("\ndhcp packet");
         } else if (pkt instanceof Data) {
index 349e660..6080656 100644 (file)
@@ -41,6 +41,17 @@ public final class Bandwidth implements RichComparable<Bandwidth> {
         this.bps = 0;
     }
 
+    /**
+     * Creates a new instance with given bandwidth.
+     *
+     * @param v         bandwidth value
+     * @param unit      {@link DataRateUnit} of {@code v}
+     * @return {@link Bandwidth} instance with given bandwidth
+     */
+    public static Bandwidth of(double v, DataRateUnit unit) {
+        return new Bandwidth(unit.toBitsPerSecond(v));
+    }
+
     /**
      * Creates a new instance with given bandwidth in bps.
      *
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java
new file mode 100644 (file)
index 0000000..d49ed7b
--- /dev/null
@@ -0,0 +1,64 @@
+package org.onlab.util;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Data rate unit.
+ */
+@Beta
+public enum DataRateUnit {
+    /**
+     * Bit per second.
+     */
+    BPS(1L),
+    /**
+     * Kilobit per second.
+     * (Decimal/SI)
+     */
+    KBPS(1_000L),
+    /**
+     * Megabit per second.
+     * (Decimal/SI)
+     */
+    MBPS(1_000_000L),
+    /**
+     * Gigabit per second.
+     * (Decimal/SI)
+     */
+    GBPS(1_000_000_000L);
+
+    private final long multiplier;
+
+    DataRateUnit(long multiplier) {
+        this.multiplier = multiplier;
+    }
+
+    /**
+     * Returns the multiplier to use, when converting value of this unit to bps.
+     *
+     * @return multiplier
+     */
+    public long multiplier() {
+        return multiplier;
+    }
+
+    /**
+     * Converts given value in this unit to bits per seconds.
+     *
+     * @param v data rate value
+     * @return {@code v} in bits per seconds
+     */
+    public long toBitsPerSecond(long v) {
+        return v * multiplier;
+    }
+
+    /**
+     * Converts given value in this unit to bits per seconds.
+     *
+     * @param v data rate value
+     * @return {@code v} in bits per seconds
+     */
+    public double toBitsPerSecond(double v) {
+        return v * multiplier;
+    }
+}
index db7224a..8a409c3 100644 (file)
@@ -31,7 +31,10 @@ import static org.onlab.junit.TestTools.assertAfter;
 public class AbstractAccumulatorTest {
 
 
-    private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer();
+    private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer(true);
+
+    private static final int LONG_REAL_TIME_DELAY = 30;
+    private static final int SHORT_REAL_TIME_DELAY = 5;
 
 
     @Test
@@ -52,7 +55,7 @@ public class AbstractAccumulatorTest {
         accumulator.add(new TestItem("d"));
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("e"));
-        timer.advanceTimeMillis(20, 10);
+        timer.advanceTimeMillis(20, LONG_REAL_TIME_DELAY);
         assertFalse("should have fired", accumulator.batch.isEmpty());
         assertEquals("incorrect batch", "abcde", accumulator.batch);
     }
@@ -61,16 +64,16 @@ public class AbstractAccumulatorTest {
     public void timeTrigger() {
         TestAccumulator accumulator = new TestAccumulator();
         accumulator.add(new TestItem("a"));
-        timer.advanceTimeMillis(30, 1);
+        timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("b"));
-        timer.advanceTimeMillis(30, 1);
+        timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("c"));
-        timer.advanceTimeMillis(30, 1);
+        timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("d"));
-        timer.advanceTimeMillis(10, 10);
+        timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY);
         assertFalse("should have fired", accumulator.batch.isEmpty());
         assertEquals("incorrect batch", "abcd", accumulator.batch);
     }
@@ -81,7 +84,7 @@ public class AbstractAccumulatorTest {
         accumulator.add(new TestItem("a"));
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("b"));
-        timer.advanceTimeMillis(70, 10);
+        timer.advanceTimeMillis(70, LONG_REAL_TIME_DELAY);
         assertFalse("should have fired", accumulator.batch.isEmpty());
         assertEquals("incorrect batch", "ab", accumulator.batch);
     }
@@ -93,10 +96,10 @@ public class AbstractAccumulatorTest {
         accumulator.add(new TestItem("a"));
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("b"));
-        timer.advanceTimeMillis(80, 1);
+        timer.advanceTimeMillis(80, SHORT_REAL_TIME_DELAY);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.ready = true;
-        timer.advanceTimeMillis(80, 10);
+        timer.advanceTimeMillis(80, LONG_REAL_TIME_DELAY);
         assertFalse("should have fired", accumulator.batch.isEmpty());
         assertEquals("incorrect batch", "ab", accumulator.batch);
     }
@@ -105,12 +108,12 @@ public class AbstractAccumulatorTest {
     public void readyLongTrigger() {
         TestAccumulator accumulator = new TestAccumulator();
         accumulator.ready = false;
-        timer.advanceTimeMillis(120, 1);
+        timer.advanceTimeMillis(120, SHORT_REAL_TIME_DELAY);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestItem("a"));
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.ready = true;
-        timer.advanceTimeMillis(120, 10);
+        timer.advanceTimeMillis(120, LONG_REAL_TIME_DELAY);
         assertFalse("should have fired", accumulator.batch.isEmpty());
         assertEquals("incorrect batch", "a", accumulator.batch);
     }
@@ -128,7 +131,7 @@ public class AbstractAccumulatorTest {
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.ready = true;
         accumulator.add(new TestItem("g"));
-        timer.advanceTimeMillis(10, 10);
+        timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY);
         assertFalse("should have fired", accumulator.batch.isEmpty());
         assertEquals("incorrect batch", "abcdefg", accumulator.batch);
     }
index 4116cbe..8fb008e 100644 (file)
@@ -65,6 +65,14 @@ public class ManuallyAdvancingTimer extends java.util.Timer {
     /* Data structure for tracking tasks */
     private final TaskQueue queue = new TaskQueue();
 
+    /* Whether execution should execute on the executor thread or the calling thread. */
+    private final boolean runLocally;
+
+    public ManuallyAdvancingTimer(boolean runLocally) {
+        this.runLocally = runLocally;
+    }
+
+
     @Override
     public void schedule(TimerTask task, long delay) {
         if (!staticsPopulated) {
@@ -165,14 +173,16 @@ public class ManuallyAdvancingTimer extends java.util.Timer {
 
     /**
      * Advances the virtual time a certain number of millis triggers execution delays a certain amount to
-     * allow time for execution.
+     * allow time for execution.  If runLocally is true then all real time delays are ignored.
      *
      * @param virtualTimeAdvance the time to be advances in millis of simulated time.
      * @param realTimeDelay      the time to delay in real time to allow for processing.
      */
     public void advanceTimeMillis(long virtualTimeAdvance, int realTimeDelay) {
         timerKeeper.advanceTimeMillis(virtualTimeAdvance);
-        delay(realTimeDelay);
+        if (!runLocally) {
+            delay(realTimeDelay);
+        }
     }
 
     /**
@@ -238,7 +248,11 @@ public class ManuallyAdvancingTimer extends java.util.Timer {
                     e.printStackTrace();
                     return false;
                 }
-                executorService.execute(task);
+                if (runLocally) {
+                    task.run();
+                } else {
+                    executorService.execute(task);
+                }
                 return true;
             } else {
                 //Calculate next execution time, using absolute value of period
@@ -253,7 +267,11 @@ public class ManuallyAdvancingTimer extends java.util.Timer {
                 }
                 //Schedule next execution
                 queue.insertOrdered(task);
-                executorService.execute(task);
+                if (runLocally) {
+                    task.run();
+                } else {
+                    executorService.execute(task);
+                }
                 return true;
             }
         }
index b8e1e85..36b50e6 100644 (file)
@@ -47,14 +47,14 @@ public class ManuallyAdvancingTimerTest {
     private AtomicInteger tasksRunCount;
 
     // FIXME if this class fails first try increasing the real time delay to account for heavy system load.
-    private static final int REAL_TIME_DELAY = 1;
+    private static final int REAL_TIME_DELAY = 10;
 
     /**
      * Sets up the testing environment.
      */
     @Before
     public void setup() {
-        timer = new ManuallyAdvancingTimer();
+        timer = new ManuallyAdvancingTimer(true);
         idGenerator = new AtomicInteger(1);
         tasksRunCount = new AtomicInteger(0);
         taskList = Lists.newArrayList();
index bc10ec7..ca04a7c 100644 (file)
 package org.onlab.stc;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.io.Files;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.servlet.ServletHandler;
 import org.eclipse.jetty.util.log.Logger;
 import org.onlab.stc.Coordinator.Status;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
@@ -64,10 +67,12 @@ public final class Main {
     private String runToPatterns = "";
 
     private Coordinator coordinator;
+    private Compiler compiler;
     private Monitor monitor;
     private Listener delegate = new Listener();
 
     private static boolean useColor = Objects.equals("true", System.getenv("stcColor"));
+    private static boolean dumpLogs = Objects.equals("true", System.getenv("stcDumpLogs"));
 
     // usage: stc [<scenario-file>] [run]
     // usage: stc [<scenario-file>] run [from <from-patterns>] [to <to-patterns>]]
@@ -113,7 +118,7 @@ public final class Main {
             Scenario scenario = Scenario.loadScenario(new FileInputStream(scenarioFile));
 
             // Elaborate scenario
-            Compiler compiler = new Compiler(scenario);
+            compiler = new Compiler(scenario);
             compiler.compile();
 
             // Setup the process flow coordinator
@@ -221,7 +226,7 @@ public final class Main {
     /**
      * Internal delegate to monitor the process execution.
      */
-    private static class Listener implements StepProcessListener {
+    private class Listener implements StepProcessListener {
         @Override
         public void onStart(Step step, String command) {
             logStatus(currentTimeMillis(), step.name(), IN_PROGRESS, command);
@@ -230,6 +235,9 @@ public final class Main {
         @Override
         public void onCompletion(Step step, Status status) {
             logStatus(currentTimeMillis(), step.name(), status, null);
+            if (dumpLogs && !(step instanceof Group) && status == FAILED) {
+                dumpLogs(step);
+            }
         }
 
         @Override
@@ -246,6 +254,18 @@ public final class Main {
         }
     }
 
+    // Dumps the step logs to standard output.
+    private void dumpLogs(Step step) {
+        File logFile = new File(compiler.logDir(), step.name() + ".log");
+        try {
+            print(">>>>>");
+            Files.copy(logFile, System.out);
+            print("<<<<<");
+        } catch (IOException e) {
+            print("Unable to dump log file %s", logFile.getName());
+        }
+    }
+
     // Produces a description of event using the specified step status.
     private static String action(Status status) {
         return status == IN_PROGRESS ? "started" :
index dd9b9fc..312f6e3 100644 (file)
@@ -84,10 +84,9 @@ public class ClusterWebResource extends AbstractWebResource {
     public Response formCluster(InputStream config) throws IOException {
         JsonCodec<ControllerNode> codec = codec(ControllerNode.class);
         ObjectNode root = (ObjectNode) mapper().readTree(config);
-        String ipPrefix = root.path("ipPrefix").asText();
 
         List<ControllerNode> nodes = codec.decode((ArrayNode) root.path("nodes"), this);
-        get(ClusterAdminService.class).formCluster(new HashSet<>(nodes), ipPrefix);
+        get(ClusterAdminService.class).formCluster(new HashSet<>(nodes));
 
         return Response.ok().build();
     }
index 8acdc2c..82b7a78 100644 (file)
@@ -27,12 +27,14 @@ import org.onosproject.cluster.ClusterEventListener;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.event.Event;
 import org.onosproject.mastership.MastershipAdminService;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
@@ -48,11 +50,14 @@ import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.intent.HostToHostIntent;
+import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentEvent;
 import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.link.LinkEvent;
 import org.onosproject.net.link.LinkListener;
+import org.onosproject.ui.JsonUtils;
 import org.onosproject.ui.RequestHandler;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.impl.TrafficMonitor.Mode;
@@ -76,7 +81,9 @@ import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.HostId.hostId;
-import static org.onosproject.net.device.DeviceEvent.Type.*;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
+import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
 import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
 import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
 import static org.onosproject.ui.JsonUtils.envelope;
@@ -97,6 +104,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
     private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
     private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
     private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
+    private static final String SEL_INTENT = "selectIntent";
     private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
     private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
     private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
@@ -117,9 +125,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
     private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
     private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
     private static final String UPDATE_INSTANCE = "updateInstance";
+    private static final String TOPO_START_DONE = "topoStartDone";
 
     // fields
     private static final String ID = "id";
+    private static final String KEY = "key";
+    private static final String APP_ID = "appId";
+    private static final String APP_NAME = "appName";
     private static final String DEVICE = "device";
     private static final String HOST = "host";
     private static final String CLASS = "class";
@@ -135,7 +147,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
     private static final String DEACTIVATE = "deactivate";
 
 
-    private static final String APP_ID = "org.onosproject.gui";
+    private static final String MY_APP_ID = "org.onosproject.gui";
 
     private static final long TRAFFIC_PERIOD = 5000;
     private static final long SUMMARY_PERIOD = 30000;
@@ -176,7 +188,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
     @Override
     public void init(UiConnection connection, ServiceDirectory directory) {
         super.init(connection, directory);
-        appId = directory.get(CoreService.class).registerApplication(APP_ID);
+        appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
         traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
     }
 
@@ -213,6 +225,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
                 new ReqNextIntent(),
                 new ReqPrevIntent(),
                 new ReqSelectedIntentTraffic(),
+                new SelIntent(),
 
                 new CancelTraffic()
         );
@@ -241,6 +254,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
             sendAllDevices();
             sendAllLinks();
             sendAllHosts();
+            sendTopoStartDone();
         }
     }
 
@@ -344,11 +358,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
             PropertyPanel pp = null;
 
             if (type.equals(DEVICE)) {
-                pp = deviceDetails(deviceId(id), sid);
-                overlayCache.currentOverlay().modifyDeviceDetails(pp);
+                DeviceId did = deviceId(id);
+                pp = deviceDetails(did, sid);
+                overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
             } else if (type.equals(HOST)) {
-                pp = hostDetails(hostId(id), sid);
-                overlayCache.currentOverlay().modifyHostDetails(pp);
+                HostId hid = hostId(id);
+                pp = hostDetails(hid, sid);
+                overlayCache.currentOverlay().modifyHostDetails(pp, hid);
             }
 
             sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
@@ -524,6 +540,31 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
         }
     }
 
+    private final class SelIntent extends RequestHandler {
+        private SelIntent() {
+            super(SEL_INTENT);
+        }
+
+        @Override
+        public void process(long sid, ObjectNode payload) {
+            int appId = Integer.parseInt(string(payload, APP_ID));
+            String appName = string(payload, APP_NAME);
+            ApplicationId applicId = new DefaultApplicationId(appId, appName);
+            long intentKey = Long.decode(string(payload, KEY));
+
+            Key key = Key.of(intentKey, applicId);
+            log.debug("Attempting to select intent key={}", key);
+
+            Intent intent = intentService.getIntent(key);
+            if (intent == null) {
+                log.debug("no such intent found!");
+            } else {
+                log.debug("starting to monitor intent {}", key);
+                traffic.monitor(intent);
+            }
+        }
+    }
+
     private final class CancelTraffic extends RequestHandler {
         private CancelTraffic() {
             super(CANCEL_TRAFFIC);
@@ -623,6 +664,9 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
         return hostIds;
     }
 
+    private void sendTopoStartDone() {
+        sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode()));
+    }
 
     private synchronized void startSummaryMonitoring() {
         stopSummaryMonitoring();
index ea8ca3e..f4b5598 100644 (file)
@@ -17,6 +17,7 @@
 
 package org.onosproject.ui.impl;
 
+import org.onosproject.net.DeviceId;
 import org.onosproject.ui.UiTopoOverlay;
 import org.onosproject.ui.topo.ButtonId;
 import org.onosproject.ui.topo.PropertyPanel;
@@ -55,7 +56,7 @@ public class TrafficOverlay extends UiTopoOverlay {
     }
 
     @Override
-    public void modifyDeviceDetails(PropertyPanel pp) {
+    public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) {
         pp.addButton(SHOW_DEVICE_FLOWS)
             .addButton(SHOW_RELATED_TRAFFIC);
     }
index 46dbdb5..ded05cf 100644 (file)
     border-radius: 6px;
 }
 
+.floatpanel.dialog {
+    top: 180px;
+}
+
 html[data-platform='iPad'] .floatpanel {
     top: 80px;
 }
index aef71ee..10f0481 100644 (file)
     }
 
     angular.module('onosLayer')
-        .factory('PanelService', ['$log', 'FnService', function (_$log_, _fs_) {
+    .factory('PanelService',
+        ['$log', '$window', 'FnService',
+
+        function (_$log_, _$window_, _fs_) {
             $log = _$log_;
             fs = _fs_;
 
                 destroyPanel: destroyPanel
             };
         }]);
-
 }());
index 15b44bc..1253636 100644 (file)
@@ -37,6 +37,8 @@
         play: 'play',
         stop: 'stop',
 
+        topo: 'topo',
+
         refresh: 'refresh',
         garbage: 'garbage',
 
index 18b81ba..356ac0f 100644 (file)
@@ -81,7 +81,7 @@ div.summary-list tr.no-data td {
 }
 
 .light div.summary-list tr.selected {
-    background-color: deepskyblue;
+    background-color: deepskyblue !important;
 }
 
 .dark div.summary-list tr.selected {
index 24161bb..6a5ffb1 100644 (file)
@@ -47,6 +47,7 @@
             resp = o.tag + 'DataResponse',
             onSel = fs.isF(o.selCb),
             onResp = fs.isF(o.respCb),
+            idKey = o.idKey || 'id',
             oldTableData = [],
             loaded = false,
             refreshPromise, loadingPromise;
 
         // === selecting a row functions ----------------
         function selCb($event, selRow) {
-            o.scope.selId = (o.scope.selId === selRow.id) ? null : selRow.id;
+            var selId = selRow[idKey];
+            o.scope.selId = (o.scope.selId === selId) ? null : selId;
             onSel && onSel($event, selRow);
         }
         o.scope.selectCallback = selCb;
index 4883bee..98aa565 100644 (file)
@@ -1,24 +1,13 @@
-<!--
-  ~ Copyright 2015 Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
 <!-- Intent partial HTML -->
 <div id="ov-intent">
     <div class="tabular-header">
         <h2>Intents ({{tableData.length}} total)</h2>
         <div class="ctrl-btns">
+            <div ng-class="{active: !!selId}"
+                    icon icon-id="topo" icon-size="36"
+                    tooltip tt-msg="topoTip"
+                    ng-click="showIntent()"></div>
+            <div class="separator"></div>
             <div class="refresh" ng-class="{active: autoRefresh}"
                  icon icon-size="36" icon-id="refresh"
                  tooltip tt-msg="autoRefreshTip"
@@ -51,6 +40,8 @@
                 </tr>
 
                 <tr ng-repeat-start="intent in tableData track by $index"
+                    ng-click="selectCallback($event, intent)"
+                    ng-class="{selected: intent.key === selId}"
                     ng-repeat-complete row-id="{{intent.key}}">
                     <td>{{intent.appId}}</td>
                     <td>{{intent.key}}</td>
                     <td>{{intent.priority}}</td>
                     <td>{{intent.state}}</td>
                 </tr>
-                <tr row-id="{{intent.key}}">
+                <tr ng-click="selectCallback($event, intent)"
+                    ng-class="{selected: intent.key === selId}"
+                    row-id="{{intent.key}}">
                     <td class="resources" colspan="5">{{intent.resources}}</td>
                 </tr>
-                <tr row-id="{{intent.key}}" ng-repeat-end>
+                <tr ng-click="selectCallback($event, intent)"
+                    ng-class="{selected: intent.key === selId}"
+                    row-id="{{intent.key}}" ng-repeat-end>
                     <td class="details" colspan="5">{{intent.details}}</td>
                 </tr>
             </table>
index 5810f34..19f2c07 100644 (file)
 
     angular.module('ovIntent', [])
         .controller('OvIntentCtrl',
-        ['$log', '$scope', 'TableBuilderService',
+        ['$log', '$scope', 'TableBuilderService', 'NavService',
 
-            function ($log, $scope, tbs) {
-                tbs.buildTable({
-                    scope: $scope,
-                    tag: 'intent'
-                });
+        function ($log, $scope, tbs, ns) {
 
-                $log.log('OvIntentCtrl has been created');
-            }]);
+            function selCb($event, row) {
+                $log.debug('Got a click on:', row);
+                var m = /(\d+)\s:\s(.*)/.exec(row.appId),
+                    id = m ? m[1] : null,
+                    name = m ? m[2] : null;
+
+                $scope.intentData = ($scope.selId && m) ? {
+                    intentAppId: id,
+                    intentAppName: name,
+                    intentKey: row.key
+                } : null;
+            }
+
+            tbs.buildTable({
+                scope: $scope,
+                tag: 'intent',
+                selCb: selCb,
+                idKey: 'key'
+            });
+
+            $scope.topoTip = 'Show selected intent on topology view';
+
+            $scope.showIntent = function () {
+                var d = $scope.intentData;
+                d && ns.navTo('topo', d);
+            };
+
+            $log.log('OvIntentCtrl has been created');
+        }]);
 }());
index f4b089a..dda6d5c 100644 (file)
@@ -96,6 +96,24 @@ html[data-platform='iPad'] #topo-p-detail {
     height: 30px;
 }
 
+/* --- Topo Dialog Panel --- */
+
+#topo-p-dialog .dialog-button {
+    display: inline-block;
+    cursor: pointer;
+    height: 20px;
+    padding: 2px 6px;
+    margin: 4px;
+    float: right;
+}
+
+.light #topo-p-dialog .dialog-button {
+    background-color: #fec;
+}
+.dark #topo-p-dialog .dialog-button {
+    background-color: #369;
+}
+
 /* --- general topo-panel styling --- */
 
 .topo-p div.header div.icon {
@@ -427,6 +445,39 @@ html[data-platform='iPad'] #topo-p-detail {
     fill: #f90;
 }
 
+/* Badges */
+/* (... works for both light and dark themes...) */
+#ov-topo svg .node .badge circle {
+    stroke: #aaa;
+}
+
+#ov-topo svg .node .badge.badgeInfo circle {
+    fill: #ccf;
+}
+
+#ov-topo svg .node .badge.badgeWarn circle {
+    fill: #da2;
+}
+
+#ov-topo svg .node .badge.badgeError circle {
+    fill: #e44;
+}
+
+#ov-topo svg .node .badge use {
+    fill: white;
+}
+
+#ov-topo svg .node .badge.badgeInfo use {
+    fill: #448;
+}
+
+#ov-topo svg .node .badge text {
+    fill: white;
+}
+
+#ov-topo svg .node .badge.badgeInfo text {
+    fill: #448;
+}
 
 /* Host Nodes */
 
index 0dfd628..7ddfd13 100644 (file)
         flash.enable(true);
     }
 
+    function topoStartDone() {
+        var d = $scope.intentData;
+        if (d) {
+            tts.selectIntent(d);
+        }
+    }
 
     // --- Controller Definition -----------------------------------------
 
                   _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_,
                   _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr,
                   _ttip_, _tov_) {
-            var projection,
+            var params = $loc.search(),
+                projection,
                 dim,
                 uplink = {
                     // provides function calls back into this space
                     projection: function () { return projection; },
                     zoomLayer: function () { return zoomLayer; },
                     zoomer: function () { return zoomer; },
-                    opacifyMap: opacifyMap
+                    opacifyMap: opacifyMap,
+                    topoStartDone: topoStartDone
                 };
 
             $scope = _$scope_;
             ttip = _ttip_;
             tov = _tov_;
 
+            if (params.intentKey && params.intentAppId && params.intentAppName) {
+                $scope.intentData = {
+                    key: params.intentKey,
+                    appId: params.intentAppId,
+                    appName: params.intentAppName
+                };
+            }
+
             $scope.notifyResize = function () {
                 svgResized(fs.windowSize(mast.mastHeight()));
             };
index 1f061dd..1d2c5b1 100644 (file)
                 height: 14
             }
         },
+        badgeConfig = {
+            radius: 12,
+            yoff: 5,
+            gdelta: 10
+        },
         icfg;
 
+    var status = {
+        i: 'badgeInfo',
+        w: 'badgeWarn',
+        e: 'badgeError'
+    };
+
+    function badgeStatus(badge) {
+        return status[badge.status] || status.i;
+    }
+
     // internal state
     var deviceLabelIndex = 0,
         hostLabelIndex = 0;
     }
 
 
-    function updateDeviceLabel(d) {
+    function updateDeviceRendering(d) {
         var label = trimLabel(deviceLabel(d)),
             noLabel = !label,
             node = d.el,
             dim = icfg.device.dim,
-            box, dx, dy;
+            box, dx, dy, bsel,
+            bdg = d.badge,
+            bcr = badgeConfig.radius,
+            bcgd = badgeConfig.gdelta;
 
         node.select('text')
             .text(label)
         node.select('g.deviceIcon')
             .transition()
             .attr('transform', sus.translate(dx, dy));
-    }
 
-    function updateDeviceBadge(d) {
-        // TODO: Fix this WIP
-        var node = d.el,
-            bsel;
+        // handle badge, if defined
+        if (bdg) {
+            node.select('g.badge').remove();
 
-        if (d.badge) {
             bsel = node.append('g')
                 .classed('badge', true)
-                .attr('transform', sus.translate(-14, -14));
+                .classed(badgeStatus(bdg), true)
+                .attr('transform', sus.translate(dx + dim, dy));
 
             bsel.append('circle')
-                .attr('r', 14);
-            bsel.append('text')
-                .attr('transform', sus.translate(-5, 3))
-                .text('42');
+                .attr('r', bcr);
+
+            if (bdg.txt) {
+                bsel.append('text')
+                    .attr('dy', badgeConfig.yoff)
+                    .attr('text-anchor', 'middle')
+                    .text(bdg.txt);
+            } else if (bdg.gid) {
+                bsel.append('use')
+                    .attr({
+                        width: bcgd * 2,
+                        height: bcgd * 2,
+                        transform: sus.translate(-bcgd, -bcgd),
+                        'xlink:href': '#' + bdg.gid
+                    });
+
+            }
         }
     }
 
     function deviceExisting(d) {
         var node = d.el;
         node.classed('online', d.online);
-        updateDeviceLabel(d);
-        updateDeviceBadge(d);
+        updateDeviceRendering(d);
         api.posNode(d, true);
     }
 
                 deviceLabel: deviceLabel,
                 trimLabel: trimLabel,
 
-                updateDeviceLabel: updateDeviceLabel,
+                updateDeviceLabel: updateDeviceRendering,
                 updateHostLabel: updateHostLabel,
                 updateDeviceColors: updateDeviceColors,
 
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js
new file mode 100644 (file)
index 0000000..9307918
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *  Copyright 2015 Open Networking Laboratory
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Dialog Module.
+ Defines functions for manipulating a dialog box.
+ */
+
+(function () {
+    'use strict';
+
+    // injected refs
+    var $log, $window, $rootScope, fs, ps, bns;
+
+    // constants
+    var pCls = 'topo-p dialog',
+        idDialog = 'topo-p-dialog',
+        panelOpts = {
+            width: 300,
+            edge: 'left'
+        };
+
+    // internal state
+    var pApi, panel, dApi;
+
+    // TODO: ESC key invokes Cancel callback
+    // TODO: Enter invokes OK callback
+
+    // create the dialog; return its API
+    function createDialog() {
+        var header, body, footer,
+            p = ps.createPanel(idDialog, panelOpts);
+        p.classed(pCls, true);
+        panel = p;
+
+        function reset() {
+            p.empty();
+            p.append('div').classed('header', true);
+            p.append('div').classed('body', true);
+            p.append('div').classed('footer', true);
+
+            header = p.el().select('.header');
+            body = p.el().select('.body');
+            footer = p.el().select('.footer');
+        }
+
+        function hAppend(x) {
+            if (typeof x === 'string') {
+                return header.append(x);
+            }
+            header.node().appendChild(x.node());
+            return header;
+        }
+
+        function bAppend(x) {
+            if (typeof x === 'string') {
+                return body.append(x);
+            }
+            body.node().appendChild(x.node());
+            return body;
+        }
+
+        function fAppend(x) {
+            if (typeof x === 'string') {
+                return footer.append(x);
+            }
+            footer.node().appendChild(x.node());
+            return footer;
+        }
+
+        function destroy() {
+            ps.destroyPanel(idDialog);
+        }
+
+        return {
+            reset: reset,
+            appendHeader: hAppend,
+            appendBody: bAppend,
+            appendFooter: fAppend,
+            destroy: destroy
+        };
+    }
+
+    function makeButton(text, callback) {
+        var cb = fs.isF(callback);
+
+        function invoke() {
+            cb && cb();
+            panel.hide();
+        }
+        return createDiv('dialog-button')
+            .text(text)
+            .on('click', invoke);
+    }
+
+    function addContent(content) {
+        if (pApi) {
+            pApi.appendBody(content);
+        }
+        return dApi;
+    }
+
+    function addButton(text, cb) {
+        if (pApi) {
+            pApi.appendFooter(makeButton(text, cb));
+        }
+        return dApi;
+    }
+
+    // opens the dialog (creates if necessary)
+    function openDialog() {
+        $log.debug('Open DIALOG');
+        if (!pApi) {
+            pApi = createDialog();
+        }
+        pApi.reset();
+        pApi.appendHeader('h2').text('=dialog=');
+        panel.show();
+
+        // return the dialog object API
+        dApi = {
+            addContent: addContent,
+            addButton: addButton
+        };
+        return dApi;
+    }
+
+    // closes the dialog (destroying panel)
+    function closeDialog() {
+        $log.debug('Close DIALOG');
+        if (pApi) {
+            panel.hide();
+            pApi.destroy();
+            pApi = null;
+            dApi = null;
+        }
+    }
+
+    // creates a detached div, returning D3 selection
+    // optional CSS class may be provided
+    function createDiv(cls) {
+        var div = d3.select(document.createElement('div'));
+        if (cls) {
+            div.classed(cls, true);
+        }
+        return div;
+    }
+
+    // ==========================
+
+    angular.module('ovTopo')
+    .factory('TopoDialogService',
+        ['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'ButtonService',
+
+        function (_$log_, _$window_, _$rootScope_,
+                  _fs_, _ps_, _bns_) {
+            $log = _$log_;
+            $window = _$window_;
+            $rootScope = _$rootScope_;
+            fs = _fs_;
+            ps = _ps_;
+            bns = _bns_;
+
+            return {
+                openDialog: openDialog,
+                closeDialog: closeDialog,
+                createDiv: createDiv
+            };
+        }]);
+}());
index 5fd38bf..2957629 100644 (file)
@@ -60,6 +60,8 @@
             updateLink: tfs,
             removeLink: tfs,
 
+            topoStartDone: tfs,
+
             spriteListResponse: tspr,
             spriteDataResponse: tspr
         };
index f00b87f..844d7dc 100644 (file)
         }
     }
 
+    function topoStartDone(data) {
+        // called when the initial barrage of data has been sent from server
+        uplink.topoStartDone();
+    }
+
     // ========================
 
     function nodeById(id) {
                 removeHost: removeHost,
                 addLink: addLink,
                 updateLink: updateLink,
-                removeLink: removeLink
+                removeLink: removeLink,
+                topoStartDone: topoStartDone
             };
         }]);
 }());
index 9a3b435..2dee4c4 100644 (file)
@@ -34,7 +34,8 @@
 
     // internal state
     var overlays = {},
-        current = null;
+        current = null,
+        reset = true;
 
     function error(fn, msg) {
         $log.error(tos + fn + '(): ' + msg);
             payload[op] = oid;
         }
 
-        if (!same) {
+        if (reset || !same) {
+            reset = false;
             current && doop('deactivate');
             current = overlays[id];
             current && doop('activate');
                 tbSelection: tbSelection,
                 installButtons: installButtons,
                 addDetailButton: addDetailButton,
+                resetOnToolbarDestroy: function () { reset = true; },
                 hooks: {
                     escape: escapeHook,
                     emptySelect: emptySelectHook,
index 483c4ba..4ad7690 100644 (file)
         return cc;
     }
 
+    // returns a selection context, providing info about what is selected
+    function selectionContext() {
+        var devices = [],
+            hosts = [],
+            types = {};
+
+        angular.forEach(selections, function (d) {
+            var o = d.obj,
+                c = o.class;
+
+            if (c === 'device') {
+                devices.push(o.id);
+                types[o.id] = o.type;
+            }
+            if (c === 'host') {
+                hosts.push(o.id);
+                types[o.id] = o.type;
+            }
+        });
+
+        return {
+            devices: devices,
+            hosts: hosts,
+            types: types
+        };
+    }
+
     // === -----------------------------------------------------
     // === MODULE DEFINITION ===
 
                 selectOrder: function () { return selectOrder; },
                 somethingSelected: somethingSelected,
 
-                clickConsumed: clickConsumed
+                clickConsumed: clickConsumed,
+                selectionContext: selectionContext
             };
         }]);
 }());
index 3928cd2..0628544 100644 (file)
 
     function destroyToolbar() {
         tbs.destroyToolbar(name);
+        tov.resetOnToolbarDestroy();
     }
 
     // allows us to ensure the button states track key strokes
index ca37936..ff690c4 100644 (file)
         }
     }
 
+    // force the system to create a single intent selection
+    function selectIntent(data) {
+        trafficMode = 'intents';
+        hoverMode = null;
+        wss.sendEvent('selectIntent', data);
+        flash.flash('Selecting Intent ' + data.key);
+    }
+
 
     // === ------------------------------------------------------
     // action buttons on detail panel (multiple selection)
                 showPrevIntent: showPrevIntent,
                 showNextIntent: showNextIntent,
                 showSelectedIntentTraffic: showSelectedIntentTraffic,
+                selectIntent: selectIntent,
 
                 // invoked from mouseover/mouseout and selection change
                 requestTrafficForMode: requestTrafficForMode,
index 5df3c66..7e0d9b7 100644 (file)
@@ -98,6 +98,7 @@
     <script src="app/view/topo/topo.js"></script>
     <script src="app/view/topo/topoD3.js"></script>
     <script src="app/view/topo/topoEvent.js"></script>
+    <script src="app/view/topo/topoDialog.js"></script>
     <script src="app/view/topo/topoFilter.js"></script>
     <script src="app/view/topo/topoForce.js"></script>
     <script src="app/view/topo/topoInst.js"></script>
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json
new file mode 100644 (file)
index 0000000..4f35403
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "event": "showHighlights",
+  "payload": {
+    "devices": [
+      {
+        "id": "of:0000000000000001",
+        "badge": {
+          "status": "i",
+          "gid": "xMark",
+          "msg": "x marks the spot"
+        }
+      },
+      {
+        "id": "of:0000000000000002",
+        "badge": {
+          "status": "w",
+          "gid": "crown",
+          "msg": "it's good to be the King"
+        }
+      },
+      {
+        "id": "of:0000000000000003",
+        "badge": {
+          "status": "e",
+          "gid": "chain",
+          "msg": "the weakest link"
+        }
+      },
+      {
+        "id": "of:0000000000000004",
+        "badge": {
+          "status": "i",
+          "txt": "1",
+          "msg": "singular sensation"
+        }
+      },
+      {
+        "id": "of:0000000000000005",
+        "badge": {
+          "status": "w",
+          "txt": "42",
+          "msg": "life, the universe, and everything!"
+        }
+      },
+      {
+        "id": "of:0000000000000006",
+        "badge": {
+          "status": "e",
+          "txt": "99",
+          "msg": "cadbury's flake"
+        }
+      }
+    ],
+    "hosts": [],
+    "links": [
+      {
+        "css": "primary",
+        "id": "of:0000000000000001/5-of:0000000000000002/7",
+        "label": "Foo!"
+      }
+    ]
+  }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json
new file mode 100644 (file)
index 0000000..57f3251
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000000000000003",
+    "type": "switch",
+    "online": true,
+    "master": "ONOS",
+    "labels": [
+      "",
+      "switch-3",
+      "of:0000000000000003"
+    ],
+    "metaUi": {
+      "x": 600,
+      "y": 200
+    }
+  }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json
new file mode 100644 (file)
index 0000000..bab0048
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000000000000004",
+    "type": "switch",
+    "online": true,
+    "master": "ONOS",
+    "labels": [
+      "",
+      "switch-4",
+      "of:0000000000000004"
+    ],
+    "metaUi": {
+      "x": 200,
+      "y": 400
+    }
+  }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json
new file mode 100644 (file)
index 0000000..6ee1808
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000000000000005",
+    "type": "switch",
+    "online": true,
+    "master": "ONOS",
+    "labels": [
+      "",
+      "switch-5",
+      "of:0000000000000005"
+    ],
+    "metaUi": {
+      "x": 400,
+      "y": 420
+    }
+  }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json
deleted file mode 100644 (file)
index 74c42c5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "event": "showHighlights",
-  "payload": {
-    "devices": [
-      {
-        "id": "of:0000000000000001",
-        "badge": {
-          "status": "e",
-          "gid": "xMark",
-          "msg": "x marks the spot"
-        }
-      },
-      {
-        "id": "of:0000000000000002",
-        "badge": {
-          "status": "w",
-          "txt": "7"
-        }
-      }
-    ],
-    "hosts": [],
-    "links": [
-      {
-        "css": "primary",
-        "id": "of:0000000000000001/5-of:0000000000000002/7",
-        "label": "Antz!"
-      }
-    ]
-  }
-}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json
new file mode 100644 (file)
index 0000000..4554996
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000000000000006",
+    "type": "switch",
+    "online": true,
+    "master": "ONOS",
+    "labels": [
+      "",
+      "switch-6",
+      "of:0000000000000006"
+    ],
+    "metaUi": {
+      "x": 600,
+      "y": 400
+    }
+  }
+}
index 0ca4f4f..ae093d6 100644 (file)
@@ -4,7 +4,7 @@
   ],
   "title": "Demo adding badges",
   "params": {
-    "lastAuto": 5
+    "lastAuto": 9
   },
   "description": [
     "Demonstrate the device badging feature."